Skip to content

Commit 5c26ae4

Browse files
Always call getToken before subscription/unsubscription (#3438)
1 parent 3ce13dc commit 5c26ae4

File tree

3 files changed

+132
-36
lines changed

3 files changed

+132
-36
lines changed

Example/Messaging/Tests/FIRMessagingServiceTest.m

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#import <XCTest/XCTest.h>
1818
#import <OCMock/OCMock.h>
1919

20+
#import <FirebaseInstanceID/FirebaseInstanceID.h>
21+
2022
#import "FIRMessaging.h"
2123
#import "FIRMessagingClient.h"
2224
#import "FIRMessagingPubSub.h"
@@ -29,13 +31,15 @@
2931
@"fE1e1PZJFSQ:APA91bFAOjp1ahBWn9rTlbjArwBEm_"
3032
@"yUTTzK6dhIvLqzqqCSabaa4TQVM0pGTmF6r7tmMHPe6VYiGMHuCwJFgj5v97xl78sUNMLwuPPhoci8z_"
3133
@"QGlCrTbxCFGzEUfvA3fGpGgIVQU2W6";
34+
static NSString *const kFakeID = @"fE1e1PZJFSQ";
3235

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

3538
@interface FIRMessaging () <FIRMessagingClientDelegate>
3639
@property(nonatomic, readwrite, strong) FIRMessagingClient *client;
3740
@property(nonatomic, readwrite, strong) FIRMessagingPubSub *pubsub;
3841
@property(nonatomic, readwrite, strong) NSString *defaultFcmToken;
42+
@property(nonatomic, readwrite, strong) FIRInstanceID *instanceID;
3943

4044
@end
4145

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

4650
@end
4751

52+
@interface FIRInstanceIDResult (ExposedForTest)
53+
@property(nonatomic, readwrite, copy) NSString *instanceID;
54+
@property(nonatomic, readwrite, copy) NSString *token;
55+
@end
56+
4857
@interface FIRMessagingServiceTest : XCTestCase {
4958
FIRMessaging *_messaging;
59+
FIRInstanceIDResult *_result;
60+
id _mockInstanceID;
5061
id _mockPubSub;
5162
}
5263

@@ -55,18 +66,24 @@ @interface FIRMessagingServiceTest : XCTestCase {
5566
@implementation FIRMessagingServiceTest
5667

5768
- (void)setUp {
69+
[super setUp];
5870
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingTestsServiceSuiteName];
5971
_messaging = [FIRMessagingTestUtilities messagingForTestsWithUserDefaults:defaults];
6072
_messaging.defaultFcmToken = kFakeToken;
6173
_mockPubSub = OCMPartialMock(_messaging.pubsub);
6274
[_mockPubSub setClient:nil];
63-
[super setUp];
75+
76+
_mockInstanceID = OCMPartialMock(_messaging.instanceID);
77+
_result = [[FIRInstanceIDResult alloc] init];
78+
_result.token = kFakeToken;
79+
_result.instanceID = kFakeID;
6480
}
6581

6682
- (void)tearDown {
83+
[_mockInstanceID stopMocking];
84+
[_mockPubSub stopMocking];
6785
[_messaging.messagingUserDefaults removePersistentDomainForName:kFIRMessagingTestsServiceSuiteName];
6886
_messaging = nil;
69-
[_mockPubSub stopMocking];
7087
[super tearDown];
7188
}
7289

@@ -211,7 +228,8 @@ - (void)testUnsubscribeWithInvalidTopic {
211228
}
212229

213230
- (void)testSubscribeWithNoTopicPrefix {
214-
231+
OCMStub([_mockInstanceID
232+
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
215233
NSString *topicName = @"topicWithoutPrefix";
216234
NSString *topicNameWithPrefix = [FIRMessagingPubSub addPrefixToTopic:topicName];
217235
OCMExpect(
@@ -221,13 +239,17 @@ - (void)testSubscribeWithNoTopicPrefix {
221239
}
222240

223241
- (void)testSubscribeWithTopicPrefix {
242+
OCMStub([_mockInstanceID
243+
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
224244
NSString *topicName = @"/topics/topicWithoutPrefix";
225245
OCMExpect([_mockPubSub subscribeToTopic:[OCMArg isEqual:topicName] handler:[OCMArg any]]);
226246
[_messaging subscribeToTopic:topicName];
227247
OCMVerifyAll(_mockPubSub);
228248
}
229249

230250
- (void)testUnsubscribeWithNoTopicPrefix {
251+
OCMStub([_mockInstanceID
252+
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
231253
NSString *topicName = @"topicWithoutPrefix";
232254
NSString *topicNameWithPrefix = [FIRMessagingPubSub addPrefixToTopic:topicName];
233255
OCMExpect(
@@ -237,13 +259,17 @@ - (void)testUnsubscribeWithNoTopicPrefix {
237259
}
238260

239261
- (void)testUnsubscribeWithTopicPrefix {
262+
OCMStub([_mockInstanceID
263+
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
240264
NSString *topicName = @"/topics/topicWithPrefix";
241265
OCMExpect([_mockPubSub unsubscribeFromTopic:[OCMArg isEqual:topicName] handler:[OCMArg any]]);
242266
[_messaging unsubscribeFromTopic:topicName];
243267
OCMVerifyAll(_mockPubSub);
244268
}
245269

246270
- (void)testSubscriptionCompletionHandlerWithSuccess {
271+
OCMStub([_mockInstanceID
272+
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
247273
OCMStub([_mockPubSub subscribeToTopic:[OCMArg any]
248274
handler:([OCMArg invokeBlockWithArgs:[NSNull null], nil])]);
249275
XCTestExpectation *subscriptionCompletionExpectation =
@@ -259,6 +285,8 @@ - (void)testSubscriptionCompletionHandlerWithSuccess {
259285
}
260286

261287
- (void)testUnsubscribeCompletionHandlerWithSuccess {
288+
OCMStub([_mockInstanceID
289+
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
262290
OCMStub([_mockPubSub unsubscribeFromTopic:[OCMArg any]
263291
handler:([OCMArg invokeBlockWithArgs:[NSNull null], nil])]);
264292
XCTestExpectation *unsubscriptionCompletionExpectation =
@@ -274,6 +302,8 @@ - (void)testUnsubscribeCompletionHandlerWithSuccess {
274302
}
275303

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

290320
- (void)testUnsubscribeCompletionHandlerWithInvalidTopicName {
321+
OCMStub([_mockInstanceID
322+
instanceIDWithHandler:([OCMArg invokeBlockWithArgs:_result, [NSNull null], nil])]);
291323
XCTestExpectation *unsubscriptionCompletionExpectation =
292324
[self expectationWithDescription:@"Unsubscription is complete"];
293325
[_messaging unsubscribeFromTopic:@"!@#$%^&*()"
@@ -336,4 +368,42 @@ - (void)testFIRMessagingSDKLocaleInFIRMessagingService {
336368
}
337369
}
338370

371+
372+
- (void)testSubscribeFailedWithInvalidToken {
373+
// Mock get token is failed with FIRMessagingErrorUnknown error.
374+
XCTestExpectation *subscriptionCompletionExpectation =
375+
[self expectationWithDescription:@"Subscription is complete"];
376+
OCMStub([_mockInstanceID
377+
instanceIDWithHandler:
378+
([OCMArg
379+
invokeBlockWithArgs:[NSNull null],
380+
[NSError errorWithFCMErrorCode:kFIRMessagingErrorCodeUnknown],
381+
nil])]);
382+
[_messaging subscribeToTopic:@"Apple"
383+
completion:^(NSError *_Nullable error) {
384+
XCTAssertNotNil(error);
385+
XCTAssertEqual(error.code, kFIRMessagingErrorCodeUnknown);
386+
[subscriptionCompletionExpectation fulfill];
387+
}];
388+
[self waitForExpectationsWithTimeout:0.2 handler:nil];
389+
}
390+
391+
- (void)testUnsubscribeFailedWithInvalidToken {
392+
OCMStub([_mockInstanceID
393+
instanceIDWithHandler:
394+
([OCMArg
395+
invokeBlockWithArgs:[NSNull null],
396+
[NSError errorWithFCMErrorCode:kFIRMessagingErrorCodeUnknown],
397+
nil])]);
398+
XCTestExpectation *unsubscriptionCompletionExpectation =
399+
[self expectationWithDescription:@"Unsubscription is complete"];
400+
401+
[_messaging unsubscribeFromTopic:@"news"
402+
completion:^(NSError *_Nullable error) {
403+
XCTAssertNotNil(error);
404+
XCTAssertEqual(error.code, kFIRMessagingErrorCodeUnknown);
405+
[unsubscriptionCompletionExpectation fulfill];
406+
}];
407+
[self waitForExpectationsWithTimeout:0.2 handler:nil];
408+
}
339409
@end

Firebase/Messaging/FIRMessaging.m

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -756,21 +756,30 @@ - (void)subscribeToTopic:(NSString *)topic
756756
@"subscribeToTopic.",
757757
topic, [FIRMessagingPubSub removePrefixFromTopic:topic]);
758758
}
759-
if (!self.defaultFcmToken.length) {
760-
FIRMessagingLoggerWarn(kFIRMessagingMessageCodeMessaging010,
761-
@"The subscription operation is suspended because you don't have a "
762-
@"token. The operation will resume once you get an FCM token.");
763-
}
764-
NSString *normalizeTopic = [[self class] normalizeTopic:topic];
765-
if (normalizeTopic.length) {
766-
[self.pubsub subscribeToTopic:normalizeTopic handler:completion];
767-
return;
768-
}
769-
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging009,
759+
__weak FIRMessaging *weakSelf = self;
760+
[self.instanceID instanceIDWithHandler:^(FIRInstanceIDResult *_Nullable result,
761+
NSError *_Nullable error) {
762+
if (error) {
763+
FIRMessagingLoggerError(
764+
kFIRMessagingMessageCodeMessaging010,
765+
@"The subscription operation failed due to an error getting the FCM token: %@.", error);
766+
if (completion) {
767+
completion(error);
768+
}
769+
return;
770+
}
771+
FIRMessaging *strongSelf = weakSelf;
772+
NSString *normalizeTopic = [[strongSelf class] normalizeTopic:topic];
773+
if (normalizeTopic.length) {
774+
[strongSelf.pubsub subscribeToTopic:normalizeTopic handler:completion];
775+
return;
776+
}
777+
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging009,
770778
@"Cannot parse topic name %@. Will not subscribe.", topic);
771-
if (completion) {
772-
completion([NSError fcm_errorWithCode:FIRMessagingErrorInvalidTopicName userInfo:nil]);
773-
}
779+
if (completion) {
780+
completion([NSError fcm_errorWithCode:FIRMessagingErrorInvalidTopicName userInfo:nil]);
781+
}
782+
}];
774783
}
775784

776785
- (void)unsubscribeFromTopic:(NSString *)topic {
@@ -785,21 +794,30 @@ - (void)unsubscribeFromTopic:(NSString *)topic
785794
@"unsubscribeFromTopic.",
786795
topic, [FIRMessagingPubSub removePrefixFromTopic:topic]);
787796
}
788-
if (!self.defaultFcmToken.length) {
789-
FIRMessagingLoggerWarn(kFIRMessagingMessageCodeMessaging012,
790-
@"The unsubscription operation is suspended because you don't have a "
791-
@"token. The operation will resume once you get an FCM token.");
792-
}
793-
NSString *normalizeTopic = [[self class] normalizeTopic:topic];
794-
if (normalizeTopic.length) {
795-
[self.pubsub unsubscribeFromTopic:normalizeTopic handler:completion];
796-
return;
797-
}
798-
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging011,
799-
@"Cannot parse topic name %@. Will not unsubscribe.", topic);
800-
if (completion) {
801-
completion([NSError fcm_errorWithCode:FIRMessagingErrorInvalidTopicName userInfo:nil]);
802-
}
797+
__weak FIRMessaging *weakSelf = self;
798+
[self.instanceID instanceIDWithHandler:^(FIRInstanceIDResult *_Nullable result,
799+
NSError *_Nullable error) {
800+
if (error) {
801+
FIRMessagingLoggerError(
802+
kFIRMessagingMessageCodeMessaging012,
803+
@"The unsubscription operation failed due to an error getting the FCM token: %@.", error);
804+
if (completion) {
805+
completion(error);
806+
}
807+
return;
808+
}
809+
FIRMessaging *strongSelf = weakSelf;
810+
NSString *normalizeTopic = [[strongSelf class] normalizeTopic:topic];
811+
if (normalizeTopic.length) {
812+
[strongSelf.pubsub unsubscribeFromTopic:normalizeTopic handler:completion];
813+
return;
814+
}
815+
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging011,
816+
@"Cannot parse topic name %@. Will not unsubscribe.", topic);
817+
if (completion) {
818+
completion([NSError fcm_errorWithCode:FIRMessagingErrorInvalidTopicName userInfo:nil]);
819+
}
820+
}];
803821
}
804822

805823
#pragma mark - Send

Firebase/Messaging/Public/FIRMessaging.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,14 +413,18 @@ NS_SWIFT_NAME(Messaging)
413413
#pragma mark - Topics
414414

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

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

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

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

0 commit comments

Comments
 (0)