diff --git a/PubNub/Data/Managers/PNSubscriber.m b/PubNub/Data/Managers/PNSubscriber.m index 63527cbae..69359d11e 100644 --- a/PubNub/Data/Managers/PNSubscriber.m +++ b/PubNub/Data/Managers/PNSubscriber.m @@ -1330,7 +1330,8 @@ - (void)handleFailedSubscriptionStatus:(PNSubscribeStatus *)status { statusCategory == PNTLSConnectionFailedCategory) { __weak __typeof(self) weakSelf = self; - ((PNStatus *)status).automaticallyRetry = (statusCategory != PNMalformedFilterExpressionCategory && + ((PNStatus *)status).automaticallyRetry = (statusCategory != PNAccessDeniedCategory && + statusCategory != PNMalformedFilterExpressionCategory && statusCategory != PNRequestURITooLongCategory); PNSubscriberState subscriberState = PNAccessRightsErrorSubscriberState; ((PNStatus *)status).retryCancelBlock = ^{ diff --git a/Tests/Tests/Contract/Steps/Subscribe/PNSubscribeContractTestSteps.m b/Tests/Tests/Contract/Steps/Subscribe/PNSubscribeContractTestSteps.m index 7aec371f5..eb850cf62 100644 --- a/Tests/Tests/Contract/Steps/Subscribe/PNSubscribeContractTestSteps.m +++ b/Tests/Tests/Contract/Steps/Subscribe/PNSubscribeContractTestSteps.m @@ -15,14 +15,6 @@ @implementation PNSubscribeContractTestSteps - (void)setup { [self startCucumberHookEventsListening]; - Given(@"the crypto keyset", ^(NSArray *args, NSDictionary *userInfo) { - self.configuration.cipherKey = @"enigma"; - }); - - Given(@"the invalid-crypto keyset", ^(NSArray *args, NSDictionary *userInfo) { - self.configuration.cipherKey = @"secret"; - }); - When(@"I subscribe", ^(NSArray *args, NSDictionary *userInfo) { self.testedFeatureType = PNSubscribeOperation; @@ -55,6 +47,12 @@ - (void)setup { [self pauseMainQueueFor:0.5f]; }); + + Match(@[@"*"], @"I don't auto-retry subscribe", ^(NSArray *args, NSDictionary *userInfo) { + self.allowsPendingRequests = YES; + // Delay execution to ensure that there is no automated retry. + [self pauseMainQueueFor:2.f]; + }); } #pragma mark - diff --git a/Tests/Tests/Helpers/PNContractTestCase.h b/Tests/Tests/Helpers/PNContractTestCase.h index d9568dddc..d5495a88f 100644 --- a/Tests/Tests/Helpers/PNContractTestCase.h +++ b/Tests/Tests/Helpers/PNContractTestCase.h @@ -33,6 +33,13 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, assign) PNOperationType testedFeatureType; +/** + * @brief Whether at the end of the test on expectation check it is allowed to have pending requests + * or not. + */ +@property (nonatomic, assign, class) BOOL allowsPendingRequests; +@property (nonatomic, assign) BOOL allowsPendingRequests; + #pragma mark - Initialization & Configuration diff --git a/Tests/Tests/Helpers/PNContractTestCase.m b/Tests/Tests/Helpers/PNContractTestCase.m index 575cd3837..082c94480 100644 --- a/Tests/Tests/Helpers/PNContractTestCase.m +++ b/Tests/Tests/Helpers/PNContractTestCase.m @@ -17,6 +17,8 @@ #pragma mark Types & Constants +static BOOL _allowsPendingRequests = NO; + /** * @brief Origin which should be used to reach mock server for contract testing. */ @@ -159,6 +161,22 @@ @implementation PNContractTestCase #pragma mark - Information ++ (BOOL)allowsPendingRequests { + return _allowsPendingRequests; +} + ++ (void)setAllowsPendingRequests:(BOOL)allowsPendingRequests { + _allowsPendingRequests = allowsPendingRequests; +} + +- (BOOL)allowsPendingRequests { + return [PNContractTestCase class].allowsPendingRequests; +} + +- (void)setAllowsPendingRequests:(BOOL)allowsPendingRequests { + [PNContractTestCase class].allowsPendingRequests = allowsPendingRequests; +} + - (PNConfiguration *)configuration { if (!self.currentConfiguration) { self.currentConfiguration = [PNConfiguration configurationWithPublishKey:kPNDefaultPublishKey @@ -245,8 +263,12 @@ - (void)setup { error:nil]; NSArray *pendingExpectation = [response valueForKeyPath:@"expectations.pending"]; - if (pendingExpectation.count) { - XCTAssertTrue(false, @"Expectations not met: %@", [pendingExpectation componentsJoinedByString:@", "]); + NSArray *failedExpectation = [response valueForKeyPath:@"expectations.failed"]; + if (pendingExpectation.count && !self.allowsPendingRequests) { + XCTAssertTrue(false, @"Expectations not met (pending): %@", [pendingExpectation componentsJoinedByString:@", "]); + } + if (failedExpectation.count) { + XCTAssertTrue(false, @"Expectations not met (failed): %@", [failedExpectation componentsJoinedByString:@", "]); } } @@ -262,6 +284,26 @@ - (void)setup { // Nothing to do. Mock server will simulate proper error here. }); + Given(@"the crypto keyset", ^(NSArray *args, NSDictionary *userInfo) { + self.configuration.cipherKey = @"enigma"; + }); + + Given(@"the invalid-crypto keyset", ^(NSArray *args, NSDictionary *userInfo) { + self.configuration.cipherKey = @"secret"; + }); + + Given(@"auth key", ^(NSArray *args, NSDictionary *userInfo) { + self.configuration.authKey = @"test-auth-key"; + }); + + Given(@"no auth key", ^(NSArray *args, NSDictionary *userInfo) { + // Nothing to do. By default PubNub client doesn't have configured authKey. + }); + + Given(@"token", ^(NSArray *args, NSDictionary *userInfo) { + [self.client setAuthToken:@"my-test-token"]; + }); + Then(@"I receive successful response", ^(NSArray *args, NSDictionary *userInfo) { PNStatus *status = [self lastStatus]; PNResult *result = [self lastResult]; @@ -291,6 +333,24 @@ - (void)setup { } }); + Then(@"I receive access denied status", ^(NSArray *args, NSDictionary *userInfo) { + PNStatus *status = [self lastStatus]; + + XCTAssertNotNil(status, @"Last API call should fail"); + XCTAssertTrue(status.isError, @"Last API call should report error"); + XCTAssertEqual(status.category, PNAccessDeniedCategory); + XCTAssertEqual([self lastStatus].statusCode, 403); + }); + + Match(@[@"*"], @"I receive access denied status", ^(NSArray *args, NSDictionary *userInfo) { + PNStatus *status = [self lastStatus]; + + XCTAssertNotNil(status, @"Last API call should fail"); + XCTAssertTrue(status.isError, @"Last API call should report error"); + XCTAssertEqual(status.category, PNAccessDeniedCategory); + XCTAssertEqual([self lastStatus].statusCode, 403); + }); + // Complete known contract steps configuration. [[PNAccessContractTestSteps new] setup]; [[PNFilesContractTestSteps new] setup]; @@ -317,7 +377,10 @@ - (void)subscribeClient:(PubNub *)client client = client ?: self.client; [_statusHandlers addObject:^void(PubNub *receiver, PNStatus *status) { - if (status.operation == PNSubscribeOperation && status.category == PNConnectedCategory) { + if (status.operation == PNSubscribeOperation && + (status.category == PNConnectedCategory || status.category == PNAccessDeniedCategory)) { + [self storeRequestStatus:status]; + subscribeCompletedInTime = YES; dispatch_semaphore_signal(semaphore); } @@ -379,7 +442,8 @@ - (void)unsubscribeClient:(PubNub *)client NSString *clientIdentifier = receiver.currentConfiguration.uuid; if ([client.currentConfiguration.uuid isEqualToString:clientIdentifier]) { - receivedRequiredCount = messagesCount >= [weakSelf messagesCountForClient:receiver onChannel:channel]; + NSUInteger messagesCountForClient = [weakSelf messagesCountForClient:receiver onChannel:channel]; + receivedRequiredCount = messagesCountForClient > 0 && messagesCount >= messagesCountForClient; } if (receivedRequiredCount) { diff --git a/Tests/Tests/Integration/PNSubscribeIntegrationTest.m b/Tests/Tests/Integration/PNSubscribeIntegrationTest.m index 1329a9541..6cbfc3103 100644 --- a/Tests/Tests/Integration/PNSubscribeIntegrationTest.m +++ b/Tests/Tests/Integration/PNSubscribeIntegrationTest.m @@ -413,8 +413,7 @@ - (void)testItShouldNotSubscribeToChannelAndReceiveAccessDeniedEventWhenPAMKeysU withBlock:^(PubNub *client, PNSubscribeStatus *status, BOOL *remove) { if (status.operation == PNSubscribeOperation && status.category == PNAccessDeniedCategory) { - XCTAssertTrue(status.willAutomaticallyRetry); - [status cancelAutomaticRetry]; + XCTAssertFalse(status.willAutomaticallyRetry); *remove = YES; @@ -426,32 +425,6 @@ - (void)testItShouldNotSubscribeToChannelAndReceiveAccessDeniedEventWhenPAMKeysU }]; } -- (void)testItShouldNotSubscribeToChannelAndRetryWhenReceiveAccessDeniedEvent { - NSString *channel = [self channelWithName:@"test-channel1"]; - __block NSUInteger retriedCount = 0; - - - [self waitToCompleteIn:self.testCompletionDelay codeBlock:^(dispatch_block_t handler) { - [self addStatusHandlerForClient:self.client - withBlock:^(PubNub *client, PNSubscribeStatus *status, BOOL *remove) { - - if (status.operation == PNSubscribeOperation && status.category == PNAccessDeniedCategory) { - XCTAssertTrue(status.willAutomaticallyRetry); - - if (retriedCount == 1) { - [status cancelAutomaticRetry]; - *remove = YES; - handler(); - } else { - retriedCount++; - } - } - }]; - - [self.client subscribeToChannels:@[channel] withPresence:NO]; - }]; -} - #pragma mark - Tests :: Subscribe to channel group @@ -791,8 +764,7 @@ - (void)testItShouldNotSubscribeToChannelGroupAndReceiveAccessDeniedEventWhenPAM withBlock:^(PubNub *client, PNSubscribeStatus *status, BOOL *remove) { if (status.operation == PNSubscribeOperation && status.category == PNAccessDeniedCategory) { - XCTAssertTrue(status.willAutomaticallyRetry); - [status cancelAutomaticRetry]; + XCTAssertFalse(status.willAutomaticallyRetry); *remove = YES; @@ -804,31 +776,6 @@ - (void)testItShouldNotSubscribeToChannelGroupAndReceiveAccessDeniedEventWhenPAM }]; } -- (void)testItShouldNotSubscribeToChannelGroupAndRetryWhenReceiveAccessDeniedEvent { - NSString *channelGroup = [self channelGroupWithName:@"test-channel-group1"]; - __block NSUInteger retriedCount = 0; - - - [self waitToCompleteIn:self.testCompletionDelay codeBlock:^(dispatch_block_t handler) { - [self addStatusHandlerForClient:self.client - withBlock:^(PubNub *client, PNSubscribeStatus *status, BOOL *remove) { - - if (status.operation == PNSubscribeOperation && status.category == PNAccessDeniedCategory) { - XCTAssertTrue(status.willAutomaticallyRetry); - - if (retriedCount == 1) { - [status cancelAutomaticRetry]; - *remove = YES; - handler(); - } else { - retriedCount++; - } - } - }]; - - [self.client subscribeToChannelGroups:@[channelGroup] withPresence:NO]; - }]; -} #pragma mark - Tests :: Builder pattern-based subscribe