Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 73 additions & 3 deletions Example/Messaging/Tests/FIRMessagingServiceTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>

#import <FirebaseInstanceID/FirebaseInstanceID.h>

#import "FIRMessaging.h"
#import "FIRMessagingClient.h"
#import "FIRMessagingPubSub.h"
Expand All @@ -29,13 +31,15 @@
@"fE1e1PZJFSQ:APA91bFAOjp1ahBWn9rTlbjArwBEm_"
@"yUTTzK6dhIvLqzqqCSabaa4TQVM0pGTmF6r7tmMHPe6VYiGMHuCwJFgj5v97xl78sUNMLwuPPhoci8z_"
@"QGlCrTbxCFGzEUfvA3fGpGgIVQU2W6";
static NSString *const kFakeID = @"fE1e1PZJFSQ";

NSString *const kFIRMessagingTestsServiceSuiteName = @"com.messaging.test_serviceTest";

@interface FIRMessaging () <FIRMessagingClientDelegate>
@property(nonatomic, readwrite, strong) FIRMessagingClient *client;
@property(nonatomic, readwrite, strong) FIRMessagingPubSub *pubsub;
@property(nonatomic, readwrite, strong) NSString *defaultFcmToken;
@property(nonatomic, readwrite, strong) FIRInstanceID *instanceID;

@end

Expand All @@ -45,8 +49,15 @@ @interface FIRMessagingPubSub ()

@end

@interface FIRInstanceIDResult (ExposedForTest)
@property(nonatomic, readwrite, copy) NSString *instanceID;
@property(nonatomic, readwrite, copy) NSString *token;
@end

@interface FIRMessagingServiceTest : XCTestCase {
FIRMessaging *_messaging;
FIRInstanceIDResult *_result;
id _mockInstanceID;
id _mockPubSub;
}

Expand All @@ -55,18 +66,24 @@ @interface FIRMessagingServiceTest : XCTestCase {
@implementation FIRMessagingServiceTest

- (void)setUp {
[super setUp];
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingTestsServiceSuiteName];
_messaging = [FIRMessagingTestUtilities messagingForTestsWithUserDefaults:defaults];
_messaging.defaultFcmToken = kFakeToken;
_mockPubSub = OCMPartialMock(_messaging.pubsub);
[_mockPubSub setClient:nil];
[super setUp];

_mockInstanceID = OCMPartialMock(_messaging.instanceID);
_result = [[FIRInstanceIDResult alloc] init];
_result.token = kFakeToken;
_result.instanceID = kFakeID;
}

- (void)tearDown {
[_mockInstanceID stopMocking];
[_mockPubSub stopMocking];
[_messaging.messagingUserDefaults removePersistentDomainForName:kFIRMessagingTestsServiceSuiteName];
_messaging = nil;
[_mockPubSub stopMocking];
[super tearDown];
}

Expand Down Expand Up @@ -211,7 +228,8 @@ - (void)testUnsubscribeWithInvalidTopic {
}

