Skip to content

Commit

Permalink
Merge pull request #1847 from ably/fix/1177-RSH8b-RSH3g2a
Browse files Browse the repository at this point in the history
Proper RSH8b and RSH3g2a behavior.
maratal authored Jan 18, 2024

Verified

This commit was signed with the committer’s verified signature.
Rigidity Rigidity
2 parents eda7a54 + f5b7359 commit 4ff1202
Showing 10 changed files with 231 additions and 47 deletions.
3 changes: 3 additions & 0 deletions Source/ARTAuth.m
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@
#import "ARTPushActivationState.h"
#import "ARTFormEncode.h"
#import "ARTInternalLog.h"
#import "ARTLocalDeviceStorage.h"
#import "ARTLocalDevice+Private.h"

@implementation ARTAuth {
ARTQueuedDealloc *_dealloc;
@@ -824,6 +826,7 @@ - (void)setLocalDeviceClientId_nosync:(NSString *)clientId {
return;
}
[_rest.device_nosync setClientId:clientId];
[_rest.storage setObject:clientId forKey:ARTClientIdKey];
[_rest.push getActivationMachine:^(ARTPushActivationStateMachine *stateMachine) {
if (![stateMachine.current_nosync isKindOfClass:[ARTPushActivationStateNotActivated class]]) {
[stateMachine sendEvent:[[ARTPushActivationEventGotPushDeviceDetails alloc] init]];
72 changes: 54 additions & 18 deletions Source/ARTLocalDevice.m
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@
NSString *const ARTDeviceSecretKey = @"ARTDeviceSecret";
NSString *const ARTDeviceIdentityTokenKey = @"ARTDeviceIdentityToken";
NSString *const ARTAPNSDeviceTokenKey = @"ARTAPNSDeviceToken";
NSString *const ARTClientIdKey = @"ARTClientId";

NSString *const ARTAPNSDeviceDefaultTokenType = @"default";
NSString *const ARTAPNSDeviceLocationTokenType = @"location";
@@ -46,17 +47,24 @@ @interface ARTLocalDevice ()

@implementation ARTLocalDevice

- (instancetype)initWithClientId:(NSString *)clientId storage:(id<ARTDeviceStorage>)storage logger:(nullable ARTInternalLog *)logger {
- (instancetype)initWithStorage:(id<ARTDeviceStorage>)storage logger:(nullable ARTInternalLog *)logger {
if (self = [super init]) {
self.clientId = clientId;
self.storage = storage;
_logger = logger;
}
return self;
}

+ (ARTLocalDevice *)load:(NSString *)clientId storage:(id<ARTDeviceStorage>)storage logger:(nullable ARTInternalLog *)logger {
ARTLocalDevice *device = [[ARTLocalDevice alloc] initWithClientId:clientId storage:storage logger:logger];
- (void)generateAndPersistPairOfDeviceIdAndSecret {
self.id = [self.class generateId];
self.secret = [self.class generateSecret];

[_storage setObject:self.id forKey:ARTDeviceIdKey];
[_storage setSecret:self.secret forDevice:self.id];
}

+ (instancetype)deviceWithStorage:(id<ARTDeviceStorage>)storage logger:(nullable ARTInternalLog *)logger {
ARTLocalDevice *device = [[ARTLocalDevice alloc] initWithStorage:storage logger:logger];
device.platform = ARTDevicePlatform;
#if TARGET_OS_IOS
switch ([[UIDevice currentDevice] userInterfaceIdiom]) {
@@ -75,21 +83,25 @@ + (ARTLocalDevice *)load:(NSString *)clientId storage:(id<ARTDeviceStorage>)stor
NSString *deviceId = [storage objectForKey:ARTDeviceIdKey];
NSString *deviceSecret = deviceId == nil ? nil : [storage secretForDevice:deviceId];

if (deviceId == nil || deviceSecret == nil) { // generate both at the same time
deviceId = [self generateId];
deviceSecret = [self generateSecret];
[storage setObject:deviceId forKey:ARTDeviceIdKey];
[storage setSecret:deviceSecret forDevice:deviceId];
if (deviceId == nil || deviceSecret == nil) {
[device generateAndPersistPairOfDeviceIdAndSecret]; // Should be removed later once spec issue #180 resolved.
}
else {
device.id = deviceId;
device.secret = deviceSecret;
}

device.id = deviceId;
device.secret = deviceSecret;

id identityTokenDetailsInfo = [storage objectForKey:ARTDeviceIdentityTokenKey];
ARTDeviceIdentityTokenDetails *identityTokenDetails = [ARTDeviceIdentityTokenDetails unarchive:identityTokenDetailsInfo withLogger:logger];
device->_identityTokenDetails = identityTokenDetails;

NSString *clientId = [storage objectForKey:ARTClientIdKey];
if (clientId == nil && identityTokenDetails.clientId != nil) {
clientId = identityTokenDetails.clientId; // Older versions of the SDK did not persist clientId, so as a fallback when loading data persisted by these versions we use the clientId of the stored identity token
[storage setObject:clientId forKey:ARTClientIdKey];
}
device.clientId = clientId;

NSArray *supportedTokenTypes = @[
ARTAPNSDeviceDefaultTokenType,
ARTAPNSDeviceLocationTokenType
@@ -102,6 +114,34 @@ + (ARTLocalDevice *)load:(NSString *)clientId storage:(id<ARTDeviceStorage>)stor
return device;
}

- (void)setupDetailsWithClientId:(NSString *)clientId {
NSString *deviceId = self.id;
NSString *deviceSecret = self.secret;

if (deviceId == nil || deviceSecret == nil) {
[self generateAndPersistPairOfDeviceIdAndSecret];
}

self.clientId = clientId;
[_storage setObject:clientId forKey:ARTClientIdKey];
}

- (void)resetDetails {
// Should be replaced later to resetting device's id/secret once spec issue #180 resolved.
[self generateAndPersistPairOfDeviceIdAndSecret];

self.clientId = nil;
[_storage setObject:nil forKey:ARTClientIdKey];
[self setAndPersistIdentityTokenDetails:nil];
NSArray *supportedTokenTypes = @[
ARTAPNSDeviceDefaultTokenType,
ARTAPNSDeviceLocationTokenType
];
for (NSString *tokenType in supportedTokenTypes) {
[self setAndPersistAPNSDeviceToken:nil tokenType:tokenType];
}
}

+ (NSString *)generateId {
return [NSUUID new].UUIDString;
}
@@ -146,16 +186,12 @@ - (void)setAndPersistIdentityTokenDetails:(ARTDeviceIdentityTokenDetails *)token
_identityTokenDetails = tokenDetails;
if (self.clientId == nil) {
self.clientId = tokenDetails.clientId;
[self.storage setObject:tokenDetails.clientId forKey:ARTClientIdKey];
}
}

- (BOOL)isRegistered {
return _identityTokenDetails != nil;
}

- (void)clearIdentityTokenDetailsAndClientId {
[self setAndPersistIdentityTokenDetails:nil];
self.clientId = nil;
}

@end
6 changes: 3 additions & 3 deletions Source/ARTPushActivationState.m
Original file line number Diff line number Diff line change
@@ -102,6 +102,8 @@ @implementation ARTPushActivationPersistentState
} else if ([local apnsDeviceToken]) {
[machine sendEvent:[ARTPushActivationEventGotPushDeviceDetails new]];
}
[machine.rest setupLocalDevice_nosync];
[machine registerForAPNS];
#endif

return [ARTPushActivationStateWaitingForPushDeviceDetails newWithMachine:machine logger:logger];
@@ -116,7 +118,6 @@ - (ARTPushActivationState *)transition:(ARTPushActivationEvent *)event {
return self;
}
else if ([event isKindOfClass:[ARTPushActivationEventCalledActivate class]]) {
[self.machine registerForAPNS];
return validateAndSync(self.machine, event, self.logger);
}
return nil;
@@ -274,8 +275,7 @@ - (ARTPushActivationState *)transition:(ARTPushActivationEvent *)event {
}
else if ([event isKindOfClass:[ARTPushActivationEventDeregistered class]]) {
#if TARGET_OS_IOS
ARTLocalDevice *local = self.machine.rest.device_nosync;
[local clearIdentityTokenDetailsAndClientId];
[self.machine.rest resetLocalDevice_nosync];
#endif
[self.machine callDeactivatedCallback:nil];
return [ARTPushActivationStateNotActivated newWithMachine:self.machine logger:self.logger];
24 changes: 19 additions & 5 deletions Source/ARTRest.m
Original file line number Diff line number Diff line change
@@ -744,10 +744,9 @@ - (ARTLocalDevice *)device {
}

- (ARTLocalDevice *)device_nosync {
NSString *clientId = self.auth.clientId_nosync;
__block ARTLocalDevice *ret;
dispatch_sync(ARTRestInternal.deviceAccessQueue, ^{
ret = [self deviceWithClientId_onlyCallOnDeviceAccessQueue:clientId];
dispatch_sync([ARTRestInternal deviceAccessQueue], ^{
ret = [self sharedDevice_onlyCallOnDeviceAccessQueue];
});
return ret;
}
@@ -765,7 +764,7 @@ + (dispatch_queue_t)deviceAccessQueue {

static BOOL sharedDeviceNeedsLoading_onlyAccessOnDeviceAccessQueue = YES;

- (ARTLocalDevice *)deviceWithClientId_onlyCallOnDeviceAccessQueue:(NSString *)clientId {
- (ARTLocalDevice *)sharedDevice_onlyCallOnDeviceAccessQueue {
// The device is shared in a static variable because it's a reflection
// of what's persisted. Having a device instance per ARTRest instance
// could leave some instances in a stale state, if, through another
@@ -776,12 +775,27 @@ - (ARTLocalDevice *)deviceWithClientId_onlyCallOnDeviceAccessQueue:(NSString *)c

static id device;
if (sharedDeviceNeedsLoading_onlyAccessOnDeviceAccessQueue) {
device = [ARTLocalDevice load:clientId storage:self.storage logger:self.logger];
device = [ARTLocalDevice deviceWithStorage:self.storage logger:self.logger];
sharedDeviceNeedsLoading_onlyAccessOnDeviceAccessQueue = NO;
}
return device;
}

- (void)setupLocalDevice_nosync {
ARTLocalDevice *device = [self device_nosync];
NSString *clientId = self.auth.clientId_nosync;
dispatch_sync([ARTRestInternal deviceAccessQueue], ^{
[device setupDetailsWithClientId:clientId];
});
}

- (void)resetLocalDevice_nosync {
ARTLocalDevice *device = [self device_nosync];
dispatch_sync([ARTRestInternal deviceAccessQueue], ^{
[device resetDetails];
});
}

- (void)resetDeviceSingleton {
dispatch_sync([ARTRestInternal deviceAccessQueue], ^{
sharedDeviceNeedsLoading_onlyAccessOnDeviceAccessQueue = YES;
8 changes: 5 additions & 3 deletions Source/PrivateHeaders/Ably/ARTLocalDevice+Private.h
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ extern NSString *const ARTDeviceIdKey;
extern NSString *const ARTDeviceSecretKey;
extern NSString *const ARTDeviceIdentityTokenKey;
extern NSString *const ARTAPNSDeviceTokenKey;
extern NSString *const ARTClientIdKey;

extern NSString *const ARTAPNSDeviceDefaultTokenType;
extern NSString *const ARTAPNSDeviceLocationTokenType;
@@ -19,18 +20,19 @@ NSString* ARTAPNSDeviceTokenKeyOfType(NSString * _Nullable tokenType);

@property (nonatomic) id<ARTDeviceStorage> storage;

+ (ARTLocalDevice *)load:(NSString *)clientId storage:(id<ARTDeviceStorage>)storage logger:(nullable ARTInternalLog *)logger;
+ (instancetype)deviceWithStorage:(id<ARTDeviceStorage>)storage logger:(nullable ARTInternalLog *)logger;
- (nullable NSString *)apnsDeviceToken;
- (void)setAndPersistAPNSDeviceToken:(nullable NSString *)deviceToken tokenType:(NSString *)tokenType;
- (void)setAndPersistAPNSDeviceToken:(nullable NSString *)deviceToken;
- (void)setAndPersistIdentityTokenDetails:(nullable ARTDeviceIdentityTokenDetails *)tokenDetails;
- (BOOL)isRegistered;
- (void)clearIdentityTokenDetailsAndClientId;
- (void)resetDetails;
- (void)setupDetailsWithClientId:(nullable NSString *)clientId;

+ (NSString *)generateId;
+ (NSString *)generateSecret;

+ (NSString *)apnsDeviceTokenOfType:(nullable NSString *)tokenType fromStorage:(id<ARTDeviceStorage>)storage;
+ (nullable NSString *)apnsDeviceTokenOfType:(nullable NSString *)tokenType fromStorage:(id<ARTDeviceStorage>)storage;

@end

3 changes: 3 additions & 0 deletions Source/PrivateHeaders/Ably/ARTRest+Private.h
Original file line number Diff line number Diff line change
@@ -76,6 +76,9 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable NSObject<ARTCancellable> *)internetIsUp:(void (^)(BOOL isUp))cb;

#if TARGET_OS_IOS
- (void)setupLocalDevice_nosync;
- (void)resetLocalDevice_nosync;

// This is only intended to be called from test code.
- (void)resetDeviceSingleton;

134 changes: 119 additions & 15 deletions Test/Tests/PushActivationStateMachineTests.swift
Original file line number Diff line number Diff line change
@@ -118,14 +118,27 @@ class PushActivationStateMachineTests: XCTestCase {

func test__014__Activation_state_machine__State_NotActivated__on_Event_CalledActivate__local_device__should_have_a_generated_id() {
beforeEach__Activation_state_machine__State_NotActivated()

rest.internal.resetDeviceSingleton()

let options = ARTClientOptions(key: "xxxx:xxxx")
let rest = ARTRest(options: options)
rest.internal.storage = storage
let stateMachine = ARTPushActivationStateMachine(rest: rest.internal, delegate: StateMachineDelegate(), logger: .init(core: MockInternalLogCore()))

stateMachine.send(ARTPushActivationEventCalledActivate())

XCTAssertEqual(rest.device.id.count, 36)
}

func test__015__Activation_state_machine__State_NotActivated__on_Event_CalledActivate__local_device__should_have_a_generated_secret() throws {
beforeEach__Activation_state_machine__State_NotActivated()


let options = ARTClientOptions(key: "xxxx:xxxx")
let rest = ARTRest(options: options)
rest.internal.storage = storage
let stateMachine = ARTPushActivationStateMachine(rest: rest.internal, delegate: StateMachineDelegate(), logger: .init(core: MockInternalLogCore()))

stateMachine.send(ARTPushActivationEventCalledActivate())

let secret = try XCTUnwrap(rest.device.secret, "Device Secret should be available in storage")
let data = try XCTUnwrap(Data(base64Encoded: secret), "Device Secret should be encoded with Base64")

@@ -140,6 +153,15 @@ class PushActivationStateMachineTests: XCTestCase {
options.clientId = "deviceClient"
let rest = ARTRest(options: options)
rest.internal.storage = storage

let stateMachine = ARTPushActivationStateMachine(rest: rest.internal, delegate: StateMachineDelegate(), logger: .init(core: MockInternalLogCore()))

XCTAssertNil(rest.device.clientId)

stateMachine.send(ARTPushActivationEventCalledActivate())

XCTAssertNotNil(rest.device.id)
XCTAssertNotNil(rest.device.secret)
XCTAssertEqual(rest.device.clientId, "deviceClient")
}

@@ -459,6 +481,7 @@ class PushActivationStateMachineTests: XCTestCase {
storage = MockDeviceStorage(startWith: ARTPushActivationStateWaitingForDeviceRegistration(machine: initialStateMachine, logger: .init(core: MockInternalLogCore())))
rest.internal.storage = storage
stateMachine = ARTPushActivationStateMachine(rest: rest.internal, delegate: StateMachineDelegate(), logger: .init(core: MockInternalLogCore()))
rest.internal.setupLocalDevice_nosync()
}

// RSH3c1
@@ -529,6 +552,7 @@ class PushActivationStateMachineTests: XCTestCase {
storage = MockDeviceStorage(startWith: ARTPushActivationStateWaitingForNewPushDeviceDetails(machine: initialStateMachine, logger: .init(core: MockInternalLogCore())))
rest.internal.storage = storage
stateMachine = ARTPushActivationStateMachine(rest: rest.internal, delegate: StateMachineDelegate(), logger: .init(core: MockInternalLogCore()))
rest.internal.setupLocalDevice_nosync()
}

// RSH3d1
@@ -830,6 +854,8 @@ class PushActivationStateMachineTests: XCTestCase {
rest.internal.storage = storage
stateMachine = ARTPushActivationStateMachine(rest: rest.internal, delegate: StateMachineDelegate(), logger: .init(core: MockInternalLogCore()))

rest.internal.setupLocalDevice_nosync()

XCTAssertEqual(stateMachine.rest.device.clientId, "client1")

var deactivatedCallbackCalled = false
@@ -838,19 +864,31 @@ class PushActivationStateMachineTests: XCTestCase {
}
defer { hook.remove() }

var clearIdentityTokenDetailsAndClientIdCalled = false
let hookDevice = stateMachine.rest.device.testSuite_injectIntoMethod(after: NSSelectorFromString("clearIdentityTokenDetailsAndClientId")) {
clearIdentityTokenDetailsAndClientIdCalled = true
var resetDetailsCalled = false
let hookDevice = stateMachine.rest.device.testSuite_injectIntoMethod(after: NSSelectorFromString("resetDetails")) {
resetDetailsCalled = true
}
defer { hookDevice.remove() }

stateMachine.send(ARTPushActivationEventDeregistered())
expect(stateMachine.current).to(beAKindOf(ARTPushActivationStateNotActivated.self))
XCTAssertTrue(deactivatedCallbackCalled)
XCTAssertTrue(clearIdentityTokenDetailsAndClientIdCalled)
XCTAssertTrue(resetDetailsCalled)

// RSH3g2a
XCTAssertNil(stateMachine.rest.device.identityTokenDetails)
XCTAssertNil(stateMachine.rest.device.clientId)
XCTAssertNil(stateMachine.rest.device.push.recipient["push"])

XCTAssertNil(storage.object(forKey: ARTDeviceIdentityTokenKey))
XCTAssertNil(ARTLocalDevice.apnsDeviceToken(ofType: ARTAPNSDeviceDefaultTokenType, from: storage))
XCTAssertNil(ARTLocalDevice.apnsDeviceToken(ofType: ARTAPNSDeviceLocationTokenType, from: storage))

// Should be replaced with `nil` checks after issue https://github.com/ably/specification/issues/180 resolved
XCTAssertNotNil(stateMachine.rest.device.id)
XCTAssertNotNil(stateMachine.rest.device.secret)
XCTAssertEqual(storage.keysWritten[ARTDeviceIdKey] as? String, stateMachine.rest.device.id)
XCTAssertEqual(storage.keysWritten[ARTDeviceSecretKey] as? String, stateMachine.rest.device.secret)
}

// RSH3g3
@@ -873,7 +911,60 @@ class PushActivationStateMachineTests: XCTestCase {
expect(stateMachine.current).to(beAKindOf(ARTPushActivationStateWaitingForDeregistration.self))
XCTAssertTrue(deactivatedCallbackCalled)
}

// RSH8b, RSH3a2b, RSH3g2a
func test__056__Activation_state_machine__should_be_possible_to_activate_and_deactivate_and_then_activate_again_with_different_clientId() {
beforeEach__Activation_state_machine__State_NotActivated()

let options1 = ARTClientOptions(key: "xxxx:xxxx")
options1.clientId = "client1"
let rest1 = ARTRest(options: options1)
httpExecutor = MockHTTPExecutor()
rest1.internal.httpExecutor = httpExecutor
rest1.internal.storage = storage

let stateMachineDelegate = StateMachineDelegate()
let stateMachine1 = ARTPushActivationStateMachine(rest: rest1.internal, delegate: stateMachineDelegate, logger: .init(core: MockInternalLogCore()))

let testDeviceToken = "xxxx-xxxx-xxxx-xxxx-xxxx"
stateMachine1.rest.device.setAndPersistAPNSDeviceToken(testDeviceToken)
defer { stateMachine1.rest.device.setAndPersistAPNSDeviceToken(nil) }

waitUntil(timeout: testTimeout) { done in
let partialDone = AblyTests.splitDone(3, done: done)
stateMachine1.transitions = { event, _, _ in
if event is ARTPushActivationEventCalledActivate {
XCTAssertEqual(rest1.internal.device_nosync.clientId, "client1")
partialDone()
}
if event is ARTPushActivationEventGotPushDeviceDetails {
partialDone()
stateMachine1.send(ARTPushActivationEventCalledDeactivate())
}
if event is ARTPushActivationEventCalledDeactivate {
partialDone()
}
}
stateMachine1.send(ARTPushActivationEventCalledActivate())
}

XCTAssertNil(rest1.device.clientId) // after deactivation, RSH3g2a

let options2 = ARTClientOptions(key: "xxxx:xxxx")
options2.clientId = "client2"
let rest2 = ARTRest(options: options2)
rest2.internal.storage = storage
rest2.internal.httpExecutor = httpExecutor

XCTAssertNil(rest2.device.clientId)

let stateMachine2 = ARTPushActivationStateMachine(rest: rest2.internal, delegate: stateMachineDelegate, logger: .init(core: MockInternalLogCore()))
stateMachine2.send(ARTPushActivationEventCalledActivate())

XCTAssertEqual(rest2.device.clientId, "client2")
XCTAssertTrue(rest1.device === rest2.device)
}

// RSH4
func test__005__Activation_state_machine__should_queue_event_that_has_no_transition_defined_for_it() throws {
// Start with WaitingForDeregistration state
@@ -951,6 +1042,8 @@ class PushActivationStateMachineTests: XCTestCase {
options.clientId = "deviceClient"
let rest = ARTRest(options: options)
rest.internal.storage = storage
rest.internal.setupLocalDevice_nosync()

XCTAssertEqual(rest.device.clientId, "deviceClient")

let newOptions = ARTClientOptions(key: "xxxx:xxxx")
@@ -1156,10 +1249,15 @@ class PushActivationStateMachineTests: XCTestCase {
// RSH3d2b, RSH3d2c, RSH3d2d
func test__should_fire_Deregistered_event_and_include_DeviceSecret_HTTP_header() throws {
contextBeforeEach?()


rest.internal.setupLocalDevice_nosync()

let delegate = StateMachineDelegate()
stateMachine.delegate = delegate


let deviceId = rest.device.id
let deviceSecret = rest.device.secret

waitUntil(timeout: testTimeout) { done in
let partialDone = AblyTests.splitDone(2, done: done)
stateMachine.transitions = { event, _, currentState in
@@ -1177,7 +1275,7 @@ class PushActivationStateMachineTests: XCTestCase {

expect(stateMachine.current).to(beAKindOf(ARTPushActivationStateNotActivated.self))
XCTAssertEqual(httpExecutor.requests.count, 1)
let requests = httpExecutor.requests.compactMap { $0.url?.path }.filter { $0 == "/push/deviceRegistrations/\(rest.device.id)" }
let requests = httpExecutor.requests.compactMap { $0.url?.path }.filter { $0 == "/push/deviceRegistrations/\(deviceId)" }
XCTAssertEqual(requests.count, 1)

let request = try XCTUnwrap(httpExecutor.requests.first, "Should have a \"/push/deviceRegistrations\" request")
@@ -1187,15 +1285,17 @@ class PushActivationStateMachineTests: XCTestCase {
XCTAssertEqual(request.httpMethod, "DELETE")
XCTAssertNotNil(request.allHTTPHeaderFields?["Authorization"])
let deviceAuthorization = request.allHTTPHeaderFields?["X-Ably-DeviceSecret"]
XCTAssertEqual(deviceAuthorization, rest.device.secret)
XCTAssertEqual(deviceAuthorization, deviceSecret)

contextAfterEach?()
}

// RSH3d2b, RSH3d2c, RSH3d2d
func test__should_fire_Deregistered_event_and_include_DeviceIdentityToken_HTTP_header() throws {
contextBeforeEach?()


rest.internal.setupLocalDevice_nosync()

let delegate = StateMachineDelegate()
stateMachine.delegate = delegate

@@ -1211,7 +1311,9 @@ class PushActivationStateMachineTests: XCTestCase {
rest.device.setAndPersistIdentityTokenDetails(testIdentityTokenDetails)
defer { rest.device.setAndPersistIdentityTokenDetails(nil) }
XCTAssertNotNil(rest.device.identityTokenDetails)


let deviceId = rest.device.id

waitUntil(timeout: testTimeout) { done in
let partialDone = AblyTests.splitDone(2, done: done)
stateMachine.transitions = { event, _, currentState in
@@ -1229,7 +1331,7 @@ class PushActivationStateMachineTests: XCTestCase {

expect(stateMachine.current).to(beAKindOf(ARTPushActivationStateNotActivated.self))
XCTAssertEqual(httpExecutor.requests.count, 1)
let requests = httpExecutor.requests.compactMap { $0.url?.path }.filter { $0 == "/push/deviceRegistrations/\(rest.device.id)" }
let requests = httpExecutor.requests.compactMap { $0.url?.path }.filter { $0 == "/push/deviceRegistrations/\(deviceId)" }
XCTAssertEqual(requests.count, 1)

let request = try XCTUnwrap(httpExecutor.requests.first, "Should have a \"/push/deviceRegistrations\" request")
@@ -1248,7 +1350,9 @@ class PushActivationStateMachineTests: XCTestCase {
// RSH3d2c
func test__should_fire_DeregistrationFailed_event() throws {
contextBeforeEach?()


rest.internal.setupLocalDevice_nosync()

let delegate = StateMachineDelegate()
stateMachine.delegate = delegate

1 change: 1 addition & 0 deletions Test/Tests/PushAdminTests.swift
Original file line number Diff line number Diff line change
@@ -188,6 +188,7 @@ class PushAdminTests: XCTestCase {
rest.internal.httpExecutor = mockHttpExecutor
storage = MockDeviceStorage()
rest.internal.storage = storage
rest.internal.setupLocalDevice_nosync()
localDevice = rest.device
}

1 change: 1 addition & 0 deletions Test/Tests/PushChannelTests.swift
Original file line number Diff line number Diff line change
@@ -341,6 +341,7 @@ class PushChannelTests: XCTestCase {
options.testOptions.channelNamePrefix = nil
let rest = ARTRest(options: options)
rest.internal.storage = MockDeviceStorage()
rest.internal.setupLocalDevice_nosync()

// Activate device
let testIdentityTokenDetails = ARTDeviceIdentityTokenDetails(token: "xxxx-xxxx-xxx", issued: Date(), expires: Date.distantFuture, capability: "", clientId: "")
26 changes: 23 additions & 3 deletions Test/Tests/PushTests.swift
Original file line number Diff line number Diff line change
@@ -229,16 +229,22 @@ class PushTests: XCTestCase {
issued: Date(),
expires: Date.distantFuture,
capability: "",
clientId: ""
clientId: "client1"
)

let rest = ARTRest(key: "fake:key")
rest.internal.storage = storage

storage.simulateOnNextRead(string: "testId", for: ARTDeviceIdKey)
storage.simulateOnNextRead(string: "testSecret", for: ARTDeviceSecretKey)
storage.simulateOnNextRead(string: testToken, for: ARTAPNSDeviceTokenKey)
storage.simulateOnNextRead(data: testIdentity.archive(withLogger: nil), for: ARTDeviceIdentityTokenKey)

let device = rest.device

XCTAssertEqual(device.id, "testId")
XCTAssertEqual(device.secret, "testSecret")
XCTAssertEqual(device.clientId, "client1")
XCTAssertEqual(device.apnsDeviceToken(), testToken)
XCTAssertEqual(device.identityTokenDetails?.token, testIdentity.token)
}
@@ -255,7 +261,11 @@ class PushTests: XCTestCase {
}

let realtime = ARTRealtime(options: options)
let storage = MockDeviceStorage()
realtime.internal.rest.storage = storage

XCTAssertNil(realtime.device.clientId)
XCTAssertNil(storage.keysWritten[ARTClientIdKey] as? String)

waitUntil(timeout: testTimeout) { done in
realtime.auth.authorize { _, _ in
@@ -264,6 +274,7 @@ class PushTests: XCTestCase {
}

XCTAssertEqual(realtime.device.clientId, "testClient")
XCTAssertEqual(storage.keysWritten[ARTClientIdKey] as? String, "testClient")
}

// RSH8d
@@ -274,8 +285,12 @@ class PushTests: XCTestCase {
options.testOptions.transportFactory = TestProxyTransportFactory()

let realtime = ARTRealtime(options: options)
XCTAssertNil(realtime.device.clientId)
let storage = MockDeviceStorage()
realtime.internal.rest.storage = storage

XCTAssertNil(realtime.device.clientId)
XCTAssertNil(storage.keysWritten[ARTClientIdKey] as? String)

waitUntil(timeout: testTimeout) { done in
realtime.connection.once(.connected) { _ in
done()
@@ -288,6 +303,7 @@ class PushTests: XCTestCase {
}

XCTAssertEqual(realtime.device.clientId, "testClient")
XCTAssertEqual(storage.keysWritten[ARTClientIdKey] as? String, "testClient")
}

// RSH8e
@@ -336,7 +352,7 @@ class PushTests: XCTestCase {
storage.simulateOnNextRead(string: testDeviceToken, for: ARTAPNSDeviceTokenKey)
storage.simulateOnNextRead(data: testDeviceIdentity.archive(withLogger: nil), for: ARTDeviceIdentityTokenKey)

XCTAssertNil(realtime.device.clientId)
XCTAssertEqual(realtime.device.clientId, testDeviceIdentity.clientId)

waitUntil(timeout: testTimeout) { done in
stateMachine.transitions = { event, _, _ in
@@ -377,9 +393,12 @@ class PushTests: XCTestCase {
clientId: expectedClientId
)
}
let storage = MockDeviceStorage()
rest.internal.storage = storage
rest.push.internal.activationMachine.delegate = stateMachineDelegate

XCTAssertNil(rest.device.clientId)
XCTAssertNil(storage.keysWritten[ARTClientIdKey] as? String)

waitUntil(timeout: testTimeout) { done in
stateMachineDelegate.onDidActivateAblyPush = { _ in
@@ -392,6 +411,7 @@ class PushTests: XCTestCase {
}

XCTAssertEqual(rest.device.clientId, expectedClientId)
XCTAssertEqual(storage.keysWritten[ARTClientIdKey] as? String, expectedClientId)
}

func test__014__Registerer_Delegate_option__a_successful_activation_should_call_the_correct_registerer_delegate_method() throws {

0 comments on commit 4ff1202

Please sign in to comment.