diff options
author | 2017-05-15 12:27:07 -0700 | |
---|---|---|
committer | 2017-05-15 12:27:07 -0700 | |
commit | 98ba64449a632518bd2b86fe8d927f4a960d3ddc (patch) | |
tree | 131d9c4272fa6179fcda6c5a33fcb3b1bd57ad2e /Example/Messaging/Tests/FIRMessagingClientTest.m | |
parent | 32461366c9e204a527ca05e6e9b9404a2454ac51 (diff) |
Initial
Diffstat (limited to 'Example/Messaging/Tests/FIRMessagingClientTest.m')
-rw-r--r-- | Example/Messaging/Tests/FIRMessagingClientTest.m | 308 |
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 + |