Skip to content

Commit

Permalink
Push Admin tests (#642)
Browse files Browse the repository at this point in the history
* MockHTTPExecutor

* PushAdmin

* Move `publish` method to Admin

* Add `get` method in PushDeviceRegistrations

* Should use response encoder type

* Fix save channel subscription

* Fix save device registration

* Better errors information

* Rename publish notification argument to data to conform specs

* Add equatable to DeviceDetails

* Fix DeviceRegistrations.get

* Add validations to PushAdmin.publish

* Fix RHS1a

* Fix RHS1b1

* Fix PushAdmin implementation

* Fix ambiguous reference to member 'dataTask(with:completionHandler:)'

* fixup! Fix PushAdmin implementation

* CI test

* fixup! Fix PushAdmin implementation
  • Loading branch information
ricardopereira authored Dec 13, 2017
1 parent ce05f08 commit fea3162
Show file tree
Hide file tree
Showing 27 changed files with 1,207 additions and 102 deletions.
4 changes: 4 additions & 0 deletions Ably.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
D746AE501BBD84E7003ECEF8 /* ARTChannelOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = D746AE4E1BBD84E7003ECEF8 /* ARTChannelOptions.m */; };
D746AE531BBD85C5003ECEF8 /* ARTChannels.h in Headers */ = {isa = PBXBuildFile; fileRef = D746AE511BBD85C5003ECEF8 /* ARTChannels.h */; settings = {ATTRIBUTES = (Public, ); }; };
D746AE541BBD85C5003ECEF8 /* ARTChannels.m in Sources */ = {isa = PBXBuildFile; fileRef = D746AE521BBD85C5003ECEF8 /* ARTChannels.m */; };
D74A17B81FA0D9A3006D27B5 /* PushAdmin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74A17B61FA0D81A006D27B5 /* PushAdmin.swift */; };
D74EFAEB1C4D09B500CFF98E /* RealtimeClientChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74EFAEA1C4D09B500CFF98E /* RealtimeClientChannel.swift */; };
D7534C321D79E5C20054C182 /* Ably.h in Headers */ = {isa = PBXBuildFile; fileRef = D7534C311D79E5C20054C182 /* Ably.h */; settings = {ATTRIBUTES = (Public, ); }; };
D7588AF31BFF91B800BB8279 /* ARTURLSessionServerTrust.h in Headers */ = {isa = PBXBuildFile; fileRef = D7588AF11BFF91B800BB8279 /* ARTURLSessionServerTrust.h */; settings = {ATTRIBUTES = (Private, ); }; };
Expand Down Expand Up @@ -336,6 +337,7 @@
D746AE511BBD85C5003ECEF8 /* ARTChannels.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTChannels.h; sourceTree = "<group>"; };
D746AE521BBD85C5003ECEF8 /* ARTChannels.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTChannels.m; sourceTree = "<group>"; };
D746AE551BBD8622003ECEF8 /* ARTChannels+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ARTChannels+Private.h"; sourceTree = "<group>"; };
D74A17B61FA0D81A006D27B5 /* PushAdmin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushAdmin.swift; sourceTree = "<group>"; };
D74EFAEA1C4D09B500CFF98E /* RealtimeClientChannel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RealtimeClientChannel.swift; sourceTree = "<group>"; };
D7534C311D79E5C20054C182 /* Ably.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Ably.h; sourceTree = "<group>"; };
D7588AF11BFF91B800BB8279 /* ARTURLSessionServerTrust.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTURLSessionServerTrust.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -524,6 +526,7 @@
851674EE1B7BA5CD00D35169 /* Stats.swift */,
EB1AE0CD1C5C3A4900D62250 /* Utilities.swift */,
EB7913A71C6E54C3000ABF9B /* Crypto.swift */,
D74A17B61FA0D81A006D27B5 /* PushAdmin.swift */,
);
path = Spec;
sourceTree = "<group>";
Expand Down Expand Up @@ -1163,6 +1166,7 @@
851674EF1B7BA5CD00D35169 /* Stats.swift in Sources */,
EB1AE0CE1C5C3A4900D62250 /* Utilities.swift in Sources */,
D72304701BB72CED00F1ABDA /* RealtimeClient.swift in Sources */,
D74A17B81FA0D9A3006D27B5 /* PushAdmin.swift in Sources */,
EB7913A81C6E54C3000ABF9B /* Crypto.swift in Sources */,
D746AE2D1BBB625E003ECEF8 /* RestClientChannels.swift in Sources */,
EBAB9A6F1C69702800AF036B /* ReadmeExamples.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Examples/Tests/Podfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use_frameworks!

pod 'Ably', '1.0.4'
pod 'Ably', :path => '../..'

target 'Tests' do

Expand Down
17 changes: 12 additions & 5 deletions Examples/Tests/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
PODS:
- Ably (1.0.6):
- Ably (1.0.9):
- KSCrashAblyFork (= 1.15.8-ably-1)
- msgpack (= 0.1.8)
- SocketRocket (= 0.5.1)
- ULID (= 1.0.2)
- KSCrashAblyFork (1.15.8-ably-1):
- KSCrashAblyFork/Installations (= 1.15.8-ably-1)
- KSCrashAblyFork/Installations (1.15.8-ably-1):
Expand Down Expand Up @@ -68,16 +69,22 @@ PODS:
- KSCrashAblyFork/Recording
- msgpack (0.1.8)
- SocketRocket (0.5.1)
- ULID (1.0.2)

DEPENDENCIES:
- Ably (= 1.0.4)
- Ably (from `../..`)

EXTERNAL SOURCES:
Ably:
:path: ../..

SPEC CHECKSUMS:
Ably: bd558748b327967343d47c7499239ebce3c7944c
Ably: a649faf9d3e27ede0ce10cbd83c8fd413e84d55b
KSCrashAblyFork: 6d0dd5b033710109a8fdde28103eeb0e7f9ba1f7
msgpack: 97491d2ea799408f4694f2c7d7fd79baf77853dd
SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531
ULID: fcabaa95746b670beb80c029beb3372da2f729bd

PODFILE CHECKSUM: b0e88f668991e1f477a344039c876de0a56ea710
PODFILE CHECKSUM: 6af34bf7f91045b23539816c1d0cfe253bec5ea5

COCOAPODS: 1.2.1
COCOAPODS: 1.3.1
32 changes: 30 additions & 2 deletions Examples/Tests/Tests.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Tests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
4B4F9EED98BC61874DAB2F62 /* [CP] Check Pods Manifest.lock */ = {
Expand All @@ -256,13 +259,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-TestsTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
751C5C44401069CC5CAAEE9B /* [CP] Embed Pods Frameworks */ = {
Expand All @@ -271,9 +277,20 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Ably/Ably.framework",
"${BUILT_PRODUCTS_DIR}/KSCrashAblyFork/KSCrashAblyFork.framework",
"${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework",
"${BUILT_PRODUCTS_DIR}/ULID/ULID.framework",
"${BUILT_PRODUCTS_DIR}/msgpack/msgpack.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Ably.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KSCrashAblyFork.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketRocket.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ULID.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/msgpack.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand Down Expand Up @@ -316,9 +333,20 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-TestsTests/Pods-TestsTests-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Ably/Ably.framework",
"${BUILT_PRODUCTS_DIR}/KSCrashAblyFork/KSCrashAblyFork.framework",
"${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework",
"${BUILT_PRODUCTS_DIR}/ULID/ULID.framework",
"${BUILT_PRODUCTS_DIR}/msgpack/msgpack.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Ably.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KSCrashAblyFork.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketRocket.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ULID.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/msgpack.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand Down
16 changes: 8 additions & 8 deletions Examples/Tests/TestsTests/TestsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import XCTest
import Ably
@testable import Tests



class TestsTests: XCTestCase {

let options: ARTClientOptions! = nil

func testAblyWorks() {
Expand All @@ -26,14 +25,14 @@ class TestsTests: XCTestCase {
"Accept" : "application/json",
"Content-Type" : "application/json"
]
URLSession.shared.dataTask(with: request, completionHandler: { data, _, error in
URLSession.shared.dataTask(with: request as URLRequest) { data, _, error in
defer { postAppExpectation.fulfill() }
if let e = error {
XCTFail("Error setting up sandbox app: \(e)")
return
}
responseData = data
}) .resume()
}.resume()
self.waitForExpectations(timeout: 10, handler: nil)

guard let key = responseData
Expand Down Expand Up @@ -65,22 +64,23 @@ class TestsTests: XCTestCase {

let backgroundRealtimeExpectation = self.expectation(description: "Realtime in a Background Queue")
var realtime: ARTRealtime! //strong reference
URLSession.shared.dataTask(with: URL(string:"https://ably.io")!, completionHandler: { _ in
URLSession.shared.dataTask(with: URL(string: "https://ably.io")!) { _ in
realtime = ARTRealtime(key: key as String)
realtime.channels.get("foo").attach { _ in
defer { backgroundRealtimeExpectation.fulfill() }
}
}) .resume()
} .resume()
self.waitForExpectations(timeout: 10, handler: nil)

let backgroundRestExpectation = self.expectation(description: "Rest in a Background Queue")
var rest: ARTRest! //strong reference
URLSession.shared.dataTask(with: URL(string:"https://ably.io")!, completionHandler: { _ in
URLSession.shared.dataTask(with: URL(string: "https://ably.io")!) { _ in
rest = ARTRest(key: key as String)
rest.channels.get("foo").history { _ in
defer { backgroundRestExpectation.fulfill() }
}
}) .resume()
}.resume()
self.waitForExpectations(timeout: 10, handler: nil)
}

}
1 change: 1 addition & 0 deletions Source/ARTClientOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ ART_ASSUME_NONNULL_BEGIN
@property (readwrite, assign, nonatomic) BOOL useBinaryProtocol;
@property (readwrite, assign, nonatomic) BOOL autoConnect;
@property (art_nullable, readwrite, copy, nonatomic) NSString *recover;
@property (readwrite, assign, nonatomic) BOOL pushFullWait;

/**
The id of the client represented by this instance.
Expand Down
4 changes: 3 additions & 1 deletion Source/ARTClientOptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ - (instancetype)initDefaults {
_logExceptionReportingUrl = @"https://765e1fcaba404d7598d2fd5a2a43c4f0:[email protected]/3";
_dispatchQueue = dispatch_get_main_queue();
_internalDispatchQueue = dispatch_queue_create("io.ably.main", DISPATCH_QUEUE_SERIAL);
_pushFullWait = false;
return self;
}

Expand Down Expand Up @@ -125,7 +126,8 @@ - (id)copyWithZone:(NSZone *)zone {
options.logExceptionReportingUrl = self.logExceptionReportingUrl;
options.dispatchQueue = self.dispatchQueue;
options.internalDispatchQueue = self.internalDispatchQueue;

options.pushFullWait = self.pushFullWait;

return options;
}

Expand Down
49 changes: 49 additions & 0 deletions Source/ARTDeviceDetails.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,53 @@ - (instancetype)initWithId:(ARTDeviceId *)deviceId {
return self;
}

- (id)copyWithZone:(NSZone *)zone {
ARTDeviceDetails *device = [[[self class] allocWithZone:zone] init];

device.id = self.id;
device.clientId = self.clientId;
device.platform = self.platform;
device.formFactor = self.formFactor;
device.metadata = [self.metadata copy];
device.push = [self.push copy];
device.updateToken = self.updateToken;

return device;
}

- (NSString *)description {
return [NSString stringWithFormat:@"%@ - \n\t id: %@; \n\t clientId: %@; \n\t platform: %@; \n\t formFactor: %@; \n\t updateToken: %@;", [super description], self.id, self.clientId, self.formFactor, self.platform, self.updateToken];
}

- (BOOL)isEqualToDeviceDetail:(ARTDeviceDetails *)device {
if (!device) {
return NO;
}

BOOL haveEqualDeviceId = (!self.id && !device.id) || [self.id isEqualToString:device.id];
BOOL haveEqualCliendId = (!self.clientId && !device.clientId) || [self.clientId isEqualToString:device.clientId];
BOOL haveEqualPlatform = (!self.platform && !device.platform) || [self.platform isEqualToString:device.platform];
BOOL haveEqualFormFactor = (!self.formFactor && !device.formFactor) || [self.formFactor isEqualToString:device.formFactor];

return haveEqualDeviceId && haveEqualCliendId && haveEqualPlatform && haveEqualFormFactor;
}

#pragma mark - NSObject

- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}

if (![object isKindOfClass:[ARTDeviceDetails class]]) {
return NO;
}

return [self isEqualToDeviceDetail:(ARTDeviceDetails *)object];
}

- (NSUInteger)hash {
return [self.id hash] ^ [self.clientId hash] ^ [self.formFactor hash] ^ [self.platform hash];
}

@end
14 changes: 14 additions & 0 deletions Source/ARTDevicePushDetails.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,18 @@ - (instancetype)init {
return self;
}

- (id)copyWithZone:(NSZone *)zone {
ARTDevicePushDetails *push = [[[self class] allocWithZone:zone] init];

push.recipient = [self.recipient copy];
push.state = self.state;
push.errorReason = [self.errorReason copy];

return push;
}

- (NSString *)description {
return [NSString stringWithFormat:@"%@ - \n\t recipient: %@; \n\t state: %@; \n\t errorReason: %@;", [super description], self.recipient, self.state, self.errorReason];
}

@end
2 changes: 1 addition & 1 deletion Source/ARTJsonLikeEncoder.m
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ - (NSDictionary *)deviceDetailsToDictionary:(ARTDeviceDetails *)deviceDetails {
dictionary[@"formFactor"] = deviceDetails.formFactor;

if (deviceDetails.clientId) {
dictionary[@"cliendId"] = deviceDetails.clientId;
dictionary[@"clientId"] = deviceDetails.clientId;
}

dictionary[@"push"] = [self devicePushDetailsToDictionary:deviceDetails.push];
Expand Down
9 changes: 0 additions & 9 deletions Source/ARTPush.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@
@class ARTRealtime;
@class ARTDeviceDetails;

// More context
typedef NSString ARTDeviceId;
typedef NSData ARTDeviceToken;
typedef NSString ARTUpdateToken;
typedef ARTJsonObject ARTPushRecipient;

#pragma mark ARTPushRegisterer interface

#ifdef TARGET_OS_IOS
Expand Down Expand Up @@ -51,9 +45,6 @@ NS_ASSUME_NONNULL_BEGIN

- (instancetype)init NS_UNAVAILABLE;

/// Publish a push notification.
- (void)publish:(ARTPushRecipient *)recipient notification:(ARTJsonObject *)notification callback:(art_nullable void (^)(ARTErrorInfo *__art_nullable error))callback;

#ifdef TARGET_OS_IOS

/// Push Registration token
Expand Down
38 changes: 0 additions & 38 deletions Source/ARTPush.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,55 +30,17 @@
@implementation ARTPush {
ARTRest *_rest;
__weak ARTLog *_logger;
dispatch_queue_t _queue;
dispatch_queue_t _userQueue;
}

- (instancetype)init:(ARTRest *)rest {
if (self = [super init]) {
_rest = rest;
_logger = [rest logger];
_admin = [[ARTPushAdmin alloc] init:rest];
_queue = rest.queue;
_userQueue = rest.userQueue;
}
return self;
}

- (void)publish:(ARTPushRecipient *)recipient notification:(ARTJsonObject *)notification callback:(art_nullable void (^)(ARTErrorInfo *__art_nullable error))callback {
if (callback) {
void (^userCallback)(ARTErrorInfo *error) = callback;
callback = ^(ARTErrorInfo *error) {
ART_EXITING_ABLY_CODE(_rest);
dispatch_async(_userQueue, ^{
userCallback(error);
});
};
}

dispatch_async(_queue, ^{
ART_TRY_OR_REPORT_CRASH_START(_rest) {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/push/publish"]];
request.HTTPMethod = @"POST";
NSMutableDictionary *body = [NSMutableDictionary dictionary];
[body setObject:recipient forKey:@"recipient"];
[body addEntriesFromDictionary:notification];
request.HTTPBody = [[_rest defaultEncoder] encode:body error:nil];
[request setValue:[[_rest defaultEncoder] mimeType] forHTTPHeaderField:@"Content-Type"];

[_logger debug:__FILE__ line:__LINE__ message:@"push notification to a single device %@", request];
[_rest executeRequest:request withAuthOption:ARTAuthenticationOn completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
if (error) {
[_logger error:@"%@: push notification to a single device failed (%@)", NSStringFromClass(self.class), error.localizedDescription];
if (callback) callback([ARTErrorInfo createFromNSError:error]);
return;
}
if (callback) callback(nil);
}];
} ART_TRY_OR_REPORT_CRASH_END
});
}

#ifdef TARGET_OS_IOS

- (ARTPushActivationStateMachine *)activationMachine {
Expand Down
Loading

0 comments on commit fea3162

Please sign in to comment.