aboutsummaryrefslogtreecommitdiffhomepage
path: root/Example/Messaging/Tests/FIRMessagingClientTest.m
diff options
context:
space:
mode:
authorGravatar Paul Beusterien <paulbeusterien@google.com>2017-05-15 12:27:07 -0700
committerGravatar Paul Beusterien <paulbeusterien@google.com>2017-05-15 12:27:07 -0700
commit98ba64449a632518bd2b86fe8d927f4a960d3ddc (patch)
tree131d9c4272fa6179fcda6c5a33fcb3b1bd57ad2e /Example/Messaging/Tests/FIRMessagingClientTest.m
parent32461366c9e204a527ca05e6e9b9404a2454ac51 (diff)
Initial
Diffstat (limited to 'Example/Messaging/Tests/FIRMessagingClientTest.m')
-rw-r--r--Example/Messaging/Tests/FIRMessagingClientTest.m308
1 files changed, 308 insertions, 0 deletions
diff --git a/Example/Messaging/Tests/FIRMessagingClientTest.m b/Example/Messaging/Tests/FIRMessagingClientTest.m
new file mode 100644
index 0000000..f36ec53
--- /dev/null
+++ b/Example/Messaging/Tests/FIRMessagingClientTest.m
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@import XCTest;
+
+#import <OCMock/OCMock.h>
+
+#import "Protos/GtalkCore.pbobjc.h"
+
+#import "FIRMessagingCheckinService.h"
+#import "FIRMessagingClient.h"
+#import "FIRMessagingConnection.h"
+#import "FIRMessagingDataMessageManager.h"
+#import "FIRMessagingFakeConnection.h"
+#import "FIRMessagingRegistrar.h"
+#import "FIRMessagingRmqManager.h"
+#import "FIRMessagingSecureSocket.h"
+#import "FIRMessagingUtilities.h"
+#import "NSError+FIRMessaging.h"
+
+#import "FIRReachabilityChecker.h"
+
+static NSString *const kFIRMessagingUserDefaultsSuite = @"FIRMessagingClientTestUserDefaultsSuite";
+
+static NSString *const kDeviceAuthId = @"123456";
+static NSString *const kSecretToken = @"56789";
+static NSString *const kDigest = @"com.google.digest";
+static NSString *const kVersionInfo = @"1.0";
+static NSString *const kSubscriptionID = @"abcdef-subscription-id";
+static NSString *const kDeletedSubscriptionID = @"deleted-abcdef-subscription-id";
+static NSString *const kFIRMessagingAppIDToken = @"1234xyzdef56789";
+static NSString *const kTopicToSubscribeTo = @"/topics/abcdef/hello-world";
+
+@interface FIRMessagingRegistrar ()
+
+@property(nonatomic, readwrite, strong) FIRMessagingCheckinService *checkinService;
+
+@end
+
+@interface FIRMessagingClient () <FIRMessagingConnectionDelegate>
+
+@property(nonatomic, readwrite, strong) FIRMessagingConnection *connection;
+@property(nonatomic, readwrite, strong) FIRMessagingRegistrar *registrar;
+
+@property(nonatomic, readwrite, assign) int64_t lastConnectedTimestamp;
+@property(nonatomic, readwrite, assign) int64_t lastDisconnectedTimestamp;
+@property(nonatomic, readwrite, assign) NSUInteger subscribeRetryCount;
+@property(nonatomic, readwrite, assign) NSUInteger connectRetryCount;
+
+- (NSTimeInterval)connectionTimeoutInterval;
+- (void)setupConnection;
+
+@end
+
+@interface FIRMessagingConnection () <FIRMessagingSecureSocketDelegate>
+
+@property(nonatomic, readwrite, strong) FIRMessagingSecureSocket *socket;
+
+- (void)setupConnectionSocket;
+- (void)connectToSocket:(FIRMessagingSecureSocket *)socket;
+- (NSTimeInterval)connectionTimeoutInterval;
+- (void)sendHeartbeatPing;
+
+@end
+
+@interface FIRMessagingSecureSocket ()
+
+@property(nonatomic, readwrite, assign) FIRMessagingSecureSocketState state;
+
+@end
+
+@interface FIRMessagingClientTest : XCTestCase
+
+@property(nonatomic, readwrite, strong) FIRMessagingClient *client;
+@property(nonatomic, readwrite, strong) id mockClient;
+@property(nonatomic, readwrite, strong) id mockReachability;
+@property(nonatomic, readwrite, strong) id mockRmqManager;
+@property(nonatomic, readwrite, strong) id mockClientDelegate;
+@property(nonatomic, readwrite, strong) id mockDataMessageManager;
+@property(nonatomic, readwrite, strong) id mockRegistrar;
+
+// argument callback blocks
+@property(nonatomic, readwrite, copy) FIRMessagingConnectCompletionHandler connectCompletion;
+@property(nonatomic, readwrite, copy) FIRMessagingTopicOperationCompletion subscribeCompletion;
+
+@end
+
+@implementation FIRMessagingClientTest
+
+- (void)setUp {
+ [super setUp];
+ _mockClientDelegate =
+ OCMStrictProtocolMock(@protocol(FIRMessagingClientDelegate));
+ _mockReachability = OCMClassMock([FIRReachabilityChecker class]);
+ _mockRmqManager = OCMClassMock([FIRMessagingRmqManager class]);
+ _client = [[FIRMessagingClient alloc] initWithDelegate:_mockClientDelegate
+ reachability:_mockReachability
+ rmq2Manager:_mockRmqManager];
+ _mockClient = OCMPartialMock(_client);
+ _mockRegistrar = OCMPartialMock([_client registrar]);
+ [_mockClient setRegistrar:_mockRegistrar];
+ _mockDataMessageManager = OCMClassMock([FIRMessagingDataMessageManager class]);
+ [_mockClient setDataMessageManager:_mockDataMessageManager];
+}
+
+- (void)tearDown {
+ // remove all handlers
+ [self tearDownMocksAndHandlers];
+ // Mock all sockets to disconnect in a nice way
+ [[[(id)self.client.connection.socket stub] andDo:^(NSInvocation *invocation) {
+ self.client.connection.socket.state = kFIRMessagingSecureSocketClosed;
+ }] disconnect];
+
+ [self.client teardown];
+ [super tearDown];
+}
+
+- (void)tearDownMocksAndHandlers {
+ self.connectCompletion = nil;
+ self.subscribeCompletion = nil;
+}
+
+- (void)setupConnectionWithFakeLoginResult:(BOOL)loginResult
+ heartbeatTimeout:(NSTimeInterval)heartbeatTimeout {
+ [self setupFakeConnectionWithClass:[FIRMessagingFakeConnection class]
+ withSetupCompletionHandler:^(FIRMessagingConnection *connection) {
+ FIRMessagingFakeConnection *fakeConnection = (FIRMessagingFakeConnection *)connection;
+ fakeConnection.shouldFakeSuccessLogin = loginResult;
+ fakeConnection.fakeConnectionTimeout = heartbeatTimeout;
+ }];
+}
+
+- (void)testSetupConnection {
+ XCTAssertNil(self.client.connection);
+ [self.client setupConnection];
+ XCTAssertNotNil(self.client.connection);
+ XCTAssertNotNil(self.client.connection.delegate);
+}
+
+- (void)testConnectSuccess_withCachedFcmDefaults {
+ [self addFIRMessagingPreferenceKeysToUserDefaults];
+
+ // login request should be successful
+ [self setupConnectionWithFakeLoginResult:YES heartbeatTimeout:1.0];
+
+ XCTestExpectation *setupConnection = [self
+ expectationWithDescription:@"Fcm should successfully setup a connection"];
+
+ [self.client connectWithHandler:^(NSError *error) {
+ XCTAssertNil(error);
+ [setupConnection fulfill];
+ }];
+
+ [self waitForExpectationsWithTimeout:1.0 handler:^(NSError *error) {
+ XCTAssertNil(error);
+ }];
+}
+
+- (void)testsConnectWithNoNetworkError_withCachedFcmDefaults {
+ // connection timeout interval is 1s
+ [[[self.mockClient stub] andReturnValue:@(1)] connectionTimeoutInterval];
+ [self addFIRMessagingPreferenceKeysToUserDefaults];
+
+ [self setupFakeConnectionWithClass:[FIRMessagingFakeFailConnection class]
+ withSetupCompletionHandler:^(FIRMessagingConnection *connection) {
+ FIRMessagingFakeFailConnection *fakeConnection = (FIRMessagingFakeFailConnection *)connection;
+ fakeConnection.shouldFakeSuccessLogin = NO;
+ // should fail only once
+ fakeConnection.failCount = 1;
+ }];
+
+ XCTestExpectation *connectExpectation = [self
+ expectationWithDescription:@"Should retry connection if once failed"];
+ [self.client connectWithHandler:^(NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqual(kFIRMessagingErrorCodeNetwork, error.code);
+ [connectExpectation fulfill];
+ }];
+
+ [self waitForExpectationsWithTimeout:10.0
+ handler:^(NSError *error) {
+ XCTAssertNil(error);
+ }];
+}
+
+- (void)testConnectSuccessOnSecondTry_withCachedFcmDefaults {
+ // connection timeout interval is 1s
+ [[[self.mockClient stub] andReturnValue:@(1)] connectionTimeoutInterval];
+ [self addFIRMessagingPreferenceKeysToUserDefaults];
+
+ // the network is available
+ [[[self.mockReachability stub]
+ andReturnValue:@(kFIRReachabilityViaWifi)] reachabilityStatus];
+
+ [self setupFakeConnectionWithClass:[FIRMessagingFakeFailConnection class]
+ withSetupCompletionHandler:^(FIRMessagingConnection *connection) {
+ FIRMessagingFakeFailConnection *fakeConnection = (FIRMessagingFakeFailConnection *)connection;
+ fakeConnection.shouldFakeSuccessLogin = NO;
+ // should fail only once
+ fakeConnection.failCount = 1;
+ }];
+
+ XCTestExpectation *connectExpectation = [self
+ expectationWithDescription:@"Should retry connection if once failed"];
+ [self.client connectWithHandler:^(NSError *error) {
+ XCTAssertNil(error);
+ [connectExpectation fulfill];
+ }];
+
+ [self waitForExpectationsWithTimeout:10.0
+ handler:^(NSError *error) {
+ XCTAssertNil(error);
+ XCTAssertTrue(
+ [self.client isConnectionActive]);
+ }];
+}
+
+- (void)testDisconnectAfterConnect {
+ // setup the connection
+ [self addFIRMessagingPreferenceKeysToUserDefaults];
+
+ // login request should be successful
+ // Connection should not timeout because of heartbeat failure. Therefore set heartbeatTimeout
+ // to a large value.
+ [self setupConnectionWithFakeLoginResult:YES heartbeatTimeout:100.0];
+
+ [[[self.mockClient stub] andReturnValue:@(1)] connectionTimeoutInterval];
+
+ // the network is available
+ [[[self.mockReachability stub]
+ andReturnValue:@(kFIRReachabilityViaWifi)] reachabilityStatus];
+
+ XCTestExpectation *setupConnection =
+ [self expectationWithDescription:@"Fcm should successfully setup a connection"];
+
+ __block int timesConnected = 0;
+ FIRMessagingConnectCompletionHandler handler = ^(NSError *error) {
+ XCTAssertNil(error);
+ timesConnected++;
+ if (timesConnected == 1) {
+ [setupConnection fulfill];
+ // disconnect the connection after some time
+ FIRMessagingFakeConnection *fakeConnection = (FIRMessagingFakeConnection *)[self.mockClient connection];
+ dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (0.2 * NSEC_PER_SEC));
+ dispatch_after(time, dispatch_get_main_queue(), ^{
+ // disconnect now
+ [(FIRMessagingFakeConnection *)fakeConnection mockSocketDisconnect];
+ [(FIRMessagingFakeConnection *)fakeConnection disconnectNow];
+ });
+ } else {
+ XCTFail(@"Fcm should only connect at max 2 times");
+ }
+ };
+ [self.mockClient connectWithHandler:handler];
+
+ // reconnect after disconnect
+ XCTAssertTrue(self.client.isConnectionActive);
+
+ [self waitForExpectationsWithTimeout:10.0
+ handler:^(NSError *error) {
+ XCTAssertNil(error);
+ XCTAssertNotEqual(self.client.lastDisconnectedTimestamp, 0);
+ XCTAssertTrue(self.client.isConnectionActive);
+ }];
+}
+
+#pragma mark - Private Helpers
+
+- (void)setupFakeConnectionWithClass:(Class)connectionClass
+ withSetupCompletionHandler:(void (^)(FIRMessagingConnection *))handler {
+ [[[self.mockClient stub] andDo:^(NSInvocation *invocation) {
+ self.client.connection =
+ [[connectionClass alloc] initWithAuthID:kDeviceAuthId
+ token:kSecretToken
+ host:[FIRMessagingFakeConnection fakeHost]
+ port:[FIRMessagingFakeConnection fakePort]
+ runLoop:[NSRunLoop mainRunLoop]
+ rmq2Manager:self.mockRmqManager
+ fcmManager:self.mockDataMessageManager];
+ self.client.connection.delegate = self.client;
+ handler(self.client.connection);
+ }] setupConnection];
+}
+
+- (void)addFIRMessagingPreferenceKeysToUserDefaults {
+ id mockCheckinService = OCMClassMock([FIRMessagingCheckinService class]);
+ [[[mockCheckinService stub] andReturn:kDeviceAuthId] deviceAuthID];
+ [[[mockCheckinService stub] andReturn:kSecretToken] secretToken];
+ [[[mockCheckinService stub] andReturnValue:@YES] hasValidCheckinInfo];
+
+ [[[self.mockRegistrar stub] andReturn:mockCheckinService] checkinService];
+}
+
+@end
+