From 31fdf33b3b9e85909069ef3263a1c8204789bd34 Mon Sep 17 00:00:00 2001 From: Serhii Mamontov Date: Mon, 8 Jul 2024 20:45:53 +0300 Subject: [PATCH] Fix subscribe request timeout (#460) fix(subscribe): fix subscribe request timeout Fix issue because of which wrong request timeout has been used. * fix(subscribe): fix user timetoken parse Fix issue with `PNSubscribeCursorData` which should have an optional `region` to handle user timetoken in received real-time messages. --- .pubnub.yml | 17 +- CHANGELOG.md | 7 + Example/PubNub/PNAppDelegate.m | 6 +- Framework/PubNub/Info.plist | 6 +- Framework/PubNub/PubNub-iOS-Info.plist | 6 +- Framework/PubNub/PubNub-tvOS-Info.plist | 6 +- Framework/PubNub/PubNub-watchOS-Info.plist | 6 +- PubNub.podspec | 2 +- PubNub/Data/Managers/PNSubscriber.m | 14 +- .../Data/Service Objects/PNOperationResult.m | 4 +- PubNub/Misc/PNConstants.h | 2 +- .../Modules/Transport/PNURLSessionTransport.m | 93 ++++--- .../Requests/Subscribe/PNSubscribeRequest.m | 1 + .../Subscribe/PNSubscribeCursorData.m | 4 + .../Subscribe/PNSubscribeEventData.m | 2 +- README.md | 2 +- Tests/Podfile.lock | 8 +- Tests/PubNub Tests.xcodeproj/project.pbxproj | 16 ++ .../[iOS] Mocked Integration Tests.xcscheme | 3 + ...MessageWithUserTimetokenWhenPublished.json | 244 ++++++++++++++++++ .../Integration/PNSubscribeIntegrationTest.m | 34 +++ .../Unit/Core/Subscribe/PNSubscribeTest.m | 57 ++++ VERSION | 2 +- 23 files changed, 466 insertions(+), 76 deletions(-) create mode 100644 Tests/Support Files/Fixtures/PNSubscribeIntegrationTest.bundle/ItShouldSubscribeToSingleChannelAndReceiveMessageWithUserTimetokenWhenPublished.json create mode 100644 Tests/Tests/Unit/Core/Subscribe/PNSubscribeTest.m diff --git a/.pubnub.yml b/.pubnub.yml index 713c8be0b..86fde73e7 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,9 +1,16 @@ --- name: objective-c scm: github.com/pubnub/objective-c -version: "5.6.0" +version: "5.6.1" schema: 1 changelog: + - date: 2024-07-08 + version: v5.6.1 + changes: + - type: bug + text: "Fix issue because of which wrong request timeout has been used." + - type: bug + text: "Fix issue with `PNSubscribeCursorData` which should have an optional `region` to handle user timetoken in received real-time messages." - date: 2024-06-27 version: v5.6.0 changes: @@ -1358,7 +1365,7 @@ sdks: - distribution-type: source distribution-repository: GitHub release package-name: PubNub.framework - location: https://github.com/pubnub/objective-c/archive/refs/tags/v5.6.0.zip + location: https://github.com/pubnub/objective-c/archive/refs/tags/v5.6.1.zip supported-platforms: supported-operating-systems: macOS: @@ -1419,7 +1426,7 @@ sdks: - distribution-type: library distribution-repository: GitHub release package-name: PubNub.ios.xcframework.tar.gz - location: https://github.com/pubnub/objective-c/releases/download/v5.6.0/PubNub.ios.xcframework.tar.gz + location: https://github.com/pubnub/objective-c/releases/download/v5.6.1/PubNub.ios.xcframework.tar.gz supported-platforms: supported-operating-systems: iOS: @@ -1438,7 +1445,7 @@ sdks: - distribution-type: library distribution-repository: GitHub release package-name: PubNub.macos.framework.tar.gz - location: https://github.com/pubnub/objective-c/releases/download/v5.6.0/PubNub.macos.framework.tar.gz + location: https://github.com/pubnub/objective-c/releases/download/v5.6.1/PubNub.macos.framework.tar.gz supported-platforms: supported-operating-systems: macOS: @@ -1454,7 +1461,7 @@ sdks: - distribution-type: library distribution-repository: GitHub release package-name: PubNub.tvos.xcframework.tar.gz - location: https://github.com/pubnub/objective-c/releases/download/v5.6.0/PubNub.tvos.xcframework.tar.gz + location: https://github.com/pubnub/objective-c/releases/download/v5.6.1/PubNub.tvos.xcframework.tar.gz supported-platforms: supported-operating-systems: tvOS: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e006701b..615fb6ed9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## v5.6.1 +July 08 2024 + +#### Fixed +- Fix issue because of which wrong request timeout has been used. +- Fix issue with `PNSubscribeCursorData` which should have an optional `region` to handle user timetoken in received real-time messages. + ## v5.6.0 June 27 2024 diff --git a/Example/PubNub/PNAppDelegate.m b/Example/PubNub/PNAppDelegate.m index 2052ff1e2..0e5054740 100644 --- a/Example/PubNub/PNAppDelegate.m +++ b/Example/PubNub/PNAppDelegate.m @@ -595,10 +595,8 @@ - (void)handleErrorStatus:(PNErrorStatus *)status { NSLog(@"Decryption error. Be sure the data is encrypted and/or encrypted with the correct cipher key."); NSLog(@"You can find the raw data returned from the server in the status.data attribute: %@", status.associatedObject); if (status.operation == PNSubscribeOperation) { - - NSLog(@"Decryption failed for message from channel: %@\nmessage: %@", - ((PNMessageData *)status.associatedObject).channel, - ((PNMessageData *)status.associatedObject).message); + PNSubscribeMessageEventData *data = status.associatedObject; + NSLog(@"Decryption failed for message from channel: %@\nmessage: %@", data.channel, data.message); } } else if (status.category == PNMalformedFilterExpressionCategory) { diff --git a/Framework/PubNub/Info.plist b/Framework/PubNub/Info.plist index 9eb76a905..de50bfee2 100644 --- a/Framework/PubNub/Info.plist +++ b/Framework/PubNub/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable PubNub CFBundleGetInfoString - 5.6.0 + 5.6.1 CFBundleIdentifier com.pubnub.pubnub-objc CFBundleInfoDictionaryVersion @@ -17,11 +17,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.6.0 + 5.6.1 CFBundleSignature ???? CFBundleVersion - 5.6.0 + 5.6.1 NSHumanReadableCopyright © 2010 - 2020 PubNub, Inc. NSPrincipalClass diff --git a/Framework/PubNub/PubNub-iOS-Info.plist b/Framework/PubNub/PubNub-iOS-Info.plist index 9eb76a905..de50bfee2 100644 --- a/Framework/PubNub/PubNub-iOS-Info.plist +++ b/Framework/PubNub/PubNub-iOS-Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable PubNub CFBundleGetInfoString - 5.6.0 + 5.6.1 CFBundleIdentifier com.pubnub.pubnub-objc CFBundleInfoDictionaryVersion @@ -17,11 +17,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.6.0 + 5.6.1 CFBundleSignature ???? CFBundleVersion - 5.6.0 + 5.6.1 NSHumanReadableCopyright © 2010 - 2020 PubNub, Inc. NSPrincipalClass diff --git a/Framework/PubNub/PubNub-tvOS-Info.plist b/Framework/PubNub/PubNub-tvOS-Info.plist index 9eb76a905..de50bfee2 100644 --- a/Framework/PubNub/PubNub-tvOS-Info.plist +++ b/Framework/PubNub/PubNub-tvOS-Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable PubNub CFBundleGetInfoString - 5.6.0 + 5.6.1 CFBundleIdentifier com.pubnub.pubnub-objc CFBundleInfoDictionaryVersion @@ -17,11 +17,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.6.0 + 5.6.1 CFBundleSignature ???? CFBundleVersion - 5.6.0 + 5.6.1 NSHumanReadableCopyright © 2010 - 2020 PubNub, Inc. NSPrincipalClass diff --git a/Framework/PubNub/PubNub-watchOS-Info.plist b/Framework/PubNub/PubNub-watchOS-Info.plist index 9eb76a905..de50bfee2 100644 --- a/Framework/PubNub/PubNub-watchOS-Info.plist +++ b/Framework/PubNub/PubNub-watchOS-Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable PubNub CFBundleGetInfoString - 5.6.0 + 5.6.1 CFBundleIdentifier com.pubnub.pubnub-objc CFBundleInfoDictionaryVersion @@ -17,11 +17,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.6.0 + 5.6.1 CFBundleSignature ???? CFBundleVersion - 5.6.0 + 5.6.1 NSHumanReadableCopyright © 2010 - 2020 PubNub, Inc. NSPrincipalClass diff --git a/PubNub.podspec b/PubNub.podspec index 7aedc894d..1a65c0cea 100644 --- a/PubNub.podspec +++ b/PubNub.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |spec| spec.name = 'PubNub' - spec.version = '5.6.0' + spec.version = '5.6.1' spec.summary = 'The PubNub Real-Time Network. Build real-time apps quickly and scale them globally.' spec.homepage = 'https://github.com/pubnub/objective-c' diff --git a/PubNub/Data/Managers/PNSubscriber.m b/PubNub/Data/Managers/PNSubscriber.m index e81a5503c..6e5121b99 100644 --- a/PubNub/Data/Managers/PNSubscriber.m +++ b/PubNub/Data/Managers/PNSubscriber.m @@ -1336,7 +1336,7 @@ - (void)handleNewMessage:(PNMessageResult *)message { PNErrorStatus *status = nil; - PNLogResult(self.client.logger, @" %@", [message stringifiedRepresentationWithSerializer:nil]); + PNLogResult(self.client.logger, @" %@", [message stringifiedRepresentationWithSerializer:self.client.coder]); if (message.data.decryptionError) { status = [PNErrorStatus objectWithOperation:PNSubscribeOperation @@ -1352,7 +1352,7 @@ - (void)handleNewMessage:(PNMessageResult *)message { - (void)handleNewSignal:(PNSignalResult *)signal { if (!signal) return; - PNLogResult(self.client.logger, @" %@", [signal stringifiedRepresentationWithSerializer:nil]); + PNLogResult(self.client.logger, @" %@", [signal stringifiedRepresentationWithSerializer:self.client.coder]); [self.client.listenersManager notifySignal:signal]; } @@ -1360,7 +1360,7 @@ - (void)handleNewSignal:(PNSignalResult *)signal { - (void)handleNewMessageAction:(PNMessageActionResult *)action { if (!action) return; - PNLogResult(self.client.logger, @" %@", [action stringifiedRepresentationWithSerializer:nil]); + PNLogResult(self.client.logger, @" %@", [action stringifiedRepresentationWithSerializer:self.client.coder]); [self.client.listenersManager notifyMessageAction:action]; } @@ -1368,7 +1368,7 @@ - (void)handleNewMessageAction:(PNMessageActionResult *)action { - (void)handleNewObjectsEvent:(PNObjectEventResult *)object { if (!object) return; - PNLogResult(self.client.logger, @" %@", [object stringifiedRepresentationWithSerializer:nil]); + PNLogResult(self.client.logger, @" %@", [object stringifiedRepresentationWithSerializer:self.client.coder]); [self.client.listenersManager notifyObjectEvent:object]; } @@ -1377,8 +1377,8 @@ - (void)handleNewFileEvent:(PNFileEventResult *)file { PNErrorStatus *status = nil; if (file) { - PNLogResult(self.client.logger, @" %@", [file stringifiedRepresentationWithSerializer:nil]); - + PNLogResult(self.client.logger, @" %@", [file stringifiedRepresentationWithSerializer:self.client.coder]); + if (file.data.decryptionError) { status = [PNErrorStatus objectWithOperation:PNSubscribeOperation category:PNDecryptionErrorCategory @@ -1398,7 +1398,7 @@ - (void)handleNewFileEvent:(PNFileEventResult *)file { - (void)handleNewPresenceEvent:(PNPresenceEventResult *)presence { if (presence) { - PNLogResult(self.client.logger, @" %@", [presence stringifiedRepresentationWithSerializer:nil]); + PNLogResult(self.client.logger, @" %@", [presence stringifiedRepresentationWithSerializer:self.client.coder]); } [self.client.listenersManager notifyPresenceEvent:presence]; diff --git a/PubNub/Data/Service Objects/PNOperationResult.m b/PubNub/Data/Service Objects/PNOperationResult.m index 93c742d2d..d5d0302d6 100644 --- a/PubNub/Data/Service Objects/PNOperationResult.m +++ b/PubNub/Data/Service Objects/PNOperationResult.m @@ -118,7 +118,7 @@ - (id)copyWithZone:(NSZone *)zone { - (NSDictionary *)dictionaryRepresentationWithSerializer:(id)serializer { id processedData = self.responseData; - if (serializer) { + if (serializer && processedData) { NSError *err; NSData *serializedData = [serializer dataOfClass:[NSDictionary class] fromObject:processedData withError:&err]; NSDictionary *serializedDictionary = [serializer.jsonSerializer JSONObjectWithData:serializedData error:&err]; @@ -128,7 +128,7 @@ - (NSDictionary *)dictionaryRepresentationWithSerializer:(id #pragma clang diagnostic ignored "-Wdeprecated-declarations" NSMutableDictionary *response = [@{ @"Status code": @(self.statusCode), - @"Processed data": processedData + @"Processed data": processedData ?: @"no data" } mutableCopy]; return @{@"Operation": PNOperationTypeStrings[self.operation], diff --git a/PubNub/Misc/PNConstants.h b/PubNub/Misc/PNConstants.h index 058e136b0..ae0eaecb3 100644 --- a/PubNub/Misc/PNConstants.h +++ b/PubNub/Misc/PNConstants.h @@ -15,7 +15,7 @@ #pragma mark General information constants // Stores client library version number -static NSString * const kPNLibraryVersion = @"5.6.0"; +static NSString * const kPNLibraryVersion = @"5.6.1"; // Stores information about SDK codebase static NSString * const kPNCommit = @"fd5c7ed678527fce07eaf7eb162935caf1bfd303"; diff --git a/PubNub/Modules/Transport/PNURLSessionTransport.m b/PubNub/Modules/Transport/PNURLSessionTransport.m index 92bf0b844..ac3de59f0 100644 --- a/PubNub/Modules/Transport/PNURLSessionTransport.m +++ b/PubNub/Modules/Transport/PNURLSessionTransport.m @@ -165,8 +165,8 @@ - (void)setupWithConfiguration:(PNTransportConfiguration *)configuration { - (void)requestsWithBlock:(void (^)(NSArray *))block { if (!block) return; - - [self.lock syncWriteAccessWithBlock:^{ + + [self.lock writeAccessWithBlock:^{ block(self.requests); // Filter out potentially cancelled requests after block has been called. [self.requests filterUsingPredicate:self.cancelledPredicate]; @@ -182,20 +182,26 @@ - (void)sendRequest:(PNTransportRequest *)request withCompletionBlock:(PNRequest PNWeakify(self); __block NSURLSessionTask *task; - task = [self.session dataTaskWithRequest:urlRequest - completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + __block NSURLSession *session; + + [self.lock readAccessWithBlock:^{ + session = self.session; + }]; + + task = [session dataTaskWithRequest:urlRequest + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { PNStrongify(self); BOOL retriableError = error && error.code != NSURLErrorCancelled; NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode; BOOL retriableStatusCode = statusCode >= 400 && statusCode != 403; NSTimeInterval delay = 0.f; - if ((retriableError || retriableStatusCode) && request.retriable) { + if ((retriableError || retriableStatusCode) && request.retriable && !request.cancelled) { PNRequestRetryConfiguration *retry = self.configuration.retryConfiguration; NSUInteger retryAttempt = request.retryAttempt + 1; delay = [retry retryDelayForFailedRequest:urlRequest withResponse:response retryAttempt:retryAttempt]; } - + if (delay > 0.f) { request.retryAttempt += 1; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), @@ -219,15 +225,21 @@ - (void)sendDownloadRequest:(PNTransportRequest *)request withCompletionBlock:(P PNWeakify(self); __block NSURLSessionTask *task; - task = [self.session downloadTaskWithRequest:urlRequest - completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { + __block NSURLSession *session; + + [self.lock readAccessWithBlock:^{ + session = self.session; + }]; + + task = [session downloadTaskWithRequest:urlRequest + completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { PNStrongify(self); BOOL retriableError = error && error.code != NSURLErrorCancelled; NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode; BOOL retriableStatusCode = statusCode >= 400 && statusCode != 403; NSTimeInterval delay = 0.f; - if ((retriableError || retriableStatusCode) && request.retriable) { + if ((retriableError || retriableStatusCode) && request.retriable && !request.cancelled) { PNRequestRetryConfiguration *retry = self.configuration.retryConfiguration; NSUInteger retryAttempt = request.retryAttempt + 1; delay = [retry retryDelayForFailedRequest:urlRequest withResponse:response retryAttempt:retryAttempt]; @@ -252,31 +264,38 @@ - (void)sendDownloadRequest:(PNTransportRequest *)request withCompletionBlock:(P } - (void)sendRequest:(PNTransportRequest *)request withSessionTask:(NSURLSessionTask *)task { - [self.lock asyncWriteAccessWithBlock:^{ - [self.requests addObject:request]; + if (request.cancellable) { + [self.lock writeAccessWithBlock:^{ + [self.requests addObject:request]; + }]; - PNLogRequest(self.configuration.logger, @" %@ %@", - request.stringifiedMethod, task.originalRequest.URL.absoluteString); - - if (request.cancellable) { - __weak __typeof(request) weakRequest = request; - PNWeakify(self); - - request.cancel = ^{ - PNStrongify(self); - - weakRequest.cancelled = YES; - weakRequest.cancel = nil; - [task cancel]; - - [self.lock asyncWriteAccessWithBlock:^{ - [self.requests removeObject:weakRequest]; - }]; - }; - } + __weak __typeof(request) weakRequest = request; + PNWeakify(self); - [task resume]; - }]; + request.cancel = ^{ + NSURLSessionTaskState taskState = task.state; + BOOL cancelled = weakRequest.cancelled; + + PNStrongify(self); + + weakRequest.cancelled = YES; + weakRequest.cancel = nil; + + if (cancelled || taskState != NSURLSessionTaskStateRunning) return; + + [task cancel]; + + [self.lock writeAccessWithBlock:^{ + __strong __typeof__(weakRequest) strongRequest = weakRequest; + if (strongRequest) [self.requests removeObject:strongRequest]; + }]; + }; + } + + PNLogRequest(self.configuration.logger, @" %@ %@", + request.stringifiedMethod, task.originalRequest.URL.absoluteString); + + [task resume]; } - (PNTransportRequest *)transportRequestFromTransportRequest:(PNTransportRequest *)request { @@ -302,7 +321,7 @@ - (PNTransportRequest *)transportRequestFromTransportRequest:(PNTransportRequest taskCompletion:(NSURLSessionTask *)task withResponse:(NSURLResponse *)response data:(NSData *)data { - [self.lock syncWriteAccessWithBlock:^{ + [self.lock writeAccessWithBlock:^{ request.cancel = nil; [self.requests removeObject:request]; NSUInteger activeRequestsCount = self.requests.count; @@ -362,7 +381,7 @@ - (void)endBackgroundTasksCompletionIfRequired { } - (void)invalidate { - [self.lock syncWriteAccessWithBlock:^{ + [self.lock writeAccessWithBlock:^{ [self endBackgroundTasksCompletionIfRequired]; [self.session invalidateAndCancel]; self->_session = nil; @@ -380,10 +399,10 @@ - (void)setupURLSession { } - (NSURLSessionConfiguration *)urlSessionConfiguration { - NSString *identifier = [NSString stringWithFormat:@"com.pubnub.network.%p", self]; + self.identifier = [NSString stringWithFormat:@"com.pubnub.transport.%p", self]; NSURLSessionConfiguration *configuration = nil; - configuration = [NSURLSessionConfiguration pn_ephemeralSessionConfigurationWithIdentifier:identifier]; + configuration = [NSURLSessionConfiguration pn_ephemeralSessionConfigurationWithIdentifier:self.identifier]; configuration.HTTPMaximumConnectionsPerHost = self.configuration.maximumConnections; _HTTPAdditionalHeaders = [configuration.HTTPAdditionalHeaders copy]; _cachePolicy = configuration.requestCachePolicy; @@ -394,7 +413,7 @@ - (NSURLSessionConfiguration *)urlSessionConfiguration { - (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error { if (!error) return; - [self.lock syncWriteAccessWithBlock:^{ + [self.lock writeAccessWithBlock:^{ [self setupURLSession]; }]; } diff --git a/PubNub/Network/Requests/Subscribe/PNSubscribeRequest.m b/PubNub/Network/Requests/Subscribe/PNSubscribeRequest.m index b8fdc7ee0..bd9799d23 100644 --- a/PubNub/Network/Requests/Subscribe/PNSubscribeRequest.m +++ b/PubNub/Network/Requests/Subscribe/PNSubscribeRequest.m @@ -64,6 +64,7 @@ @implementation PNSubscribeRequest - (PNTransportRequest *)request { PNTransportRequest *request = super.request; + request.timeout = self.subscribeMaximumIdleTime; request.cancellable = YES; request.retriable = NO; diff --git a/PubNub/Network/Responses/Subscribe/PNSubscribeCursorData.m b/PubNub/Network/Responses/Subscribe/PNSubscribeCursorData.m index 6a6024068..8d0ca5535 100644 --- a/PubNub/Network/Responses/Subscribe/PNSubscribeCursorData.m +++ b/PubNub/Network/Responses/Subscribe/PNSubscribeCursorData.m @@ -32,6 +32,10 @@ @implementation PNSubscribeCursorData }; } ++ (NSArray *)optionalKeys { + return @[@"region"]; +} + #pragma mark - diff --git a/PubNub/Network/Responses/Subscribe/PNSubscribeEventData.m b/PubNub/Network/Responses/Subscribe/PNSubscribeEventData.m index 88aed2be1..989e228b6 100644 --- a/PubNub/Network/Responses/Subscribe/PNSubscribeEventData.m +++ b/PubNub/Network/Responses/Subscribe/PNSubscribeEventData.m @@ -65,7 +65,7 @@ @implementation PNSubscribeEventData } + (NSArray *)ignoredKeys { - return @[@"timetoken"]; + return @[@"timetoken", @"region"]; } - (NSString *)subscription { diff --git a/README.md b/README.md index 59a595e8a..4e3ea444d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# PubNub 5.6.0 for iOS 9+ +# PubNub 5.6.1 for iOS 9+ [![Twitter](https://img.shields.io/badge/twitter-%40PubNub-blue.svg?style=flat)](https://twitter.com/PubNub) [![Twitter Releases](https://img.shields.io/badge/twitter-%40PubNubRelease-blue.svg?style=flat)](https://twitter.com/PubNubRelease) [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/PubNub.svg?style=flat)](https://img.shields.io/cocoapods/v/PubNub.svg) diff --git a/Tests/Podfile.lock b/Tests/Podfile.lock index ef40d5456..80d2100c2 100644 --- a/Tests/Podfile.lock +++ b/Tests/Podfile.lock @@ -1,9 +1,9 @@ PODS: - Cucumberish (1.4.0) - OCMock (3.6) - - PubNub (5.5.0): - - PubNub/Core (= 5.5.0) - - PubNub/Core (5.5.0) + - PubNub (5.6.0): + - PubNub/Core (= 5.6.0) + - PubNub/Core (5.6.0) - YAHTTPVCR (1.5.0) DEPENDENCIES: @@ -32,7 +32,7 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: Cucumberish: 6cbd0c1f50306b369acebfe7d9f514c9c287d26c OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 - PubNub: 17b22578c960a206863289c3662d0ccc803c71f7 + PubNub: 4c06870a45eba7d59ac5f6598de28207fe7dac17 YAHTTPVCR: cb7a710d4289ee9b038fd708d2fb8df4e6521bc0 PODFILE CHECKSUM: fb38a10e9ab7ec6c9e4fe43e6a3b6ffc35154550 diff --git a/Tests/PubNub Tests.xcodeproj/project.pbxproj b/Tests/PubNub Tests.xcodeproj/project.pbxproj index c29f369e5..394eb4338 100644 --- a/Tests/PubNub Tests.xcodeproj/project.pbxproj +++ b/Tests/PubNub Tests.xcodeproj/project.pbxproj @@ -54,6 +54,9 @@ A529271923B185F900FF46DD /* tests-configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = A529271823B1855A00FF46DD /* tests-configuration.json */; }; A529271A23B185F900FF46DD /* tests-configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = A529271823B1855A00FF46DD /* tests-configuration.json */; }; A529271D23B185FF00FF46DD /* tests-configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = A529271823B1855A00FF46DD /* tests-configuration.json */; }; + A53249102C304F90003510FF /* PNSubscribeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A532490F2C304F90003510FF /* PNSubscribeTest.m */; }; + A53249112C304F90003510FF /* PNSubscribeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A532490F2C304F90003510FF /* PNSubscribeTest.m */; }; + A53249122C304F90003510FF /* PNSubscribeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A532490F2C304F90003510FF /* PNSubscribeTest.m */; }; A53D0AEE23E9BF60001E72AF /* PNMembershipsObjectsAPICallBuilderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A53D0AED23E9BF60001E72AF /* PNMembershipsObjectsAPICallBuilderTest.m */; }; A53D0AEF23E9BF60001E72AF /* PNMembershipsObjectsAPICallBuilderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A53D0AED23E9BF60001E72AF /* PNMembershipsObjectsAPICallBuilderTest.m */; }; A53D0AF023E9BF60001E72AF /* PNMembershipsObjectsAPICallBuilderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A53D0AED23E9BF60001E72AF /* PNMembershipsObjectsAPICallBuilderTest.m */; }; @@ -230,6 +233,7 @@ A529270E23B181FE00FF46DD /* PNRecordableTestCase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PNRecordableTestCase.h; sourceTree = ""; }; A529270F23B181FE00FF46DD /* PNRecordableTestCase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PNRecordableTestCase.m; sourceTree = ""; }; A529271823B1855A00FF46DD /* tests-configuration.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "tests-configuration.json"; sourceTree = ""; }; + A532490F2C304F90003510FF /* PNSubscribeTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PNSubscribeTest.m; sourceTree = ""; }; A53D0AED23E9BF60001E72AF /* PNMembershipsObjectsAPICallBuilderTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PNMembershipsObjectsAPICallBuilderTest.m; sourceTree = ""; }; A53D0AF123E9F42B001E72AF /* PNChannelMembersObjectsAPICallBuilderTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PNChannelMembersObjectsAPICallBuilderTest.m; sourceTree = ""; }; A53D0AF523E9F7D7001E72AF /* PNChannelMetadataAPICallBuilderTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PNChannelMetadataAPICallBuilderTest.m; sourceTree = ""; }; @@ -532,6 +536,14 @@ path = Helpers; sourceTree = ""; }; + A532490E2C304F50003510FF /* Subscribe */ = { + isa = PBXGroup; + children = ( + A532490F2C304F90003510FF /* PNSubscribeTest.m */, + ); + path = Subscribe; + sourceTree = ""; + }; A53D0AEB23E9BF2C001E72AF /* Interfaces */ = { isa = PBXGroup; children = ( @@ -644,6 +656,7 @@ A59ECFDA23BB56E900E84300 /* Core */ = { isa = PBXGroup; children = ( + A532490E2C304F50003510FF /* Subscribe */, 79CFA2D526DE25A400D206D4 /* Access Manager */, A53D0AEB23E9BF2C001E72AF /* Interfaces */, A53D0B0D23EA07BD001E72AF /* Objects */, @@ -1165,6 +1178,7 @@ A53D0B2123EA0DB7001E72AF /* PNMessageActionsTest.m in Sources */, A5F8E9DD2476D47C007F79AB /* PNObjectsAPICallBuilderTest.m in Sources */, 79CFA2D926DE25DC00D206D4 /* PNPAMTokenTest.m in Sources */, + A53249112C304F90003510FF /* PNSubscribeTest.m in Sources */, A53D0B2723EA0EAD001E72AF /* PNMessageCountTest.m in Sources */, A53D0B0623EA063A001E72AF /* PNSignalAPIBuilderTest.m in Sources */, A53D0B1C23EA0C5C001E72AF /* PNUUIDMetadataObjectsTest.m in Sources */, @@ -1219,6 +1233,7 @@ A53D0B2023EA0DB7001E72AF /* PNMessageActionsTest.m in Sources */, A5F8E9DC2476D47A007F79AB /* PNObjectsAPICallBuilderTest.m in Sources */, 79CFA2D826DE25DA00D206D4 /* PNPAMTokenTest.m in Sources */, + A53249102C304F90003510FF /* PNSubscribeTest.m in Sources */, A53D0B2623EA0EAD001E72AF /* PNMessageCountTest.m in Sources */, A53D0B0523EA063A001E72AF /* PNSignalAPIBuilderTest.m in Sources */, A53D0B1B23EA0C5C001E72AF /* PNUUIDMetadataObjectsTest.m in Sources */, @@ -1248,6 +1263,7 @@ A53D0B2223EA0DB7001E72AF /* PNMessageActionsTest.m in Sources */, A5F8E9DE2476D47D007F79AB /* PNObjectsAPICallBuilderTest.m in Sources */, 79CFA2DA26DE25DD00D206D4 /* PNPAMTokenTest.m in Sources */, + A53249122C304F90003510FF /* PNSubscribeTest.m in Sources */, A53D0B2823EA0EAD001E72AF /* PNMessageCountTest.m in Sources */, A53D0B0723EA063A001E72AF /* PNSignalAPIBuilderTest.m in Sources */, A53D0B1D23EA0C5C001E72AF /* PNUUIDMetadataObjectsTest.m in Sources */, diff --git a/Tests/PubNub Tests.xcodeproj/xcshareddata/xcschemes/[iOS] Mocked Integration Tests.xcscheme b/Tests/PubNub Tests.xcodeproj/xcshareddata/xcschemes/[iOS] Mocked Integration Tests.xcscheme index baed17c19..6978a60e9 100644 --- a/Tests/PubNub Tests.xcodeproj/xcshareddata/xcschemes/[iOS] Mocked Integration Tests.xcscheme +++ b/Tests/PubNub Tests.xcodeproj/xcshareddata/xcschemes/[iOS] Mocked Integration Tests.xcscheme @@ -40,6 +40,9 @@ ReferencedContainer = "container:PubNub Tests.xcodeproj"> + + diff --git a/Tests/Support Files/Fixtures/PNSubscribeIntegrationTest.bundle/ItShouldSubscribeToSingleChannelAndReceiveMessageWithUserTimetokenWhenPublished.json b/Tests/Support Files/Fixtures/PNSubscribeIntegrationTest.bundle/ItShouldSubscribeToSingleChannelAndReceiveMessageWithUserTimetokenWhenPublished.json new file mode 100644 index 000000000..c3509bdfd --- /dev/null +++ b/Tests/Support Files/Fixtures/PNSubscribeIntegrationTest.bundle/ItShouldSubscribeToSingleChannelAndReceiveMessageWithUserTimetokenWhenPublished.json @@ -0,0 +1,244 @@ +[ + { + "id" : "6D9CF0BE-C72E-451C-BD56-ADC3759E4917", + "data" : { + "method" : "get", + "cls" : "NSURLRequest", + "cellular" : true, + "cache" : 1, + "timeout" : 60, + "cookies" : true, + "headers" : { + "User-Agent" : "iPhone; CPU iPhone OS 12.4.0 Version", + "Accept" : "*\/*", + "Connection" : "keep-alive", + "Accept-Encoding" : "gzip,deflate" + }, + "pipeline" : false, + "network" : 0, + "url" : "https:\/\/ps.pndsn.com\/v2\/subscribe\/demo\/test-channel1\/0?pnsdk=PubNub-ObjC-iOS\/4.x.x&uuid=Serhii&tt=0&heartbeat=20" + }, + "type" : 0 + }, + { + "id" : "6D9CF0BE-C72E-451C-BD56-ADC3759E4917", + "data" : { + "status" : 200, + "cls" : "NSHTTPURLResponse", + "url" : "https:\/\/ps.pndsn.com\/v2\/subscribe\/demo\/test-channel1\/0?pnsdk=PubNub-ObjC-iOS\/4.x.x&uuid=Serhii&tt=0&heartbeat=20", + "headers" : { + "Access-Control-Allow-Methods" : "GET", + "Content-Type" : "text\/javascript; charset=\"UTF-8\"", + "Access-Control-Allow-Origin" : "*", + "Date" : "Tue, 04 Feb 2020 13:10:11 GMT", + "Content-Length" : "45", + "Cache-Control" : "no-cache", + "Connection" : "keep-alive" + } + }, + "type" : 1 + }, + { + "id" : "6D9CF0BE-C72E-451C-BD56-ADC3759E4917", + "data" : { + "cls" : "NSData", + "base64" : "eyJ0Ijp7InQiOiIxNTgwODIxODExNDczMDU1OSIsInIiOjEyfSwibSI6W119" + }, + "type" : 2 + }, + { + "id" : "6D9CF0BE-C72E-451C-BD56-ADC3759E4917", + "type" : 4 + }, + { + "id" : "56380FEF-3510-4D26-8D88-22A028B35217", + "data" : { + "method" : "get", + "cls" : "NSURLRequest", + "cellular" : true, + "cache" : 1, + "timeout" : 60, + "cookies" : true, + "headers" : { + "User-Agent" : "iPhone; CPU iPhone OS 12.4.0 Version", + "Accept" : "*\/*", + "Connection" : "keep-alive", + "Accept-Encoding" : "gzip,deflate" + }, + "pipeline" : false, + "network" : 0, + "url" : "https:\/\/ps.pndsn.com\/v2\/subscribe\/demo\/test-channel1\/0?uuid=Serhii&pnsdk=PubNub-ObjC-iOS\/4.x.x&tt=15808218114730559&heartbeat=20&tr=12" + }, + "type" : 0 + }, + { + "id" : "9060F768-F824-4970-93AC-4BF1FA1121D5", + "data" : { + "method" : "get", + "cls" : "NSURLRequest", + "cellular" : true, + "cache" : 1, + "timeout" : 60, + "cookies" : true, + "headers" : { + "User-Agent" : "iPhone; CPU iPhone OS 12.4.0 Version", + "Accept" : "*\/*", + "Connection" : "keep-alive", + "Accept-Encoding" : "gzip,deflate" + }, + "pipeline" : false, + "network" : 0, + "url" : "https:\/\/ps.pndsn.com\/publish\/demo\/demo\/0\/test-channel1\/0\/%7B%22test-message%22:%5B%22message%22%5D%7D?uuid=Serhii&pnsdk=PubNub-ObjC-iOS\/4.x.x&seqn=1" + }, + "type" : 0 + }, + { + "id" : "9060F768-F824-4970-93AC-4BF1FA1121D5", + "data" : { + "status" : 200, + "cls" : "NSHTTPURLResponse", + "url" : "https:\/\/ps.pndsn.com\/publish\/demo\/demo\/0\/test-channel1\/0\/%7B%22test-message%22:%5B%22message%22%5D%7D?pnsdk=PubNub-ObjC-iOS\/4.x.x&seqn=1&uuid=Serhii", + "headers" : { + "Access-Control-Allow-Methods" : "GET", + "Content-Type" : "text\/javascript; charset=\"UTF-8\"", + "Access-Control-Allow-Origin" : "*", + "Date" : "Tue, 04 Feb 2020 13:10:14 GMT", + "Content-Length" : "30", + "Cache-Control" : "no-cache", + "Connection" : "keep-alive" + } + }, + "type" : 1 + }, + { + "id" : "9060F768-F824-4970-93AC-4BF1FA1121D5", + "data" : { + "cls" : "NSData", + "base64" : "WzEsIlNlbnQiLCIxNTgwODIxODE0ODc5NTIwMCJd" + }, + "type" : 2 + }, + { + "id" : "9060F768-F824-4970-93AC-4BF1FA1121D5", + "type" : 4 + }, + { + "id" : "56380FEF-3510-4D26-8D88-22A028B35217", + "data" : { + "status" : 200, + "cls" : "NSHTTPURLResponse", + "url" : "https:\/\/ps.pndsn.com\/v2\/subscribe\/demo\/test-channel1\/0?uuid=Serhii&pnsdk=PubNub-ObjC-iOS\/4.x.x&tt=15808218114730559&heartbeat=20&tr=12", + "headers" : { + "Access-Control-Allow-Methods" : "GET", + "Content-Type" : "text\/javascript; charset=\"UTF-8\"", + "Access-Control-Allow-Origin" : "*", + "Date" : "Tue, 04 Feb 2020 13:10:14 GMT", + "Content-Length" : "291", + "Cache-Control" : "no-cache", + "Connection" : "keep-alive" + } + }, + "type" : 1 + }, + { + "id" : "56380FEF-3510-4D26-8D88-22A028B35217", + "data" : { + "cls" : "NSData", + "base64" : "eyJ0Ijp7InQiOiIxNTgwODIxODE0ODgwNDc4NyIsInIiOjEyfSwibSI6W3siYSI6IjUiLCJmIjowLCJpIjoiU2VyaGlpIiwicyI6MTAsInAiOnsidCI6IjE1ODA4MjE4MTQ4Nzk1MjAwIiwiciI6MTJ9LCJvIjp7InQiOiIxNTgwODIxODE0ODc5NTE5OSJ9LCJrIjoiZGVtbyIsImMiOiJ0ZXN0LWNoYW5uZWwxIiwiZCI6eyJ0ZXN0LW1lc3NhZ2UiOlsibWVzc2FnZSJdfX1dfQ==" + }, + "type" : 2 + }, + { + "id" : "56380FEF-3510-4D26-8D88-22A028B35217", + "type" : 4 + }, + { + "id" : "8166D76F-F897-4ABB-934A-13726D856948", + "data" : { + "method" : "get", + "cls" : "NSURLRequest", + "cellular" : true, + "cache" : 1, + "timeout" : 60, + "cookies" : true, + "headers" : { + "User-Agent" : "iPhone; CPU iPhone OS 12.4.0 Version", + "Accept" : "*\/*", + "Connection" : "keep-alive", + "Accept-Encoding" : "gzip,deflate" + }, + "pipeline" : false, + "network" : 0, + "url" : "https:\/\/ps.pndsn.com\/v2\/subscribe\/demo\/test-channel1\/0?uuid=Serhii&pnsdk=PubNub-ObjC-iOS\/4.x.x&tt=15808218148804787&heartbeat=20&tr=12" + }, + "type" : 0 + }, + { + "id" : "8166D76F-F897-4ABB-934A-13726D856948", + "data" : { + "code" : -999, + "info" : { + "NSErrorFailingURLStringKey" : "https:\/\/ps.pndsn.com\/v2\/subscribe\/demo\/test-channel1\/0?uuid=Serhii&pnsdk=PubNub-ObjC-iOS\/4.x.x&tt=15808218148804787&heartbeat=20&tr=12", + "NSLocalizedDescription" : "cancelled", + "NSErrorFailingURLKey" : "https:\/\/ps.pndsn.com\/v2\/subscribe\/demo\/test-channel1\/0?uuid=Serhii&pnsdk=PubNub-ObjC-iOS\/4.x.x&tt=15808218148804787&heartbeat=20&tr=12" + }, + "cls" : "NSError", + "domain" : "NSURLErrorDomain" + }, + "type" : 3 + }, + { + "id" : "1966F67F-1E40-41C0-B669-9A9607D9514C", + "data" : { + "method" : "get", + "cls" : "NSURLRequest", + "cellular" : true, + "cache" : 1, + "timeout" : 60, + "cookies" : true, + "headers" : { + "User-Agent" : "iPhone; CPU iPhone OS 12.4.0 Version", + "Accept" : "*\/*", + "Connection" : "keep-alive", + "Accept-Encoding" : "gzip,deflate" + }, + "pipeline" : false, + "network" : 0, + "url" : "https:\/\/ps.pndsn.com\/v2\/presence\/sub_key\/demo\/channel\/test-channel1\/leave?uuid=Serhii&pnsdk=PubNub-ObjC-iOS\/4.x.x" + }, + "type" : 0 + }, + { + "id" : "1966F67F-1E40-41C0-B669-9A9607D9514C", + "data" : { + "status" : 200, + "cls" : "NSHTTPURLResponse", + "url" : "https:\/\/ps.pndsn.com\/v2\/presence\/sub_key\/demo\/channel\/test-channel1\/leave?uuid=Serhii&pnsdk=PubNub-ObjC-iOS\/4.x.x", + "headers" : { + "Access-Control-Allow-Methods" : "OPTIONS, GET, POST", + "Content-Type" : "text\/javascript; charset=\"UTF-8\"", + "Server" : "Pubnub Presence", + "Access-Control-Allow-Origin" : "*", + "Age" : "0", + "Date" : "Tue, 04 Feb 2020 13:10:15 GMT", + "Accept-Ranges" : "bytes", + "Content-Length" : "74", + "Cache-Control" : "no-cache", + "Connection" : "keep-alive" + } + }, + "type" : 1 + }, + { + "id" : "1966F67F-1E40-41C0-B669-9A9607D9514C", + "data" : { + "cls" : "NSData", + "base64" : "eyJzdGF0dXMiOiAyMDAsICJtZXNzYWdlIjogIk9LIiwgImFjdGlvbiI6ICJsZWF2ZSIsICJzZXJ2aWNlIjogIlByZXNlbmNlIn0=" + }, + "type" : 2 + }, + { + "id" : "1966F67F-1E40-41C0-B669-9A9607D9514C", + "type" : 4 + } +] diff --git a/Tests/Tests/Integration/PNSubscribeIntegrationTest.m b/Tests/Tests/Integration/PNSubscribeIntegrationTest.m index 2c0d8f39a..a32b452b8 100644 --- a/Tests/Tests/Integration/PNSubscribeIntegrationTest.m +++ b/Tests/Tests/Integration/PNSubscribeIntegrationTest.m @@ -3,6 +3,7 @@ * @copyright © 2010-2020 PubNub, Inc. */ #import "PNRecordableTestCase.h" +#import "PNSubscribeEventData+Private.h" #import "NSString+PNTest.h" @@ -1387,6 +1388,39 @@ - (void)testItShouldSubscribeToSingleChannelAndReceiveMessageWhenPublished { }]; } +- (void)testItShouldSubscribeToSingleChannelAndReceiveMessageWithUserTimetokenWhenPublished { + NSDictionary *publishedMessage = @{ @"test-message": [self randomizedValuesWithValues:@[@"message"]] }; + NSString *channel = [self channelWithName:@"test-channel1"]; + + + [self subscribeClient:self.client toChannels:@[channel] withPresence:NO]; + [self waitTask:@"waitForDistribution" completionFor:(YHVVCR.cassette.isNewCassette ? 3.f : 0.f)]; + + + [self waitToCompleteIn:self.testCompletionDelay codeBlock:^(dispatch_block_t handler) { + [self addMessageHandlerForClient:self.client + withBlock:^(PubNub *client, PNMessageResult *message, BOOL *remove) { + + if ([message.data.publisher isEqualToString:self.client.currentConfiguration.userID]) { + XCTAssertEqualObjects(message.data.message, publishedMessage); + XCTAssertEqualObjects(message.data.subscription, channel); + XCTAssertEqualObjects(message.data.channel, channel); + XCTAssertEqualObjects(message.data.userTimetoken.timetoken, + @(message.data.timetoken.unsignedIntegerValue - 1)); + XCTAssertNil(message.data.userTimetoken.region); + XCTAssertNotNil(message.data.userTimetoken); + *remove = YES; + + handler(); + } + }]; + + [self.client publish:publishedMessage toChannel:channel withCompletion:^(PNPublishStatus *status) { + XCTAssertFalse(status.isError); + }]; + }]; +} + /** * @brief Follow instructions to simulate server response with "broken" payload. * diff --git a/Tests/Tests/Unit/Core/Subscribe/PNSubscribeTest.m b/Tests/Tests/Unit/Core/Subscribe/PNSubscribeTest.m new file mode 100644 index 000000000..f6b9aae2b --- /dev/null +++ b/Tests/Tests/Unit/Core/Subscribe/PNSubscribeTest.m @@ -0,0 +1,57 @@ +#import "PNRecordableTestCase.h" +#import +#import +#import "PNBaseRequest+Private.h" + + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark Interface declaration + +@interface PNSubscribeTest : PNRecordableTestCase + + +#pragma mark - + + +@end + +NS_ASSUME_NONNULL_END + + +#pragma mark - Tests + +@implementation PNSubscribeTest + + +#pragma mark - VCR configuration + +- (BOOL)shouldSetupVCR { + return NO; +} + +#pragma mark - Tests :: Request + +- (void)testItShouldSetProperRequestValues { + PNSubscribeRequest *request = [PNSubscribeRequest requestWithChannels:@[@"ch-a"] channelGroups:@[@"gr-a"]]; + + id clientTransportMock = [self mockForObject:self.client.subscriptionNetwork]; + id recorded = OCMExpect([clientTransportMock sendRequest:[OCMArg isKindOfClass:[PNTransportRequest class]] + withCompletionBlock:[OCMArg any]]) + .andDo(^(NSInvocation *invocation) { + PNTransportRequest *transportRequest = [self objectForInvocation:invocation argumentAtIndex:1]; + NSLog(@"CALLED"); + + XCTAssertEqual(transportRequest.timeout, self.client.configuration.subscribeMaximumIdleTime); + XCTAssertTrue(transportRequest.cancellable); + XCTAssertFalse(transportRequest.retriable); + }); + + [self waitForObject:clientTransportMock recordedInvocationCall:recorded afterBlock:^{ + [self.client subscribeWithRequest:request]; + }]; +} + +#pragma mark - + +@end diff --git a/VERSION b/VERSION index 1bc788d3b..b7c75422b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.6.0 +5.6.1