Skip to content

Commit

Permalink
Merge branch 'main' into feature/no-connection-serial
Browse files Browse the repository at this point in the history
  • Loading branch information
maratal authored May 16, 2023
2 parents ebc91c2 + 0a97ac3 commit c0433e7
Show file tree
Hide file tree
Showing 19 changed files with 129 additions and 35 deletions.
21 changes: 20 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Change Log

## Unreleased
## [1.2.20](https://github.com/ably/ably-cocoa/tree/1.2.20)

[Full Changelog](https://github.com/ably/ably-cocoa/compare/1.2.19...1.2.20)

**Public API changes:**

Expand All @@ -10,6 +12,23 @@

- The ably-cocoa library no longer calls any of the `ARTLog` methods in the `ARTLog (Shorthand)` category, nor the `-logWithError:` method. Be aware that if you have created a custom subclass of `ARTLog` which overrides any of these methods, they will no longer be called. `ARTLog` now performs all of its logging using only the `-log:withLevel:` method.

**Fixed bugs:**

- Fallback host is being discarded before `fallbackRetryTimeout` elapses [\#1683](https://github.com/ably/ably-cocoa/issues/1683)
- Compilation error in SocketRocket in Xcode 14.3 [\#1591](https://github.com/ably/ably-cocoa/issues/1591)
- Call to `_connect` in `ARTRealtimeInternal` constructor [\#1566](https://github.com/ably/ably-cocoa/issues/1566)
- SCNetworkReachabilitySetCallback \(Crashed: io.ably.main\) [\#1380](https://github.com/ably/ably-cocoa/issues/1380)
- Crash in ARTOSReachability [\#593](https://github.com/ably/ably-cocoa/issues/593)

**Closed issues:**

- Run tests in Ably-iOS and Ably-macOS using Xcode 14.3 [\#1653](https://github.com/ably/ably-cocoa/issues/1653)
- Emit file name and line number with every logged message [\#1643](https://github.com/ably/ably-cocoa/issues/1643)
- Thread running at QOS\_CLASS\_USER\_INTERACTIVE waiting on a lower QoS thread running at QOS\_CLASS\_DEFAULT. Investigate ways to avoid priority inversions [\#1569](https://github.com/ably/ably-cocoa/issues/1569)
- App Store publication issues when using Carthage [\#1559](https://github.com/ably/ably-cocoa/issues/1559)
- Remove extra callback with `setSuspended` [\#1550](https://github.com/ably/ably-cocoa/issues/1550)
- Make sure we can build the library and run the tests using Xcode 14 [\#1523](https://github.com/ably/ably-cocoa/issues/1523)

## [1.2.19](https://github.com/ably/ably-cocoa/tree/1.2.19)

[Full Changelog](https://github.com/ably/ably-cocoa/compare/1.2.18...1.2.19)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ You can install Ably for iOS and macOS through Package Manager, CocoaPods, Carth
- [This apple guide](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app) explains the steps in more detail.
- To install the `ably-cocoa` package in another **Swift Package**, then add the following to your `Package.Swift`:
```swift
.package(url: "https://github.com/ably/ably-cocoa", from: "1.2.19"),
.package(url: "https://github.com/ably/ably-cocoa", from: "1.2.20"),
```
### Installing through [CocoaPods](https://cocoapods.org/)

Expand Down Expand Up @@ -104,7 +104,7 @@ If you see, for example, a `dyld: Library not loaded: @rpath/AblyDeltaCodec.fram

### Manual installation

1. Get the code from GitHub [from the release page](https://github.com/ably/ably-cocoa/releases/tag/1.2.19), or clone it to get the latest, unstable and possibly underdocumented version: `git clone [email protected]:ably/ably-cocoa.git`
1. Get the code from GitHub [from the release page](https://github.com/ably/ably-cocoa/releases/tag/1.2.20), or clone it to get the latest, unstable and possibly underdocumented version: `git clone [email protected]:ably/ably-cocoa.git`
2. Drag the directory `ably-cocoa/ably-cocoa` into your project as a group.
3. Ably depends on our [MessagePack Fork](https://github.com/ably-forks/msgpack-objective-C) 0.2.0; get it [from the releases page](https://github.com/ably-forks/msgpack-objective-C/releases/tag/0.2.0-ably-1) and link it into your project.

Expand Down
2 changes: 1 addition & 1 deletion Scripts/jazzy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jazzy \
--objc \
--clean \
--author Ably \
--module-version 1.2.19 \
--module-version 1.2.20 \
--umbrella-header Source/include/Ably/Ably.h \
--framework-root Source \
--module Ably \
Expand Down
2 changes: 1 addition & 1 deletion Source/ARTClientInformation.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#import <sys/utsname.h>

NSString *const ARTClientInformationAgentNotVersioned = @"ARTClientInformationAgentNotVersioned";
NSString *const ARTClientInformation_libraryVersion = @"1.2.19";
NSString *const ARTClientInformation_libraryVersion = @"1.2.20";
static NSString *const _libraryName = @"ably-cocoa";

// NSOperatingSystemVersion has NSInteger as version components for some reason, so mitigate it here.
Expand Down
2 changes: 1 addition & 1 deletion Source/ARTTypes.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ NSTimeInterval millisecondsToTimeInterval(uint64_t msecs) {
return ((NSTimeInterval)msecs) / 1000;
}

NSString *generateNonce() {
NSString *generateNonce(void) {
// Generate two random numbers up to 8 digits long and concatenate them to produce a 16 digit random number
NSUInteger r1 = arc4random_uniform(100000000);
NSUInteger r2 = arc4random_uniform(100000000);
Expand Down
2 changes: 1 addition & 1 deletion Source/SocketRocket/ARTSRWebSocket.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
#error SocketRocket must be compiled with ARC enabled
#endif

__attribute__((used)) static void importCategories()
__attribute__((used)) static void importCategories(void)
{
import_NSURLRequest_ARTSRWebSocket();
import_NSRunLoop_ARTSRWebSocket();
Expand Down
2 changes: 1 addition & 1 deletion Source/SocketRocket/NSRunLoop+ARTSRWebSocket.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#import "ARTSRRunLoopThread.h"

// Required for object file to always be linked.
void import_NSRunLoop_ARTSRWebSocket() { }
void import_NSRunLoop_ARTSRWebSocket(void) { }

@implementation NSRunLoop (ARTSRWebSocket)

Expand Down
2 changes: 1 addition & 1 deletion Source/SocketRocket/NSURLRequest+ARTSRWebSocket.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#import "NSURLRequest+ARTSRWebSocketPrivate.h"

// Required for object file to always be linked.
void import_NSURLRequest_ARTSRWebSocket() { }
void import_NSURLRequest_ARTSRWebSocket(void) { }

NS_ASSUME_NONNULL_BEGIN

Expand Down
8 changes: 0 additions & 8 deletions Test/Test Utilities/NSObject+TestSuite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,4 @@ extension NSObject {
return try? self.aspect_hook(selector, with: AspectOptions(), usingBlock: unsafeBitCast(block, to: AnyObject.self))
}

/// Replace identified class method with a block of code.
class func testSuite_replaceClassMethod(_ selector: Selector, code: @escaping ()->()) -> AspectToken? {
let block: @convention(block) (AspectInfo) -> Void = { _ in
code()
}
return try? self.aspect_hook(selector, with: .positionInstead, usingBlock: unsafeBitCast(block, to: AnyObject.self))
}

}
33 changes: 31 additions & 2 deletions Test/Test Utilities/TestProxyTransportFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,43 @@ class TestProxyTransportFactory: RealtimeTransportFactory {
var networkConnectEvent: ((ARTRealtimeTransport, URL) -> Void)?

func transport(withRest rest: ARTRestInternal, options: ARTClientOptions, resumeKey: String?, logger: InternalLog) -> ARTRealtimeTransport {
let webSocketFactory = DefaultWebSocketFactory()
return TestProxyTransport(
let webSocketFactory = WebSocketFactory()

let testProxyTransport = TestProxyTransport(
factory: self,
rest: rest,
options: options,
resumeKey: resumeKey,
logger: logger,
webSocketFactory: webSocketFactory
)

webSocketFactory.testProxyTransport = testProxyTransport

return testProxyTransport
}

private class WebSocketFactory: Ably.WebSocketFactory {
weak var testProxyTransport: TestProxyTransport?

func createWebSocket(with request: URLRequest, logger: InternalLog?) -> ARTWebSocket {
let webSocket = WebSocket(urlRequest: request, logger: logger)
webSocket.testProxyTransport = testProxyTransport

return webSocket
}
}

private class WebSocket: ARTSRWebSocket {
weak var testProxyTransport: TestProxyTransport?

override func open() {
guard let testProxyTransport else {
preconditionFailure("Tried to fetch testProxyTransport but it's already been deallocated")
}
if !testProxyTransport.handleWebSocketOpen() {
super.open()
}
}
}
}
57 changes: 54 additions & 3 deletions Test/Test Utilities/TestUtilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,24 @@ class TestProxyTransport: ARTWebSocketTransport {
private var callbackBeforeIncomingMessageModifier: ((ARTProtocolMessage) -> ARTProtocolMessage?)?
private var callbackAfterIncomingMessageModifier: ((ARTProtocolMessage) -> ARTProtocolMessage?)?

// Represents a request to replace the implementation of a method.
private class Hook {
private var implementation: () -> Void

init(implementation: @escaping () -> Void) {
self.implementation = implementation
}

func performImplementation() -> Void {
implementation()
}
}

/// The active request, if any, to replace the implementation of the ARTWebSocket#open method for all WebSocket objects created by this transport. Access must be synchronised using webSocketOpenHookSemaphore.
private var webSocketOpenHook: Hook?
/// Used for synchronising access to webSocketOpenHook.
private let webSocketOpenHookSempahore = DispatchSemaphore(value: 1)

func setListenerBeforeProcessingIncomingMessage(_ callback: ((ARTProtocolMessage) -> Void)?) {
queue.sync {
self.callbackBeforeProcessingIncomingMessage = callback
Expand Down Expand Up @@ -1216,17 +1234,50 @@ class TestProxyTransport: ARTWebSocketTransport {
performNetworkConnectEvent()
}

private func addWebSocketOpenHook(withImplementation implementation: @escaping () -> Void) -> Hook {
webSocketOpenHookSempahore.wait()
let hook = Hook(implementation: implementation)
webSocketOpenHook = hook
webSocketOpenHookSempahore.signal()
return hook
}

private func removeWebSocketOpenHook(_ hook: Hook) {
webSocketOpenHookSempahore.wait()
if (webSocketOpenHook === hook) {
webSocketOpenHook = nil
}
webSocketOpenHookSempahore.signal()
}

/// If this transport has been configured with a replacement implementation of ARTWebSocket#open, then this performs that implementation and returns `true`. Else, returns `false`.
func handleWebSocketOpen() -> Bool {
let hook: Hook?
webSocketOpenHookSempahore.wait()
hook = webSocketOpenHook
webSocketOpenHookSempahore.signal()

if let hook {
hook.performImplementation()
return true
} else {
return false
}
}

private func setupFakeNetworkResponse(_ networkResponse: FakeNetworkResponse) {
var hook: AspectToken?
hook = ARTSRWebSocket.testSuite_replaceClassMethod(#selector(ARTSRWebSocket.open)) {
var hook: Hook?
hook = addWebSocketOpenHook {
if self.factory.fakeNetworkResponse == nil {
return
}

func performFakeConnectionError(_ secondsForDelay: TimeInterval, error: ARTRealtimeTransportError) {
self.queue.asyncAfter(deadline: .now() + secondsForDelay) {
self.delegate?.realtimeTransportFailed(self, withError: error)
hook?.remove()
if let hook {
self.removeWebSocketOpenHook(hook)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Test/Tests/ARTDefaultTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ class ARTDefaultTests: XCTestCase {

func testVersions() {
XCTAssertEqual(ARTDefault.apiVersion(), "2")
XCTAssertEqual(ARTDefault.libraryVersion(), "1.2.19")
XCTAssertEqual(ARTDefault.libraryVersion(), "1.2.20")
}
}
4 changes: 3 additions & 1 deletion Test/Tests/AuthTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,9 @@ class AuthTests: XCTestCase {
options.authCallback = { _, completion in
getTestTokenDetails(for: test, completion: completion)
}
options.testOptions.realtimeRequestTimeout = 0.5

// This needs to be sufficiently long such that we can expect to receive a CONNECTED ProtocolMessage within this duration after starting a connection attempt (there's no "correct" value since it depends on network conditions, but 1.5s seemed to work locally and in CI at time of writing). But we also don't want it to be longer than necessary since that would impact test execution time.
options.testOptions.realtimeRequestTimeout = 1.5

let realtime = ARTRealtime(options: options)
defer { realtime.dispose(); realtime.close() }
Expand Down
6 changes: 3 additions & 3 deletions Test/Tests/ClientInformationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ final class ClientInformationTests: XCTestCase {

XCTAssertEqual(agents.keys.count, 2)

XCTAssertEqual(agents["ably-cocoa"], "1.2.19")
XCTAssertEqual(agents["ably-cocoa"], "1.2.20")

#if os(iOS)
XCTAssertTrue(agents.keys.contains("iOS"))
Expand All @@ -27,7 +27,7 @@ final class ClientInformationTests: XCTestCase {
// CR3, CR3b
func testAgentIdentifierWithAdditionalAgents_withNilAdditionalAgents() {
let expectedIdentifier = [
"ably-cocoa/1.2.19",
"ably-cocoa/1.2.20",
ARTDefault.platformAgent()
].sorted().joined(separator: " ")

Expand All @@ -42,7 +42,7 @@ final class ClientInformationTests: XCTestCase {
]

let expectedIdentifier = [
"ably-cocoa/1.2.19",
"ably-cocoa/1.2.20",
"demolib/0.0.1",
"morelib",
ARTDefault.platformAgent()
Expand Down
2 changes: 1 addition & 1 deletion Test/Tests/RealtimeClientChannelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2781,7 +2781,7 @@ class RealtimeClientChannelTests: XCTestCase {
channelOne.publish("i", data: ["expectedBundle": 5], clientId: "bar")
channelOne.publish("j", data: ["expectedBundle": 6])
// RTL6d1
channelOne.publish("k", data: ["expectedBundle": 7, "moreData": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"])
channelOne.publish("k", data: ["expectedBundle": 7, "moreData": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"] as [String : Any])
channelOne.publish("l", data: ["expectedBundle": 8])
// RTL6d7
channelOne.publish([ARTMessage(id: "bundle_m", name: "m", data: ["expectedBundle": 9])])
Expand Down
7 changes: 4 additions & 3 deletions Test/Tests/RealtimeClientConnectionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ class RealtimeClientConnectionTests: XCTestCase {
done()
case .connected:
if let transport = client.internal.transport as? TestProxyTransport, let query = transport.lastUrl?.query {
expect(query).to(haveParam("agent", hasPrefix: "ably-cocoa/1.2.19"))
expect(query).to(haveParam("agent", hasPrefix: "ably-cocoa/1.2.20"))
} else {
XCTFail("MockTransport isn't working")
}
Expand Down Expand Up @@ -4407,7 +4407,8 @@ class RealtimeClientConnectionTests: XCTestCase {
func test__011__Connection__should_disconnect_the_transport_when_no_activity_exist() throws {
let test = Test()
let options = try AblyTests.commonAppSetup(for: test)
let realtimeRequestTimeout = 0.5
// This needs to be sufficiently long such that we can expect to receive a CONNECTED ProtocolMessage within this duration after starting a connection attempt (there's no "correct" value since it depends on network conditions, but 1.5s seemed to work locally and in CI at time of writing). But we also don't want it to be longer than necessary since that would impact test execution time.
let realtimeRequestTimeout = 1.5
options.testOptions.realtimeRequestTimeout = realtimeRequestTimeout
let client = AblyTests.newRealtime(options).client
defer { client.dispose(); client.close() }
Expand Down Expand Up @@ -4462,7 +4463,7 @@ class RealtimeClientConnectionTests: XCTestCase {
}
}

XCTAssertEqual(expectedInactivityTimeout, 3.5)
XCTAssertEqual(expectedInactivityTimeout, 4.5)
XCTAssertEqual(client.internal.maxIdleInterval, 3.0)
}

Expand Down
2 changes: 1 addition & 1 deletion Test/Tests/RestClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1734,7 +1734,7 @@ class RestClientTests: XCTestCase {
let headerAgent = testHTTPExecutor.requests.first!.allHTTPHeaderFields?["Ably-Agent"]
let ablyAgent = ARTClientInformation.agentIdentifier(withAdditionalAgents: options.agents)
XCTAssertEqual(headerAgent, ablyAgent)
XCTAssertTrue(headerAgent!.hasPrefix("ably-cocoa/1.2.19"))
XCTAssertTrue(headerAgent!.hasPrefix("ably-cocoa/1.2.20"))
done()
}
}
Expand Down
4 changes: 2 additions & 2 deletions Test/Tests/UtilitiesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ class UtilitiesTests: XCTestCase {
func test__001__Utilities__JSON_Encoder__should_decode_a_protocol_message_that_has_an_error_without_a_message() throws {
beforeEach__Utilities__JSON_Encoder()

let jsonObject: NSDictionary = [
let jsonObject: [String : Any] = [
"action": 9,
"error": [
"code": 40142,
"statusCode": "401",
],
] as [String : Any],
]
let data = try JSONSerialization.data(withJSONObject: jsonObject, options: [])
guard let protocolMessage = try? jsonEncoder.decodeProtocolMessage(data) else {
Expand Down
2 changes: 1 addition & 1 deletion Version.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
CURRENT_PROJECT_VERSION = 1.2.19
CURRENT_PROJECT_VERSION = 1.2.20

0 comments on commit c0433e7

Please sign in to comment.