From 9b7c1f5bc4e23290e82b4d746207563ab982f873 Mon Sep 17 00:00:00 2001 From: jguz-pubnub Date: Tue, 31 Oct 2023 17:02:46 +0100 Subject: [PATCH] Reusing existing unit tests for old & new implementation --- PubNub.xcodeproj/project.pbxproj | 8 +- ...entEngineSubscriptionSessionStrategy.swift | 2 +- .../Subscription/SubscriptionSession.swift | 4 - .../Routers/SubscribeRouterTests.swift | 399 ++++++++++++------ .../SubscribeRouterWithEventEngineTests.swift | 47 --- .../SubscriptionSessionTests.swift | 140 ++++++ 6 files changed, 416 insertions(+), 184 deletions(-) delete mode 100644 Tests/PubNubTests/Networking/Routers/SubscribeRouterWithEventEngineTests.swift create mode 100644 Tests/PubNubTests/Subscription/SubscriptionSessionTests.swift diff --git a/PubNub.xcodeproj/project.pbxproj b/PubNub.xcodeproj/project.pbxproj index 3eb46ce4..5c562ac2 100644 --- a/PubNub.xcodeproj/project.pbxproj +++ b/PubNub.xcodeproj/project.pbxproj @@ -382,7 +382,7 @@ 3D2D57252A8A1EEC00BEA8CB /* WaitEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D2D57242A8A1EEC00BEA8CB /* WaitEffect.swift */; }; 3D371DE62A4EE20700953D7F /* PubNubEventEngineTestsHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D371DE52A4EE20700953D7F /* PubNubEventEngineTestsHelpers.swift */; }; 3D371DE72A4EE20700953D7F /* PubNubEventEngineTestsHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D371DE52A4EE20700953D7F /* PubNubEventEngineTestsHelpers.swift */; }; - 3D5848A02AEBED5C00C20C92 /* SubscribeRouterWithEventEngineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D58489F2AEBED5C00C20C92 /* SubscribeRouterWithEventEngineTests.swift */; }; + 3D62D6EB2AF1404900EA46F9 /* SubscriptionSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D62D6EA2AF1404900EA46F9 /* SubscriptionSessionTests.swift */; }; 3D8773662A6130EC004A2953 /* Presence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D8773652A6130EC004A2953 /* Presence.swift */; }; 3D8773682A613A58004A2953 /* PresenceTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D8773672A613A58004A2953 /* PresenceTransition.swift */; }; 3D9134972A1216F7000A5124 /* PubNubPushTargetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9134962A1216F7000A5124 /* PubNubPushTargetTests.swift */; }; @@ -954,7 +954,7 @@ 3D2D57222A8A1AF100BEA8CB /* PresenceLeaveRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresenceLeaveRequest.swift; sourceTree = ""; }; 3D2D57242A8A1EEC00BEA8CB /* WaitEffect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitEffect.swift; sourceTree = ""; }; 3D371DE52A4EE20700953D7F /* PubNubEventEngineTestsHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PubNubEventEngineTestsHelpers.swift; sourceTree = ""; }; - 3D58489F2AEBED5C00C20C92 /* SubscribeRouterWithEventEngineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribeRouterWithEventEngineTests.swift; sourceTree = ""; }; + 3D62D6EA2AF1404900EA46F9 /* SubscriptionSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionSessionTests.swift; sourceTree = ""; }; 3D8773652A6130EC004A2953 /* Presence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Presence.swift; sourceTree = ""; }; 3D8773672A613A58004A2953 /* PresenceTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresenceTransition.swift; sourceTree = ""; }; 3D9134962A1216F7000A5124 /* PubNubPushTargetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PubNubPushTargetTests.swift; sourceTree = ""; }; @@ -1217,6 +1217,7 @@ isa = PBXGroup; children = ( 35458BA2230CB3570085B502 /* SubscribeSessionFactoryTests.swift */, + 3D62D6EA2AF1404900EA46F9 /* SubscriptionSessionTests.swift */, ); path = Subscription; sourceTree = ""; @@ -1627,7 +1628,6 @@ 35A6C7B622FBEA7200E97CC5 /* PushRouterTests.swift */, 359287B3231720C20046F7A2 /* PublishRouterTests.swift */, 359287BC23173D490046F7A2 /* SubscribeRouterTests.swift */, - 3D58489F2AEBED5C00C20C92 /* SubscribeRouterWithEventEngineTests.swift */, 3557CDFF237F6380004BBACC /* TimeRouterTests.swift */, 35DA9AB42335491F00867989 /* ObjectsUUIDRouterTests.swift */, 3562DBC22345066F006DFFBC /* ObjectsChannelRouterTests.swift */, @@ -3421,7 +3421,6 @@ 35FE941B22EFE5400051C455 /* EventStreamTests.swift in Sources */, 35FE93C322EF57FA0051C455 /* Session+URLErrorTests.swift in Sources */, 35FE940122EF983A0051C455 /* Session+EndpointErrorTests.swift in Sources */, - 3D5848A02AEBED5C00C20C92 /* SubscribeRouterWithEventEngineTests.swift in Sources */, 3D9B29FA2A65609000C988C9 /* EmitMessagesTests.swift in Sources */, 357AEB8422E6954600C18250 /* Collection+PubNubTests.swift in Sources */, 35D0615223035E4300FDB2F9 /* CryptoTests.swift in Sources */, @@ -3433,6 +3432,7 @@ 35CDFEBC22E789B200F3B9F2 /* ConstantsTests.swift in Sources */, 35CF54A0248D96320099FE81 /* SubscribeRouterTests.swift in Sources */, 35CF54A1248DA6430099FE81 /* ObjectsChannelRouterTests.swift in Sources */, + 3D62D6EB2AF1404900EA46F9 /* SubscriptionSessionTests.swift in Sources */, 3DB56B652A715F7E00FC35A0 /* HeartbeatEffectTests.swift in Sources */, 359C2C1422EBB56A009C3B4B /* Int+PubNubTests.swift in Sources */, 35CDFEC022E7B48000F3B9F2 /* ImportTestResource.swift in Sources */, diff --git a/Sources/PubNub/Subscription/Strategy/EventEngineSubscriptionSessionStrategy.swift b/Sources/PubNub/Subscription/Strategy/EventEngineSubscriptionSessionStrategy.swift index fe71fc4c..1b2c4ca2 100644 --- a/Sources/PubNub/Subscription/Strategy/EventEngineSubscriptionSessionStrategy.swift +++ b/Sources/PubNub/Subscription/Strategy/EventEngineSubscriptionSessionStrategy.swift @@ -71,7 +71,7 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { private func listenForStateUpdates() { subscribeEngine.onStateUpdated = { [weak self] state in - if state.hasTimetoken { + if state is Subscribe.ReceivingState && state.hasTimetoken { self?.previousTokenResponse = state.cursor } } diff --git a/Sources/PubNub/Subscription/SubscriptionSession.swift b/Sources/PubNub/Subscription/SubscriptionSession.swift index 190152b3..1adb7315 100644 --- a/Sources/PubNub/Subscription/SubscriptionSession.swift +++ b/Sources/PubNub/Subscription/SubscriptionSession.swift @@ -34,10 +34,6 @@ public class SubscriptionSession { strategy.uuid } - /// PSV2 feature to subscribe with a custom filter expression. - @available(*, unavailable) - public var filterExpression: String? - private let strategy: any SubscriptionSessionStrategy var previousTokenResponse: SubscribeCursor? { diff --git a/Tests/PubNubTests/Networking/Routers/SubscribeRouterTests.swift b/Tests/PubNubTests/Networking/Routers/SubscribeRouterTests.swift index 54395edc..f26734ec 100644 --- a/Tests/PubNubTests/Networking/Routers/SubscribeRouterTests.swift +++ b/Tests/PubNubTests/Networking/Routers/SubscribeRouterTests.swift @@ -30,6 +30,7 @@ import XCTest class SubscribeRouterTests: XCTestCase { var config: PubNubConfiguration! + var eventEngineEnabledConfig: PubNubConfiguration! let testChannel = "TestChannel" let testAction = PubNubMessageActionBase( @@ -42,38 +43,170 @@ class SubscribeRouterTests: XCTestCase { override func setUp() { super.setUp() + config = PubNubConfiguration( publishKey: "FakeTestString", subscribeKey: "FakeTestString", userId: UUID().uuidString, enableEventEngine: false ) + eventEngineEnabledConfig = PubNubConfiguration( + publishKey: "FakeTestString", + subscribeKey: "FakeTestString", + userId: UUID().uuidString, + enableEventEngine: true + ) } override func tearDown() { config = nil + eventEngineEnabledConfig = nil + super.tearDown() } +} - // MARK: - Endpoint Tests +// MARK: - Endpoint Tests +extension SubscribeRouterTests { func testSubscribe_Router() { + testSubscribe_Router(config: config) + testSubscribe_Router(config: eventEngineEnabledConfig) + } + + func testSubscribe_Router_ValidationError() { + testSubscribe_Router_ValidationError(config: config) + testSubscribe_Router_ValidationError(config: eventEngineEnabledConfig) + } +} + +// MARK: - Message Response + +extension SubscribeRouterTests { + func testSubscribe_Message() { + testSubscribe_Message(config: config) + testSubscribe_Message(config: eventEngineEnabledConfig) + } +} + +// MARK: - Presence Response + +extension SubscribeRouterTests { + func testSubscribe_Presence() { + testSubscribe_Presence(config: config) + testSubscribe_Presence(config: eventEngineEnabledConfig) + } +} + +// MARK: - Signal Response + +extension SubscribeRouterTests { + func testSubscribe_Signal() { + testSubscribe_Signal(config: config) + testSubscribe_Signal(config: eventEngineEnabledConfig) + } +} + +// MARK: - User Object Response + +extension SubscribeRouterTests { + func testSubscribe_UUIDMetadata_Set() { + testSubscribe_UUIDMetadata_Set(config: config) + testSubscribe_UUIDMetadata_Set(config: eventEngineEnabledConfig) + } + + func testSubscribe_UUIDMetadata_Removed() { + testSubscribe_UUIDMetadata_Removed(config: config) + testSubscribe_UUIDMetadata_Removed(config: eventEngineEnabledConfig) + } + + func testSubscribe_ChannelMetadata_Set() { + testSubscribe_ChannelMetadata_Set(config: config) + testSubscribe_ChannelMetadata_Set(config: eventEngineEnabledConfig) + } + + func testSubscribe_ChannelMetadata_Removed() { + testSubscribe_ChannelMetadata_Removed(config: config) + testSubscribe_ChannelMetadata_Removed(config: eventEngineEnabledConfig) + } + + func testSubscribe_Membership_Set() { + testSubscribe_Membership_Set(config: config) + testSubscribe_Membership_Set(config: eventEngineEnabledConfig) + } + + func testSubscribe_Membership_Removed() { + testSubscribe_Membership_Removed(config: config) + testSubscribe_Membership_Removed(config: eventEngineEnabledConfig) + } +} + +// MARK: - Message Action + +extension SubscribeRouterTests { + func testSubscribe_MessageAction_Added() { + testSubscribe_MessageAction_Added(config: config) + testSubscribe_MessageAction_Added(config: eventEngineEnabledConfig) + } + + func testSubscribe_MessageAction_Removed() { + testSubscribe_MessageAction_Removed(config: config) + testSubscribe_MessageAction_Removed(config: eventEngineEnabledConfig) + } +} + +// MARK: - Mixed Response + +extension SubscribeRouterTests { + func testSubscribe_Mixed() { + testSubscribe_Mixed(config: config) + testSubscribe_Mixed(config: eventEngineEnabledConfig) + } +} + +// MARK: - Error Handling + +extension SubscribeRouterTests { + func testInvalidJSONResponse() { + testInvalidJSONResponse(config: config) + testInvalidJSONResponse(config: eventEngineEnabledConfig) + } +} + +// MARK: - Unsubscribe + +extension SubscribeRouterTests { + func testUnsubscribe() { + testUnsubscribe(config: config) + testUnsubscribe(config: eventEngineEnabledConfig) + } + + func testUnsubscribeAll() { + testUnsubscribeAll(config: config) + testUnsubscribeAll(config: eventEngineEnabledConfig) + } +} + +// MARK: - Endpoint Tests (Implementation) + +extension SubscribeRouterTests { + func testSubscribe_Router(config: PubNubConfiguration) { let router = SubscribeRouter(.subscribe( channels: ["TestChannel"], groups: [], timetoken: 0, region: nil, heartbeat: nil, filter: nil, eventEngineEnabled: config.enableEventEngine ), configuration: config) - + XCTAssertEqual(router.endpoint.description, "Subscribe") XCTAssertEqual(router.category, "Subscribe") XCTAssertEqual(router.service, .subscribe) } - - func testSubscribe_Router_ValidationError() { + + func testSubscribe_Router_ValidationError(config: PubNubConfiguration) { let router = SubscribeRouter(.subscribe( channels: [], groups: [], timetoken: 0, region: nil, heartbeat: nil, filter: nil, eventEngineEnabled: config.enableEventEngine ), configuration: config) - + XCTAssertNotEqual( router.validationError?.pubNubError, PubNubError(.invalidEndpointType, router: router) @@ -81,29 +214,29 @@ class SubscribeRouterTests: XCTestCase { } } -// MARK: - Message Response +// MARK: - Message Response (Implementation) extension SubscribeRouterTests { - func testSubscribe_Message() { + func testSubscribe_Message(config: PubNubConfiguration) { let messageExpect = XCTestExpectation(description: "Message Event") let statusExpect = XCTestExpectation(description: "Status Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_message_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveMessage = { [weak self] message in XCTAssertEqual(message.channel, self?.testChannel) XCTAssertEqual(message.payload.stringOptional, "Test Message") - subscription.unsubscribeAll() messageExpect.fulfill() } + listener.didReceiveStatus = { status in if let status = try? status.get(), status == .disconnected { statusExpect.fulfill() @@ -111,40 +244,41 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [messageExpect, statusExpect], timeout: 1.0) } } -// MARK: - Presence Response +// MARK: - Presence Response (Implementation) extension SubscribeRouterTests { - func testSubscribe_Presence() { + func testSubscribe_Presence(config: PubNubConfiguration) { let presenceExpect = XCTestExpectation(description: "Presence Event") let statusExpect = XCTestExpectation(description: "Status Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_presence_success","cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceivePresence = { [weak self] presence in XCTAssertEqual(presence.channel, self?.testChannel) XCTAssertEqual(presence.actions, [ .join(uuids: ["db9c5e39-7c95-40f5-8d71-125765b6f561", "vqwqvae39-7c95-40f5-8d71-25234165142"]), .leave(uuids: ["234vq2343-7c95-40f5-8d71-125765b6f561", "42vvsge39-7c95-40f5-8d71-25234165142"]) ]) - + subscription.unsubscribeAll() presenceExpect.fulfill() } + listener.didReceiveStatus = { status in if let status = try? status.get(), status == .disconnected { statusExpect.fulfill() @@ -152,38 +286,39 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [presenceExpect, statusExpect], timeout: 1.0) } } - -// MARK: - Signal Response + +// MARK: - Signal Response (Implementation) extension SubscribeRouterTests { - func testSubscribe_Signal() { + func testSubscribe_Signal(config: PubNubConfiguration) { let signalExpect = XCTestExpectation(description: "Signal Event") let statusExpect = XCTestExpectation(description: "Status Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_signal_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveSignal = { [weak self] signal in XCTAssertEqual(signal.channel, self?.testChannel) XCTAssertEqual(signal.publisher, "TestUser") XCTAssertEqual(signal.payload.stringOptional, "Test Signal") - + subscription.unsubscribeAll() signalExpect.fulfill() } + listener.didReceiveStatus = { status in if let status = try? status.get(), status == .disconnected { statusExpect.fulfill() @@ -191,29 +326,29 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [signalExpect, statusExpect], timeout: 1.0) } } - -// MARK: - User Object Response + +// MARK: - User Object Response (Implementation) extension SubscribeRouterTests { // swiftlint:disable:next function_body_length cyclomatic_complexity - func testSubscribe_UUIDMetadata_Set() { + func testSubscribe_UUIDMetadata_Set(config: PubNubConfiguration) { let objectExpect = XCTestExpectation(description: "Object Event") let statusExpect = XCTestExpectation(description: "Status Event") let objectListenerExpect = XCTestExpectation(description: "Object Listener Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_uuidSet_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let baseUser = PubNubUUIDMetadataBase(metadataId: "TestUserID", name: "Not Real Name") let patchedObjectUser = PubNubUUIDMetadataBase( metadataId: "TestUserID", @@ -221,10 +356,10 @@ extension SubscribeRouterTests { updated: DateFormatter.iso8601.date(from: "2019-10-06T01:55:50.645685Z"), eTag: "UserUpdateEtag" ) - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveSubscription = { event in switch event { case let .connectionStatusChanged(status): @@ -241,6 +376,7 @@ extension SubscribeRouterTests { XCTFail("Incorrect Event Received \(event)") } } + listener.didReceiveObjectMetadataEvent = { event in switch event { case let .setUUID(changeset): @@ -253,28 +389,28 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [objectExpect, statusExpect, objectListenerExpect], timeout: 1.0) } - + // swiftlint:disable:next cyclomatic_complexity - func testSubscribe_UUIDMetadata_Removed() { + func testSubscribe_UUIDMetadata_Removed(config: PubNubConfiguration) { let objectExpect = XCTestExpectation(description: "Object Event") let statusExpect = XCTestExpectation(description: "Status Event") let objectListenerExpect = XCTestExpectation(description: "Object Listener Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_uuidRemove_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveSubscription = { event in switch event { case let .connectionStatusChanged(status): @@ -288,6 +424,7 @@ extension SubscribeRouterTests { XCTFail("Incorrect Event Received") } } + listener.didReceiveObjectMetadataEvent = { event in switch event { case let .removedUUID(metadataId): @@ -300,25 +437,25 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [objectExpect, statusExpect, objectListenerExpect], timeout: 1.0) } - + // swiftlint:disable:next function_body_length - func testSubscribe_ChannelMetadata_Set() { + func testSubscribe_ChannelMetadata_Set(config: PubNubConfiguration) { let objectExpect = XCTestExpectation(description: "Object Event") let statusExpect = XCTestExpectation(description: "Status Event") let objectListenerExpect = XCTestExpectation(description: "Object Listener Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_channelSet_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let baseChannel = PubNubChannelMetadataBase( metadataId: "TestSpaceID", name: "Not Real Name", type: "someType" ) @@ -329,10 +466,10 @@ extension SubscribeRouterTests { updated: DateFormatter.iso8601.date(from: "2019-10-06T01:55:50.645685Z"), eTag: "SpaceUpdateEtag" ) - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveSubscription = { event in switch event { case let .connectionStatusChanged(status): @@ -349,11 +486,11 @@ extension SubscribeRouterTests { XCTFail("Incorrect Event Received") } } + listener.didReceiveObjectMetadataEvent = { event in switch event { case let .setChannel(changeset): XCTAssertEqual(changeset.metadataId, "TestSpaceID") - subscription.unsubscribeAll() objectListenerExpect.fulfill() default: @@ -362,28 +499,28 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [objectExpect, statusExpect, objectListenerExpect], timeout: 1.0) } - + // swiftlint:disable:next cyclomatic_complexity - func testSubscribe_ChannelMetadata_Removed() { + func testSubscribe_ChannelMetadata_Removed(config: PubNubConfiguration) { let objectExpect = XCTestExpectation(description: "Object Event") let statusExpect = XCTestExpectation(description: "Status Event") let objectListenerExpect = XCTestExpectation(description: "Object Listener Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_channelRemove_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveSubscription = { event in switch event { case let .connectionStatusChanged(status): @@ -397,6 +534,7 @@ extension SubscribeRouterTests { XCTFail("Incorrect Event Received") } } + listener.didReceiveObjectMetadataEvent = { event in switch event { case let .removedChannel(metadataId: metadataId): @@ -409,35 +547,35 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [objectExpect, statusExpect, objectListenerExpect], timeout: 1.0) } - + // swiftlint:disable:next function_body_length cyclomatic_complexity - func testSubscribe_Membership_Set() { + func testSubscribe_Membership_Set(config: PubNubConfiguration) { let objectExpect = XCTestExpectation(description: "Object Event") let statusExpect = XCTestExpectation(description: "Status Event") let objectListenerExpect = XCTestExpectation(description: "Object Listener Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_membershipSet_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let channel = PubNubChannelMetadataBase(metadataId: "TestSpaceID") let uuid = PubNubUUIDMetadataBase(metadataId: "TestUserID") let testMembership = PubNubMembershipMetadataBase( uuidMetadataId: "TestUserID", channelMetadataId: "TestSpaceID", uuid: uuid, channel: channel, custom: ["something": true], updated: DateFormatter.iso8601.date(from: "2019-10-05T23:35:38.457823306Z"), eTag: "TestETag" ) - + let listener = SubscriptionListener() + listener.didReceiveSubscription = { event in switch event { case let .connectionStatusChanged(status): @@ -451,6 +589,7 @@ extension SubscribeRouterTests { XCTFail("Incorrect Event Received \(event)") } } + listener.didReceiveObjectMetadataEvent = { event in switch event { case let .setMembership(membership): @@ -463,34 +602,35 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [objectExpect, statusExpect, objectListenerExpect], timeout: 1.0) } - + // swiftlint:disable:next function_body_length cyclomatic_complexity - func testSubscribe_Membership_Removed() { + func testSubscribe_Membership_Removed(config: PubNubConfiguration) { let objectExpect = XCTestExpectation(description: "Object Event") let statusExpect = XCTestExpectation(description: "Status Event") let objectListenerExpect = XCTestExpectation(description: "Object Listener Event") + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_membershipRemove_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let channel = PubNubChannelMetadataBase(metadataId: "TestSpaceID") let uuid = PubNubUUIDMetadataBase(metadataId: "TestUserID") let testMembership = PubNubMembershipMetadataBase( uuidMetadataId: "TestUserID", channelMetadataId: "TestSpaceID", uuid: uuid, channel: channel, updated: DateFormatter.iso8601.date(from: "2019-10-05T23:35:38.457823306Z"), eTag: "TestETag" ) - + let listener = SubscriptionListener() + listener.didReceiveSubscription = { event in switch event { case let .connectionStatusChanged(status): @@ -504,6 +644,7 @@ extension SubscribeRouterTests { XCTFail("Incorrect Event Received \(event)") } } + listener.didReceiveObjectMetadataEvent = { event in switch event { case let .removedMembership(membership): @@ -516,32 +657,32 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [objectExpect, statusExpect, objectListenerExpect], timeout: 1.0) } } - -// MARK: - Message Action + +// MARK: - Message Action (Implementation) extension SubscribeRouterTests { // swiftlint:disable:next cyclomatic_complexity - func testSubscribe_MessageAction_Added() { + func testSubscribe_MessageAction_Added(config: PubNubConfiguration) { let actionExpect = XCTestExpectation(description: "Message Action Event") let statusExpect = XCTestExpectation(description: "Status Event") let actionListenerExpect = XCTestExpectation(description: "Action Listener Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_addMessageAction_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveSubscription = { [weak self] event in switch event { case let .connectionStatusChanged(status): @@ -555,6 +696,7 @@ extension SubscribeRouterTests { XCTFail("Incorrect Event Received \(event)") } } + listener.didReceiveMessageAction = { [weak self] event in switch event { case let .added(action): @@ -567,28 +709,28 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [actionExpect, statusExpect, actionListenerExpect], timeout: 1.0) } - + // swiftlint:disable:next cyclomatic_complexity function_body_length - func testSubscribe_MessageAction_Removed() { + func testSubscribe_MessageAction_Removed(config: PubNubConfiguration) { let actionExpect = XCTestExpectation(description: "Message Action Event") let statusExpect = XCTestExpectation(description: "Status Event") let actionListenerExpect = XCTestExpectation(description: "Action Listener Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_removeMessageAction_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveSubscription = { [weak self] event in switch event { case let .connectionStatusChanged(status): @@ -614,39 +756,41 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [actionExpect, statusExpect, actionListenerExpect], timeout: 1.0) } } -// MARK: - Mixed Response - +// MARK: - Mixed Response (Implementation) + extension SubscribeRouterTests { - func testSubscribe_Mixed() { + func testSubscribe_Mixed(config: PubNubConfiguration) { let messageExpect = XCTestExpectation(description: "Message Event") let presenceExpect = XCTestExpectation(description: "Presence Event") let signalExpect = XCTestExpectation(description: "Signal Event") let statusExpect = XCTestExpectation(description: "Status Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_mixed_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - + let listener = SubscriptionListener() var payloadCount = 0 + listener.didReceiveSubscription = { _ in payloadCount += 1 if payloadCount == 3 { subscription.unsubscribeAll() } } + listener.didReceiveMessage = { [weak self] message in XCTAssertEqual(message.channel, self?.testChannel) XCTAssertEqual(message.payload.stringOptional, "Test Message") @@ -669,37 +813,37 @@ extension SubscribeRouterTests { } subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [signalExpect, statusExpect], timeout: 1.0) } } - -// MARK: - Error Handling + +// MARK: - Error Handling (Implementation) extension SubscribeRouterTests { - func testInvalidJSONResponse() { + func testInvalidJSONResponse(config: PubNubConfiguration) { // swiftlint:disable:next line_length let corruptBase64Response = "eyJ0Ijp7InQiOiIxNTkxMjE4MzQ0MTUyNjM1MCIsInIiOjF9LCJtIjpbeyJhIjoiMyIsImYiOjUxMiwicCI6eyJ0IjoiMTU5MTIxODM0NDE1NTQyMDAiLCJyIjoxfSwiayI6ImRlbW8tMzYiLCJjIjoic3dpZnRJbnZhbGlkSlNPTi7/IiwiZCI6ImhlbGxvIiwiYiI6InN3aWZ0SW52YWxpZEpTT04uKiJ9XX0=" - + guard let corruptedData = Data(base64Encoded: corruptBase64Response) else { return XCTFail("Could not create Data from String") } - + let errorExpect = XCTestExpectation(description: "Error Event") - + guard let session = try? MockURLSession.mockSession( for: ["cancelled"], raw: [corruptedData] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveSubscription = { event in if case let .subscribeError(error) = event { XCTAssertEqual(error.reason, .jsonDataDecodingFailure) @@ -707,33 +851,32 @@ extension SubscribeRouterTests { errorExpect.fulfill() } } - subscription.add(listener) subscription.subscribe(to: [testChannel]) - + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [errorExpect], timeout: 1.0) } } - -// MARK: - Unsubscribe + +// MARK: - Unsubscribe (Implementation) extension SubscribeRouterTests { - func testUnsubscribe() { + func testUnsubscribe(config: PubNubConfiguration) { let statusExpect = XCTestExpectation(description: "Status Event") statusExpect.expectedFulfillmentCount = 2 - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_mixed_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) - let listener = SubscriptionListener() + listener.didReceiveSubscription = { [unowned self] event in switch event { case let .connectionStatusChanged(status): @@ -741,7 +884,7 @@ extension SubscribeRouterTests { case .connected: subscription.unsubscribe(from: [self.testChannel]) XCTAssertEqual(subscription.subscribedChannels, []) - + statusExpect.fulfill() case .connectionError: statusExpect.fulfill() @@ -755,27 +898,27 @@ extension SubscribeRouterTests { } } subscription.add(listener) - subscription.subscribe(to: [testChannel]) + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) - + defer { listener.cancel() } wait(for: [statusExpect], timeout: 1.0) } - - func testUnsubscribeAll() { + + func testUnsubscribeAll(config: PubNubConfiguration) { let statusExpect = XCTestExpectation(description: "Status Event") - + guard let session = try? MockURLSession.mockSession( for: ["subscription_handshake_success", "subscription_mixed_success", "cancelled"] ).session else { return XCTFail("Could not create mock url session") } - + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) let otherChannel = "OtherChannel" - let listener = SubscriptionListener() + listener.didReceiveSubscription = { event in switch event { case let .connectionStatusChanged(status): @@ -796,14 +939,14 @@ extension SubscribeRouterTests { } } subscription.add(listener) - subscription.subscribe(to: [testChannel, otherChannel]) + XCTAssertTrue(subscription.subscribedChannels.contains(testChannel)) XCTAssertTrue(subscription.subscribedChannels.contains(otherChannel)) - + defer { listener.cancel() } wait(for: [statusExpect], timeout: 1.0) } - + // swiftlint:disable:next file_length } diff --git a/Tests/PubNubTests/Networking/Routers/SubscribeRouterWithEventEngineTests.swift b/Tests/PubNubTests/Networking/Routers/SubscribeRouterWithEventEngineTests.swift deleted file mode 100644 index b01a3b3f..00000000 --- a/Tests/PubNubTests/Networking/Routers/SubscribeRouterWithEventEngineTests.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// SubscribeRouterWithEventEngineTests.swift -// -// PubNub Real-time Cloud-Hosted Push API and Push Notification Client Frameworks -// Copyright © 2023 PubNub Inc. -// https://www.pubnub.com/ -// https://www.pubnub.com/terms -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import Foundation - -@testable import PubNub - -class SubscribeRouterWithEventEngineTests: SubscribeRouterTests { - override func setUp() { - super.setUp() - config = PubNubConfiguration( - publishKey: "FakeTestString", - subscribeKey: "FakeTestString", - userId: UUID().uuidString, - enableEventEngine: true - ) - } - - func test_SubscribeRouterWithEventEngineEnabled() { - // This class reuses all test cases from the parent class with different PubNubConfiguration. - // This empty replacement method was added so that the XCTest framework can also run these inherited test cases - } -} diff --git a/Tests/PubNubTests/Subscription/SubscriptionSessionTests.swift b/Tests/PubNubTests/Subscription/SubscriptionSessionTests.swift new file mode 100644 index 00000000..fa21ef95 --- /dev/null +++ b/Tests/PubNubTests/Subscription/SubscriptionSessionTests.swift @@ -0,0 +1,140 @@ +// +// SubscriptionSessionTests.swift +// +// PubNub Real-time Cloud-Hosted Push API and Push Notification Client Frameworks +// Copyright © 2023 PubNub Inc. +// https://www.pubnub.com/ +// https://www.pubnub.com/terms +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import XCTest + +@testable import PubNub + +class SubscriptionSessionTests: XCTestCase { + var config: PubNubConfiguration! + var eventEngineEnabledConfig: PubNubConfiguration! + + let testChannel = "TestChannel" + + override func setUp() { + super.setUp() + + config = PubNubConfiguration( + publishKey: "FakeTestString", + subscribeKey: "FakeTestString", + userId: UUID().uuidString + ) + eventEngineEnabledConfig = PubNubConfiguration( + publishKey: "FakeTestString", + subscribeKey: "FakeTestString", + userId: UUID().uuidString, + enableEventEngine: true + ) + } + + override func tearDown() { + config = nil + eventEngineEnabledConfig = nil + + super.tearDown() + } + + func testSubscriptionSession_PreviousTimetokenResponse() { + test_PreviousTimetokenResponse(configuration: config) + test_PreviousTimetokenResponse(configuration: eventEngineEnabledConfig) + } + + func testSubscriptionSession_PreviousTimetokenResponseOnError() { + test_PreviousTimetokenResponseOnError(configuration: config) + test_PreviousTimetokenResponseOnError(configuration: eventEngineEnabledConfig) + } +} + +fileprivate extension SubscriptionSessionTests { + func test_PreviousTimetokenResponse(configuration config: PubNubConfiguration) { + let messageExpect = XCTestExpectation(description: "Message Event") + let statusExpect = XCTestExpectation(description: "Status Event") + + guard let session = try? MockURLSession.mockSession( + for: ["subscription_handshake_success", "subscription_message_success", "cancelled"] + ).session else { + return XCTFail("Could not create mock url session") + } + + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) + let listener = SubscriptionListener() + + listener.didReceiveMessage = { message in + XCTAssertEqual( + subscription.previousTokenResponse, + SubscribeCursor(timetoken: 15614817397807903, region: 2) + ) + subscription.unsubscribeAll() + messageExpect.fulfill() + } + listener.didReceiveStatus = { status in + if let status = try? status.get(), status == .connected { + XCTAssertEqual( + subscription.previousTokenResponse, + SubscribeCursor(timetoken: 16873352451141050, region: 42) + ) + statusExpect.fulfill() + } + } + + subscription.add(listener) + subscription.subscribe(to: [testChannel]) + + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) + + defer { listener.cancel() } + wait(for: [messageExpect, statusExpect], timeout: 1.0) + } + + func test_PreviousTimetokenResponseOnError(configuration config: PubNubConfiguration) { + let statusExpect = XCTestExpectation(description: "Status Event") + + guard let session = try? MockURLSession.mockSession( + for: ["badURL", "cancelled"] + ).session else { + return XCTFail("Could not create mock url session") + } + + let subscription = SubscribeSessionFactory.shared.getSession(from: config, with: session) + let listener = SubscriptionListener() + + listener.didReceiveStatus = { status in + if case .failure(_) = status { + XCTAssertNil(subscription.previousTokenResponse) + statusExpect.fulfill() + } + } + + subscription.add(listener) + subscription.subscribe(to: [testChannel], at: SubscribeCursor(timetoken: 123456, region: 1)) + + XCTAssertEqual(subscription.subscribedChannels, [testChannel]) + + defer { listener.cancel() } + wait(for: [statusExpect], timeout: 1.0) + } +}