- (void)testSubscribeWithNoTopicPrefix {

OCMStub([_mockInstanceID
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
NSString *topicName = @"topicWithoutPrefix";
NSString *topicNameWithPrefix = [FIRMessagingPubSub addPrefixToTopic:topicName];
OCMExpect(
Expand All @@ -221,13 +239,17 @@ - (void)testSubscribeWithNoTopicPrefix {
}

- (void)testSubscribeWithTopicPrefix {
OCMStub([_mockInstanceID
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
NSString *topicName = @"/topics/topicWithoutPrefix";
OCMExpect([_mockPubSub subscribeToTopic:[OCMArg isEqual:topicName] handler:[OCMArg any]]);
[_messaging subscribeToTopic:topicName];
OCMVerifyAll(_mockPubSub);
}

- (void)testUnsubscribeWithNoTopicPrefix {
OCMStub([_mockInstanceID
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
NSString *topicName = @"topicWithoutPrefix";
NSString *topicNameWithPrefix = [FIRMessagingPubSub addPrefixToTopic:topicName];
OCMExpect(
Expand All @@ -237,13 +259,17 @@ - (void)testUnsubscribeWithNoTopicPrefix {
}

- (void)testUnsubscribeWithTopicPrefix {
OCMStub([_mockInstanceID
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
NSString *topicName = @"/topics/topicWithPrefix";
OCMExpect([_mockPubSub unsubscribeFromTopic:[OCMArg isEqual:topicName] handler:[OCMArg any]]);
[_messaging unsubscribeFromTopic:topicName];
OCMVerifyAll(_mockPubSub);
}

- (void)testSubscriptionCompletionHandlerWithSuccess {
OCMStub([_mockInstanceID
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
OCMStub([_mockPubSub subscribeToTopic:[OCMArg any]
handler:([OCMArg invokeBlockWithArgs:[NSNull null], nil])]);
XCTestExpectation *subscriptionCompletionExpectation =
Expand All @@ -259,6 +285,8 @@ - (void)testSubscriptionCompletionHandlerWithSuccess {
}

- (void)testUnsubscribeCompletionHandlerWithSuccess {
OCMStub([_mockInstanceID
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
OCMStub([_mockPubSub unsubscribeFromTopic:[OCMArg any]
handler:([OCMArg invokeBlockWithArgs:[NSNull null], nil])]);
XCTestExpectation *unsubscriptionCompletionExpectation =
Expand All @@ -274,6 +302,8 @@ - (void)testUnsubscribeCompletionHandlerWithSuccess {
}

- (void)testSubscriptionCompletionHandlerWithInvalidTopicName {
OCMStub([_mockInstanceID
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
XCTestExpectation *subscriptionCompletionExpectation =
[self expectationWithDescription:@"Subscription is complete"];
[_messaging subscribeToTopic:@"!@#$%^&*()"
Expand All @@ -288,6 +318,8 @@ - (void)testSubscriptionCompletionHandlerWithInvalidTopicName {
}

- (void)testUnsubscribeCompletionHandlerWithInvalidTopicName {
OCMStub([_mockInstanceID
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
XCTestExpectation *unsubscriptionCompletionExpectation =
[self expectationWithDescription:@"Unsubscription is complete"];
[_messaging unsubscribeFromTopic:@"!@#$%^&*()"
Expand Down Expand Up @@ -336,4 +368,42 @@ - (void)testFIRMessagingSDKLocaleInFIRMessagingService {
}
}


- (void)testSubscribeFailedWithInvalidToken {
// Mock get token is failed with FIRMessagingErrorUnknown error.
XCTestExpectation *subscriptionCompletionExpectation =
[self expectationWithDescription:@"Subscription is complete"];
OCMStub([_mockInstanceID
instanceIDWithHandler:
([OCMArg
invokeBlockWithArgs:[NSNull null],
[NSError errorWithFCMErrorCode:kFIRMessagingErrorCodeUnknown],
nil])]);
[_messaging subscribeToTopic:@"Apple"
completion:^(NSError *_Nullable error) {
XCTAssertNotNil(error);
XCTAssertEqual(error.code, kFIRMessagingErrorCodeUnknown);
[subscriptionCompletionExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:0.2 handler:nil];
}

- (void)testUnsubscribeFailedWithInvalidToken {
OCMStub([_mockInstanceID
instanceIDWithHandler:
([OCMArg
invokeBlockWithArgs:[NSNull null],
[NSError errorWithFCMErrorCode:kFIRMessagingErrorCodeUnknown],
nil])]);
XCTestExpectation *unsubscriptionCompletionExpectation =
[self expectationWithDescription:@"Unsubscription is complete"];

[_messaging unsubscribeFromTopic:@"news"
completion:^(NSError *_Nullable error) {
XCTAssertNotNil(error);
XCTAssertEqual(error.code, kFIRMessagingErrorCodeUnknown);
[unsubscriptionCompletionExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:0.2 handler:nil];
}
@end
76 changes: 47 additions & 29 deletions Firebase/Messaging/FIRMessaging.m
Original file line number Diff line number Diff line change
Expand Up @@ -756,21 +756,30 @@ - (void)subscribeToTopic:(NSString *)topic
@"subscribeToTopic.",
topic, [FIRMessagingPubSub removePrefixFromTopic:topic]);
}
if (!self.defaultFcmToken.length) {
FIRMessagingLoggerWarn(kFIRMessagingMessageCodeMessaging010,
@"The subscription operation is suspended because you don't have a "
@"token. The operation will resume once you get an FCM token.");
}
NSString *normalizeTopic = [[self class] normalizeTopic:topic];
if (normalizeTopic.length) {
[self.pubsub subscribeToTopic:normalizeTopic handler:completion];
return;
}
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging009,
__weak FIRMessaging *weakSelf = self;
[self.instanceID instanceIDWithHandler:^(FIRInstanceIDResult *_Nullable result,
NSError *_Nullable error) {
if (error) {
FIRMessagingLoggerError(
kFIRMessagingMessageCodeMessaging010,
@"The subscription operation failed due to an error getting the FCM token: %@.", error);
if (completion) {
completion(error);
}
return;
}
FIRMessaging *strongSelf = weakSelf;
NSString *normalizeTopic = [[strongSelf class] normalizeTopic:topic];
if (normalizeTopic.length) {
[strongSelf.pubsub subscribeToTopic:normalizeTopic handler:completion];
return;
}
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging009,
@"Cannot parse topic name %@. Will not subscribe.", topic);
if (completion) {
completion([NSError fcm_errorWithCode:FIRMessagingErrorInvalidTopicName userInfo:nil]);
}
if (completion) {
completion([NSError fcm_errorWithCode:FIRMessagingErrorInvalidTopicName userInfo:nil]);
}
}];
}

- (void)unsubscribeFromTopic:(NSString *)topic {
Expand All @@ -785,21 +794,30 @@ - (void)unsubscribeFromTopic:(NSString *)topic
@"unsubscribeFromTopic.",
topic, [FIRMessagingPubSub removePrefixFromTopic:topic]);
}
if (!self.defaultFcmToken.length) {
FIRMessagingLoggerWarn(kFIRMessagingMessageCodeMessaging012,
@"The unsubscription operation is suspended because you don't have a "
@"token. The operation will resume once you get an FCM token.");
}
NSString *normalizeTopic = [[self class] normalizeTopic:topic];
if (normalizeTopic.length) {
[self.pubsub unsubscribeFromTopic:normalizeTopic handler:completion];
return;
}
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging011,
@"Cannot parse topic name %@. Will not unsubscribe.", topic);
if (completion) {
completion([NSError fcm_errorWithCode:FIRMessagingErrorInvalidTopicName userInfo:nil]);
}
__weak FIRMessaging *weakSelf = self;
[self.instanceID instanceIDWithHandler:^(FIRInstanceIDResult *_Nullable result,
NSError *_Nullable error) {
if (error) {
FIRMessagingLoggerError(
kFIRMessagingMessageCodeMessaging012,
@"The unsubscription operation failed due to an error getting the FCM token: %@.", error);
if (completion) {
completion(error);
}
return;
}
FIRMessaging *strongSelf = weakSelf;
NSString *normalizeTopic = [[strongSelf class] normalizeTopic:topic];
if (normalizeTopic.length) {
[strongSelf.pubsub unsubscribeFromTopic:normalizeTopic handler:completion];
return;
}
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging011,
@"Cannot parse topic name %@. Will not unsubscribe.", topic);
if (completion) {
completion([NSError fcm_errorWithCode:FIRMessagingErrorInvalidTopicName userInfo:nil]);
}
}];
}

#pragma mark - Send
Expand Down
16 changes: 12 additions & 4 deletions Firebase/Messaging/Public/FIRMessaging.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,14 +413,18 @@ NS_SWIFT_NAME(Messaging)
#pragma mark - Topics

/**
* Asynchronously subscribes to a topic.
* Asynchronously subscribes to a topic. This uses a FCM Token to identify
* the app instance and periodically sends data to the Firebase backend. To stop this, see
* `[FIRInstanceID deleteIDWithHandler:]`.
*
* @param topic The name of the topic, for example, @"sports".
*/
- (void)subscribeToTopic:(NSString *)topic NS_SWIFT_NAME(subscribe(toTopic:));

/**
* Asynchronously subscribe to the provided topic, retrying on failure.
* Asynchronously subscribe to the provided topic, retrying on failure. This uses a FCM Token
* to identify the app instance and periodically sends data to the Firebase backend. To stop this,
* see `[FIRInstanceID deleteIDWithHandler:]`.
*
* @param topic The topic name to subscribe to, for example, @"sports".
* @param completion The completion that is invoked once the subscribe call ends.
Expand All @@ -431,14 +435,18 @@ NS_SWIFT_NAME(Messaging)
completion:(nullable FIRMessagingTopicOperationCompletion)completion;

/**
* Asynchronously unsubscribe from a topic.
* Asynchronously unsubscribe from a topic. This uses a FCM Token
* to identify the app instance and periodically sends data to the Firebase backend. To stop this,
* see `[FIRInstanceID deleteIDWithHandler:]`.
*
* @param topic The name of the topic, for example @"sports".
*/
- (void)unsubscribeFromTopic:(NSString *)topic NS_SWIFT_NAME(unsubscribe(fromTopic:));

/**
* Asynchronously unsubscribe from the provided topic, retrying on failure.
* Asynchronously unsubscribe from the provided topic, retrying on failure. This uses a FCM Token
* to identify the app instance and periodically sends data to the Firebase backend. To stop this,
* see `[FIRInstanceID deleteIDWithHandler:]`.
*
* @param topic The topic name to unsubscribe from, for example @"sports".
* @param completion The completion that is invoked once the unsubscribe call ends.
Expand Down