aboutsummaryrefslogtreecommitdiffhomepage
path: root/Example/Messaging/Tests/FIRMessagingDataMessageManagerTest.m
diff options
context:
space:
mode:
Diffstat (limited to 'Example/Messaging/Tests/FIRMessagingDataMessageManagerTest.m')
-rw-r--r--Example/Messaging/Tests/FIRMessagingDataMessageManagerTest.m662
1 files changed, 662 insertions, 0 deletions
diff --git a/Example/Messaging/Tests/FIRMessagingDataMessageManagerTest.m b/Example/Messaging/Tests/FIRMessagingDataMessageManagerTest.m
new file mode 100644
index 0000000..2b4f407
--- /dev/null
+++ b/Example/Messaging/Tests/FIRMessagingDataMessageManagerTest.m
@@ -0,0 +1,662 @@
+/*
+ * 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 "FIRMessaging.h"
+#import "FIRMessagingClient.h"
+#import "FIRMessagingConfig.h"
+#import "FIRMessagingConnection.h"
+#import "FIRMessagingDataMessageManager.h"
+#import "FIRMessagingReceiver.h"
+#import "FIRMessagingRmqManager.h"
+#import "FIRMessagingSyncMessageManager.h"
+#import "FIRMessagingUtilities.h"
+#import "FIRMessaging_Private.h"
+#import "FIRMessagingConstants.h"
+#import "FIRMessagingDefines.h"
+#import "NSError+FIRMessaging.h"
+
+static NSString *const kFIRMessagingUserDefaultsSuite = @"FIRMessagingClientTestUserDefaultsSuite";
+
+static NSString *const kFIRMessagingAppIDToken = @"1234abcdef789";
+
+static NSString *const kMessagePersistentID = @"abcdef123";
+static NSString *const kMessageFrom = @"com.example.gcm";
+static NSString *const kMessageTo = @"123456789";
+static NSString *const kCollapseKey = @"collapse-1";
+static NSString *const kAppDataItemKey = @"hello";
+static NSString *const kAppDataItemValue = @"world";
+static NSString *const kAppDataItemInvalidKey = @"google.hello";
+
+static NSString *const kRmqDatabaseName = @"gcm-dmm-test";
+
+@interface FIRMessagingDataMessageManager()
+
+@property(nonatomic, readwrite, weak) FIRMessagingRmqManager *rmq2Manager;
+
+- (NSString *)categoryForUpstreamMessages;
+
+@end
+
+@interface FIRMessagingDataMessageManagerTest : XCTestCase
+
+@property(nonatomic, readwrite, strong) id mockClient;
+@property(nonatomic, readwrite, strong) id mockRmqManager;
+@property(nonatomic, readwrite, strong) id mockReceiver;
+@property(nonatomic, readwrite, strong) id mockSyncMessageManager;
+@property(nonatomic, readwrite, strong) FIRMessagingDataMessageManager *dataMessageManager;
+@property(nonatomic, readwrite, strong) id mockDataMessageManager;
+
+@end
+
+@implementation FIRMessagingDataMessageManagerTest
+
+- (void)setUp {
+ [super setUp];
+ _mockClient = OCMClassMock([FIRMessagingClient class]);
+ _mockReceiver = OCMClassMock([FIRMessagingReceiver class]);
+ _mockRmqManager = OCMClassMock([FIRMessagingRmqManager class]);
+ _mockSyncMessageManager = OCMClassMock([FIRMessagingSyncMessageManager class]);
+ _dataMessageManager = [[FIRMessagingDataMessageManager alloc]
+ initWithDelegate:_mockReceiver
+ client:_mockClient
+ rmq2Manager:_mockRmqManager
+ syncMessageManager:_mockSyncMessageManager];
+ [_dataMessageManager refreshDelayedMessages];
+ _mockDataMessageManager = OCMPartialMock(_dataMessageManager);
+}
+
+
+- (void)testSendValidMessage_withNoConnection {
+ // mock no connection initially
+ NSString *messageID = @"1";
+ BOOL mockConnectionActive = NO;
+ [[[self.mockClient stub] andDo:^(NSInvocation *invocation) {
+ NSValue *returnValue = [NSValue valueWithBytes:&mockConnectionActive
+ objCType:@encode(BOOL)];
+ [invocation setReturnValue:&returnValue];
+ }] isConnectionActive];
+
+ BOOL(^isValidStanza)(id obj) = ^BOOL(id obj) {
+ if ([obj isKindOfClass:[GtalkDataMessageStanza class]]) {
+ GtalkDataMessageStanza *message = (GtalkDataMessageStanza *)obj;
+ return ([message.id_p isEqualToString:messageID] && [message.to isEqualToString:kMessageTo]);
+ }
+ return NO;
+ };
+ OCMExpect([self.mockReceiver willSendDataMessageWithID:[OCMArg isEqual:messageID]
+ error:[OCMArg isNil]]);
+ [[[self.mockRmqManager stub] andReturnValue:@YES]
+ saveRmqMessage:[OCMArg checkWithBlock:isValidStanza]
+ error:[OCMArg anyObjectRef]];
+
+ // should be logged into the service
+ [self addFakeFIRMessagingRegistrationToken];
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ // try to send messages with no connection should be queued into RMQ
+ NSMutableDictionary *message = [self upstreamMessageWithID:messageID ttl:-1 delay:0];
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ OCMVerifyAll(self.mockReceiver);
+ OCMVerifyAll(self.mockRmqManager);
+}
+
+- (void)testSendValidMessage_withoutCheckinAuthentication {
+ NSString *messageID = @"1";
+ NSMutableDictionary *message = [self standardFIRMessagingMessageWithMessageID:messageID];
+
+ OCMExpect([self.mockReceiver
+ willSendDataMessageWithID:[OCMArg isEqual:messageID]
+ error:[OCMArg checkWithBlock:^BOOL(id obj) {
+ if ([obj isKindOfClass:[NSError class]]) {
+ NSError *error = (NSError *)obj;
+ return error.code == kFIRMessagingErrorCodeMissingDeviceID;
+ }
+ return NO;
+ }]]);
+
+ // do not log into checkin service
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ OCMVerifyAll(self.mockReceiver);
+}
+
+- (void)testSendInvalidMessage_withNoTo {
+ NSString *messageID = @"1";
+ NSMutableDictionary *message =
+ [FIRMessaging createFIRMessagingMessageWithMessage:@{ kAppDataItemKey : kAppDataItemValue}
+ to:@""
+ withID:messageID
+ timeToLive:-1
+ delay:0];
+
+ OCMExpect([self.mockReceiver
+ willSendDataMessageWithID:[OCMArg isEqual:messageID]
+ error:[OCMArg checkWithBlock:^BOOL(id obj) {
+ if ([obj isKindOfClass:[NSError class]]) {
+ NSError *error = (NSError *)obj;
+ return error.code == kFIRMessagingErrorMissingTo;
+ }
+ return NO;
+ }]]);
+
+ // should be logged into the service
+ [self addFakeFIRMessagingRegistrationToken];
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ OCMVerifyAll(self.mockReceiver);
+}
+
+- (void)testSendInvalidMessage_withSizeExceeded {
+ NSString *messageID = @"1";
+ NSString *veryLargeString = [@"a" stringByPaddingToLength:4 * 1024 // 4kB
+ withString:@"b"
+ startingAtIndex:0];
+ NSMutableDictionary *message =
+ [FIRMessaging createFIRMessagingMessageWithMessage:@{ kAppDataItemKey : veryLargeString }
+ to:kMessageTo
+ withID:messageID
+ timeToLive:-1
+ delay:0];
+
+ OCMExpect([self.mockReceiver
+ willSendDataMessageWithID:[OCMArg isEqual:messageID]
+ error:[OCMArg checkWithBlock:^BOOL(id obj) {
+ if ([obj isKindOfClass:[NSError class]]) {
+ NSError *error = (NSError *)obj;
+ return error.code == kFIRMessagingErrorSizeExceeded;
+ }
+ return NO;
+ }]]);
+
+ [self addFakeFIRMessagingRegistrationToken];
+ // should be logged into the service
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ OCMVerifyAll(self.mockReceiver);
+}
+
+// TODO: Add test with rawData exceeding 4KB in size
+
+- (void)testSendValidMessage_withRmqSaveError {
+ NSString *messageID = @"1";
+ NSMutableDictionary *message = [self standardFIRMessagingMessageWithMessageID:messageID];
+ [[[self.mockRmqManager stub] andReturnValue:@NO]
+ saveRmqMessage:[OCMArg any] error:[OCMArg anyObjectRef]];
+
+ OCMExpect([self.mockReceiver
+ willSendDataMessageWithID:[OCMArg isEqual:messageID]
+ error:[OCMArg checkWithBlock:^BOOL(id obj) {
+ if ([obj isKindOfClass:[NSError class]]) {
+ NSError *error = (NSError *)obj;
+ return error.code == kFIRMessagingErrorSave;
+ }
+ return NO;
+ }]]);
+
+ // should be logged into the service
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ [self addFakeFIRMessagingRegistrationToken];
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ OCMVerifyAll(self.mockReceiver);
+}
+
+- (void)testSendValidMessage_withTTL0 {
+ // simulate a valid connection
+ [[[self.mockClient stub] andReturnValue:@YES] isConnectionActive];
+ NSString *messageID = @"1";
+ NSMutableDictionary *message = [self upstreamMessageWithID:messageID ttl:0 delay:0];
+
+ BOOL(^isValidStanza)(id obj) = ^BOOL(id obj) {
+ if ([obj isKindOfClass:[GtalkDataMessageStanza class]]) {
+ GtalkDataMessageStanza *stanza = (GtalkDataMessageStanza *)obj;
+ return ([stanza.id_p isEqualToString:messageID] &&
+ [stanza.to isEqualToString:kMessageTo] &&
+ stanza.ttl == 0);
+ }
+ return NO;
+ };
+
+ OCMExpect([self.mockClient sendMessage:[OCMArg checkWithBlock:isValidStanza]]);
+
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ [self addFakeFIRMessagingRegistrationToken];
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ OCMVerifyAll(self.mockClient);
+}
+
+// TODO: This is failing on simulator 7.1 & 8.2, take this out temporarily
+- (void)XXX_testSendValidMessage_withTTL0AndNoFIRMessagingConnection {
+ // simulate a invalid connection
+ [[[self.mockClient stub] andReturnValue:@NO] isConnectionActive];
+
+ // simulate network reachability
+ FIRMessaging *service = [FIRMessaging messaging];
+ id mockService = OCMPartialMock(service);
+ [[[mockService stub] andReturnValue:@YES] isNetworkAvailable];
+
+ NSString *messageID = @"1";
+ NSMutableDictionary *message = [self upstreamMessageWithID:messageID ttl:0 delay:0];
+
+
+ BOOL(^isValidStanza)(id obj) = ^BOOL(id obj) {
+ if ([obj isKindOfClass:[GtalkDataMessageStanza class]]) {
+ GtalkDataMessageStanza *stanza = (GtalkDataMessageStanza *)obj;
+ return ([stanza.id_p isEqualToString:messageID] &&
+ [stanza.to isEqualToString:kMessageTo] &&
+ stanza.ttl == 0);
+ }
+ return NO;
+ };
+
+ // should save the message to be sent when we reconnect the next time
+ OCMExpect([self.mockClient sendOnConnectOrDrop:[OCMArg checkWithBlock:isValidStanza]]);
+ // should also try to reconnect immediately
+ OCMExpect([self.mockClient retryConnectionImmediately:[OCMArg isEqual:@YES]]);
+
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ [self addFakeFIRMessagingRegistrationToken];
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ OCMVerifyAll(self.mockClient);
+}
+
+// TODO: Investigate why this test is flaky
+- (void)xxx_testSendValidMessage_withTTL0AndNoNetwork {
+ // simulate a invalid connection
+ [[[self.mockClient stub] andReturnValue:@NO] isConnectionActive];
+
+ NSString *messageID = @"1";
+ NSMutableDictionary *message = [self upstreamMessageWithID:messageID ttl:0 delay:0];
+
+
+ // should drop the message since there is no network
+ OCMExpect([self.mockReceiver willSendDataMessageWithID:[OCMArg isEqual:messageID]
+ error:[OCMArg checkWithBlock:^BOOL(id obj) {
+ if ([obj isKindOfClass:[NSError class]]) {
+ NSError *error = (NSError *)obj;
+ return error.code == kFIRMessagingErrorCodeNetwork;
+ }
+ return NO;
+ }]]);
+
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ [self addFakeFIRMessagingRegistrationToken];
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ OCMVerifyAll(self.mockReceiver);
+}
+
+// TODO: This failed on simulator 7.1 & 8.2, take this out temporarily
+- (void)XXX_testDelayedMessagesBeingResentOnReconnect {
+ static BOOL isConnectionActive = NO;
+ OCMStub([self.mockClient isConnectionActive]).andDo(^(NSInvocation *invocation) {
+ [invocation setReturnValue:&isConnectionActive];
+ });
+
+ // message that lives for 2 seconds
+ NSString *messageID = @"1";
+ int ttl = 2;
+ NSMutableDictionary *message = [self upstreamMessageWithID:messageID ttl:ttl delay:1];
+
+ __block GtalkDataMessageStanza *firstMessageStanza;
+
+ OCMStub([self.mockRmqManager saveRmqMessage:[OCMArg any]
+ error:[OCMArg anyObjectRef]]).andReturn(YES);
+
+ OCMExpect([self.mockReceiver willSendDataMessageWithID:[OCMArg isEqual:messageID]
+ error:[OCMArg isNil]]);
+
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ [self addFakeFIRMessagingRegistrationToken];
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ __block FIRMessagingDataMessageHandler dataMessageHandler;
+
+ [[[self.mockRmqManager stub] andDo:^(NSInvocation *invocation) {
+ dataMessageHandler([FIRMessagingGetRmq2Id(firstMessageStanza) longLongValue],
+ firstMessageStanza);
+ }]
+ scanWithRmqMessageHandler:[OCMArg isNil]
+ dataMessageHandler:[OCMArg checkWithBlock:^BOOL(id obj) {
+ dataMessageHandler = obj;
+ return YES;
+ }]];
+
+ // expect both 1 and 2 messages to be sent once we regain connection
+ __block BOOL firstMessageSent = NO;
+ __block BOOL secondMessageSent = NO;
+ XCTestExpectation *didSendAllMessages =
+ [self expectationWithDescription:@"Did send all messages"];
+ OCMExpect([self.mockClient sendMessage:[OCMArg checkWithBlock:^BOOL(id obj) {
+ // [didSendAllMessages fulfill];
+ if ([obj isKindOfClass:[GtalkDataMessageStanza class]]) {
+ GtalkDataMessageStanza *message = (GtalkDataMessageStanza *)obj;
+ if ([@"1" isEqualToString:message.id_p]) {
+ firstMessageSent = YES;
+ } else if ([@"2" isEqualToString:message.id_p]) {
+ secondMessageSent = YES;
+ }
+ if (firstMessageSent && secondMessageSent) {
+ [didSendAllMessages fulfill];
+ }
+ return firstMessageSent || secondMessageSent;
+ }
+ return NO;
+ }]]);
+
+ // send the second message after some delay
+ [NSThread sleepForTimeInterval:2.0];
+
+ isConnectionActive = YES;
+ // simulate active connection
+ NSString *newMessageID = @"2";
+ NSMutableDictionary *newMessage = [self upstreamMessageWithID:newMessageID
+ ttl:0
+ delay:0];
+ // send another message to resend not sent messages
+ [self.dataMessageManager sendDataMessageStanza:newMessage];
+
+ [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
+ XCTAssertNil(error);
+ OCMVerifyAll(self.mockClient);
+ OCMVerifyAll(self.mockReceiver);
+ }];
+}
+
+- (void)testSendDelayedMessage_shouldNotSend {
+ // should not send a delayed message even with an active connection
+ // simulate active connection
+ [[[self.mockClient stub] andReturnValue:OCMOCK_VALUE(YES)] isConnectionActive];
+ [[self.mockClient reject] sendMessage:[OCMArg any]];
+
+ [[self.mockReceiver reject] didSendDataMessageWithID:[OCMArg any]];
+
+ // delayed message
+ NSString *messageID = @"1";
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ NSMutableDictionary *message = [self upstreamMessageWithID:messageID ttl:0 delay:1];
+ [self.dataMessageManager sendDataMessageStanza:message];
+
+ OCMVerifyAll(self.mockClient);
+ OCMVerifyAll(self.mockReceiver);
+}
+
+- (void)testProcessPacket_withValidPacket {
+ GtalkDataMessageStanza *message = [self validDataMessagePacket];
+ NSDictionary *parsedMessage = [self.dataMessageManager processPacket:message];
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingFromKey], message.from);
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingCollapseKey], message.token);
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingMessageIDKey], kMessagePersistentID);
+ XCTAssertEqualObjects(parsedMessage[kAppDataItemKey], kAppDataItemValue);
+ XCTAssertEqual(4, parsedMessage.count);
+}
+
+- (void)testProcessPacket_withOnlyFrom {
+ GtalkDataMessageStanza *message = [self validDataMessageWithOnlyFrom];
+ NSDictionary *parsedMessage = [self.dataMessageManager processPacket:message];
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingFromKey], message.from);
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingMessageIDKey], kMessagePersistentID);
+ XCTAssertEqual(2, parsedMessage.count);
+}
+
+- (void)testProcessPacket_withInvalidPacket {
+ GtalkDataMessageStanza *message = [self invalidDataMessageUsingReservedKeyword];
+ NSDictionary *parsedMessage = [self.dataMessageManager processPacket:message];
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingFromKey], message.from);
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingMessageIDKey], kMessagePersistentID);
+ XCTAssertEqual(2, parsedMessage.count);
+}
+
+/**
+ * Test parsing a duplex message.
+ */
+- (void)testProcessPacket_withDuplexMessage {
+ GtalkDataMessageStanza *stanza = [self validDuplexmessage];
+ NSDictionary *parsedMessage = [self.dataMessageManager processPacket:stanza];
+ XCTAssertEqual(5, parsedMessage.count);
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingFromKey], stanza.from);
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingCollapseKey], stanza.token);
+ XCTAssertEqualObjects(parsedMessage[kFIRMessagingMessageIDKey], kMessagePersistentID);
+ XCTAssertEqualObjects(parsedMessage[kAppDataItemKey], kAppDataItemValue);
+ XCTAssertTrue([parsedMessage[kFIRMessagingMessageSyncViaMCSKey] boolValue]);
+}
+
+- (void)testReceivingParsedMessage {
+ NSDictionary *message = @{ @"hello" : @"world" };
+ OCMStub([self.mockReceiver didReceiveMessage:[OCMArg isEqual:message] withIdentifier:[OCMArg any]]);
+ [self.dataMessageManager didReceiveParsedMessage:message];
+ OCMVerify([self.mockReceiver didReceiveMessage:message withIdentifier:[OCMArg any]]);
+}
+
+/**
+ * Test receiving a new duplex message notifies the receiver callback.
+ */
+- (void)testReceivingNewDuplexMessage {
+ GtalkDataMessageStanza *message = [self validDuplexmessage];
+ NSDictionary *parsedMessage = [self.dataMessageManager processPacket:message];
+ [[[self.mockSyncMessageManager stub] andReturnValue:@(NO)]
+ didReceiveMCSSyncMessage:parsedMessage];
+ OCMStub([self.mockReceiver didReceiveMessage:[OCMArg isEqual:message] withIdentifier:[OCMArg any]]);
+ [self.dataMessageManager didReceiveParsedMessage:parsedMessage];
+ OCMVerify([self.mockReceiver didReceiveMessage:[OCMArg any] withIdentifier:[OCMArg any]]);
+}
+
+/**
+ * Test receiving a duplicated duplex message does not notify the receiver callback.
+ */
+- (void)testReceivingDuplicateDuplexMessage {
+ GtalkDataMessageStanza *message = [self validDuplexmessage];
+ NSDictionary *parsedMessage = [self.dataMessageManager processPacket:message];
+ [[[self.mockSyncMessageManager stub] andReturnValue:@(YES)]
+ didReceiveMCSSyncMessage:parsedMessage];
+ [[self.mockReceiver reject] didReceiveMessage:[OCMArg any] withIdentifier:[OCMArg any]];
+ [self.dataMessageManager didReceiveParsedMessage:parsedMessage];
+}
+
+/**
+ * In this test we simulate a real RMQ manager and send messages simulating no
+ * active connection. Then we simulate a new connection being established and
+ * the client receives a Streaming ACK which should result in resending RMQ messages.
+ */
+- (void)testResendSavedMessages {
+ static BOOL isClientConnected = NO;
+ [[[self.mockClient stub] andDo:^(NSInvocation *invocation) {
+ [invocation setReturnValue:&isClientConnected];
+ }] isConnectionActive];
+
+ // Set a fake, valid bundle identifier
+ [[[self.mockDataMessageManager stub] andReturn:@"gcm-dmm-test"] categoryForUpstreamMessages];
+
+ [FIRMessagingRmqManager removeDatabaseWithName:kRmqDatabaseName];
+ FIRMessagingRmqManager *newRmqManager =
+ [[FIRMessagingRmqManager alloc] initWithDatabaseName:kRmqDatabaseName];
+ [newRmqManager loadRmqId];
+ // have a real RMQ store
+ [self.dataMessageManager setRmq2Manager:newRmqManager];
+
+ [self addFakeFIRMessagingRegistrationToken];
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+
+ // send a couple of message with no connection should be saved to RMQ
+ [self.dataMessageManager sendDataMessageStanza:
+ [self upstreamMessageWithID:@"1" ttl:20000 delay:0]];
+ [self.dataMessageManager sendDataMessageStanza:
+ [self upstreamMessageWithID:@"2" ttl:20000 delay:0]];
+
+ [NSThread sleepForTimeInterval:1.0];
+ isClientConnected = YES;
+ // after the usual version, login assertion we would receive a SelectiveAck
+ // assuming we we weren't able to send any messages we won't delete anything
+ // from the RMQ but try to resend whatever is there
+ __block int didRecieveMessages = 0;
+ id mockConnection = OCMClassMock([FIRMessagingConnection class]);
+
+ BOOL (^resendMessageBlock)(id obj) = ^BOOL(id obj) {
+ if ([obj isKindOfClass:[GtalkDataMessageStanza class]]) {
+ GtalkDataMessageStanza *message = (GtalkDataMessageStanza *)obj;
+ NSLog(@"hello resending %@, %d", message.id_p, didRecieveMessages);
+ if ([@"1" isEqualToString:message.id_p]) {
+ didRecieveMessages |= 1; // right most bit for 1st message
+ return YES;
+ } else if ([@"2" isEqualToString:message.id_p]) {
+ didRecieveMessages |= (1<<1); // second from RMB for 2nd message
+ return YES;
+ }
+ }
+ return NO;
+ };
+ [[[mockConnection stub] andDo:^(NSInvocation *invocation) {
+ // pass
+ }] sendProto:[OCMArg checkWithBlock:resendMessageBlock]];
+
+ [self.dataMessageManager resendMessagesWithConnection:mockConnection];
+
+ // should send both messages
+ XCTAssert(didRecieveMessages == 3);
+ OCMVerifyAll(mockConnection);
+}
+
+- (void)testResendingExpiredMessagesFails {
+ // TODO: Test that expired messages should not be sent on resend
+ static BOOL isClientConnected = NO;
+ [[[self.mockClient stub] andDo:^(NSInvocation *invocation) {
+ [invocation setReturnValue:&isClientConnected];
+ }] isConnectionActive];
+
+ // Set a fake, valid bundle identifier
+ [[[self.mockDataMessageManager stub] andReturn:@"gcm-dmm-test"] categoryForUpstreamMessages];
+
+ [FIRMessagingRmqManager removeDatabaseWithName:kRmqDatabaseName];
+ FIRMessagingRmqManager *newRmqManager =
+ [[FIRMessagingRmqManager alloc] initWithDatabaseName:kRmqDatabaseName];
+ [newRmqManager loadRmqId];
+ // have a real RMQ store
+ [self.dataMessageManager setRmq2Manager:newRmqManager];
+
+ [self.dataMessageManager setDeviceAuthID:@"auth-id" secretToken:@"secret-token"];
+ // send a message that expires in 1 sec
+ [self.dataMessageManager sendDataMessageStanza:
+ [self upstreamMessageWithID:@"1" ttl:1 delay:0]];
+
+ // wait for 2 seconds (let the above message expire)
+ [NSThread sleepForTimeInterval:2.0];
+ isClientConnected = YES;
+
+ id mockConnection = OCMClassMock([FIRMessagingConnection class]);
+
+ [[mockConnection reject] sendProto:[OCMArg any]];
+ [self.dataMessageManager resendMessagesWithConnection:mockConnection];
+
+ // rmq should not have any pending messages
+ [newRmqManager scanWithRmqMessageHandler:^(int64_t rmqId, int8_t tag, NSData *data) {
+ XCTFail(@"RMQ should not have any message");
+ }
+ dataMessageHandler:nil];
+}
+
+#pragma mark - Private
+
+- (void)addFakeFIRMessagingRegistrationToken {
+ // [[FIRMessagingDefaultsManager sharedInstance] saveAppIDToken:kFIRMessagingAppIDToken];
+}
+
+#pragma mark - Create Packet
+
+- (GtalkDataMessageStanza *)validDataMessagePacket {
+ GtalkDataMessageStanza *message = [[GtalkDataMessageStanza alloc] init];
+ message.from = kMessageFrom;
+ message.token = kCollapseKey;
+ message.persistentId = kMessagePersistentID;
+ GtalkAppData *item = [[GtalkAppData alloc] init];
+ item.key = kAppDataItemKey;
+ item.value = kAppDataItemValue;
+ message.appDataArray = [NSMutableArray arrayWithObject:item];
+ return message;
+}
+
+- (GtalkDataMessageStanza *)validDataMessageWithOnlyFrom {
+ GtalkDataMessageStanza *message = [[GtalkDataMessageStanza alloc] init];
+ message.from = kMessageFrom;
+ message.persistentId = kMessagePersistentID;
+ return message;
+}
+
+- (GtalkDataMessageStanza *)invalidDataMessageUsingReservedKeyword {
+ GtalkDataMessageStanza *message = [[GtalkDataMessageStanza alloc] init];
+ message.from = kMessageFrom;
+ message.persistentId = kMessagePersistentID;
+ GtalkAppData *item = [[GtalkAppData alloc] init];
+ item.key = kAppDataItemInvalidKey;
+ item.value = kAppDataItemValue;
+ message.appDataArray = [NSMutableArray arrayWithObject:item];
+ return message;
+}
+
+- (GtalkDataMessageStanza *)validDataMessageForFIRMessaging {
+ GtalkDataMessageStanza *message = [[GtalkDataMessageStanza alloc] init];
+ message.from = kMessageFrom;
+ message.token = @"com.google.gcm";
+ return message;
+}
+
+- (GtalkDataMessageStanza *)validDuplexmessage {
+ GtalkDataMessageStanza *message = [[GtalkDataMessageStanza alloc] init];
+ message.from = kMessageFrom;
+ message.token = kCollapseKey;
+ message.persistentId = kMessagePersistentID;
+ GtalkAppData *item = [[GtalkAppData alloc] init];
+ item.key = kAppDataItemKey;
+ item.value = kAppDataItemValue;
+ GtalkAppData *duplexItem = [[GtalkAppData alloc] init];
+ duplexItem.key = @"gcm.duplex";
+ duplexItem.value = @"1";
+ message.appDataArray = [NSMutableArray arrayWithObjects:item, duplexItem, nil];
+ return message;
+}
+
+#pragma mark - Create Message
+
+- (NSMutableDictionary *)standardFIRMessagingMessageWithMessageID:(NSString *)messageID {
+ NSDictionary *message = @{ kAppDataItemKey : kAppDataItemValue };
+ return [FIRMessaging createFIRMessagingMessageWithMessage:message
+ to:kMessageTo
+ withID:messageID
+ timeToLive:-1
+ delay:0];
+}
+
+- (NSMutableDictionary *)upstreamMessageWithID:(NSString *)messageID
+ ttl:(int64_t)ttl
+ delay:(int)delay {
+ NSDictionary *message = @{ kAppDataItemInvalidKey : kAppDataItemValue };
+ return [FIRMessaging createFIRMessagingMessageWithMessage:message
+ to:kMessageTo
+ withID:messageID
+ timeToLive:ttl
+ delay:delay];
+}
+
+@end