From 77f0e5d1e6c0c134c6e00c2b2a12473eeb1b5a45 Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Sun, 13 Sep 2020 16:34:29 -0700 Subject: [PATCH 01/14] initialize networkStatus PR --- ...ataStoreCategory+HubPayloadEventName.swift | 4 ++++ .../Sync/Events/NetworkStatusEvent.swift | 16 +++++++++++++++ .../Sync/RemoteSyncEngine.swift | 20 +++++++++++++++++++ .../project.pbxproj | 4 ++++ 4 files changed, 44 insertions(+) create mode 100644 AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Events/NetworkStatusEvent.swift diff --git a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift index ce26faf0a7..25a0ea0d3d 100644 --- a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift +++ b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift @@ -37,4 +37,8 @@ public extension HubPayload.EventName.DataStore { /// Dispatched when DataStore is about to start sync queries /// HubPayload `syncQueriesStartedEvent` contains an array of each model's `name` static let syncQueriesStarted = "DataStore.syncQueriesStarted" + + /// Dispatched when DataStore starts and everytime network status changes + /// HubPayload `NetworkStatusEvent` contains a boolean value `active` to norify network staus + static let networkStatus = "DataStore.networkStatus" } diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Events/NetworkStatusEvent.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Events/NetworkStatusEvent.swift new file mode 100644 index 0000000000..13a0f77c51 --- /dev/null +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Events/NetworkStatusEvent.swift @@ -0,0 +1,16 @@ +// +// Copyright 2018-2020 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +/// Used as HubPayload for the `NetworkStatus` +public struct NetworkStatusEvent { + /// status of network: true if network is active + public let active: Bool + + public init(active: Bool) { + self.active = active + } +} diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift index dee1b11a29..9fb3f5ac90 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift @@ -48,6 +48,7 @@ class RemoteSyncEngine: RemoteSyncEngineBehavior { private var stateMachineSink: AnyCancellable? var networkReachabilityPublisher: AnyPublisher? + private var networkReachabilitySink: AnyCancellable? var mutationRetryNotifier: MutationRetryNotifier? let requestRetryablePolicy: RequestRetryablePolicy var currentAttemptNumber: Int @@ -184,6 +185,18 @@ class RemoteSyncEngine: RemoteSyncEngineBehavior { self.api = api self.auth = auth + if networkReachabilityPublisher == nil { + if let reachability = api as? APICategoryReachabilityBehavior { + do { + networkReachabilityPublisher = try reachability.reachabilityPublisher() + networkReachabilitySink = networkReachabilityPublisher? + .sink(receiveValue: onReceiveNetworkStatus(networkStatus:)) + } catch { + log.error("\(#function): Unable to listen on reachability: \(error)") + } + } + } + remoteSyncTopicPublisher.send(.storageAdapterAvailable) stateMachine.notify(action: .receivedStart) } @@ -327,6 +340,13 @@ class RemoteSyncEngine: RemoteSyncEngineBehavior { stateMachine.notify(action: .notifiedSyncStarted) } + private func onReceiveNetworkStatus(networkStatus: ReachabilityUpdate) { + let networkStatusEvent = NetworkStatusEvent(active: networkStatus.isOnline) + let networkStatusEventPayload = HubPayload(eventName: HubPayload.EventName.DataStore.networkStatus, + data: networkStatusEvent) + Amplify.Hub.dispatch(to: .dataStore, payload: networkStatusEventPayload) + } + func reset(onComplete: () -> Void) { let group = DispatchGroup() diff --git a/AmplifyPlugins/DataStore/DataStoreCategoryPlugin.xcodeproj/project.pbxproj b/AmplifyPlugins/DataStore/DataStoreCategoryPlugin.xcodeproj/project.pbxproj index f8392a5687..0d15b000a3 100755 --- a/AmplifyPlugins/DataStore/DataStoreCategoryPlugin.xcodeproj/project.pbxproj +++ b/AmplifyPlugins/DataStore/DataStoreCategoryPlugin.xcodeproj/project.pbxproj @@ -105,6 +105,7 @@ D8D900A4249DB599004042E7 /* QuerySort+SQLite.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D900A3249DB599004042E7 /* QuerySort+SQLite.swift */; }; D8E9992425013C2F0006170A /* DataStoreHubEventsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E9992325013C2F0006170A /* DataStoreHubEventsTests.swift */; }; D8E99926250142790006170A /* HubEventsIntegrationTestBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E99925250142790006170A /* HubEventsIntegrationTestBase.swift */; }; + D8FF6207250EB4C3000BFB4B /* NetworkStatusEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FF6206250EB4C3000BFB4B /* NetworkStatusEvent.swift */; }; FA0427C82396C27400D25AB0 /* SyncEngineStartupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0427C72396C27400D25AB0 /* SyncEngineStartupTests.swift */; }; FA0427CA2396C35500D25AB0 /* InitialSyncOrchestrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0427C92396C35500D25AB0 /* InitialSyncOrchestrator.swift */; }; FA0427CC2396C7E400D25AB0 /* InitialSyncOrchestratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0427CB2396C7E400D25AB0 /* InitialSyncOrchestratorTests.swift */; }; @@ -323,6 +324,7 @@ D8D900A3249DB599004042E7 /* QuerySort+SQLite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QuerySort+SQLite.swift"; sourceTree = ""; }; D8E9992325013C2F0006170A /* DataStoreHubEventsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStoreHubEventsTests.swift; sourceTree = ""; }; D8E99925250142790006170A /* HubEventsIntegrationTestBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HubEventsIntegrationTestBase.swift; sourceTree = ""; }; + D8FF6206250EB4C3000BFB4B /* NetworkStatusEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkStatusEvent.swift; sourceTree = ""; }; DCC3AA75D77D0DB916EC42DB /* Pods-HostApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HostApp.release.xcconfig"; path = "Target Support Files/Pods-HostApp/Pods-HostApp.release.xcconfig"; sourceTree = ""; }; EA320D973669D3843FDF755E /* Pods_HostApp_AWSDataStoreCategoryPluginAuthIntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HostApp_AWSDataStoreCategoryPluginAuthIntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA53DF78CC578B7C81E72D83 /* Pods-AWSDataStoreCategoryPlugin-AWSDataStoreCategoryPluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AWSDataStoreCategoryPlugin-AWSDataStoreCategoryPluginTests.debug.xcconfig"; path = "Target Support Files/Pods-AWSDataStoreCategoryPlugin-AWSDataStoreCategoryPluginTests/Pods-AWSDataStoreCategoryPlugin-AWSDataStoreCategoryPluginTests.debug.xcconfig"; sourceTree = ""; }; @@ -664,6 +666,7 @@ isa = PBXGroup; children = ( D838AB4524FF268400BF4940 /* SyncQueriesStartedEvent.swift */, + D8FF6206250EB4C3000BFB4B /* NetworkStatusEvent.swift */, D838AB4324FF264600BF4940 /* OutboxStatusEvent.swift */, ); path = Events; @@ -1513,6 +1516,7 @@ FA5D4CEF238AFCBC00D2F54A /* AWSDataStorePlugin+DataStoreSubscribeBehavior.swift in Sources */, FAAFAF3923905F35002CF932 /* MutationEventPublisher.swift in Sources */, 6BB93F07244BA44B00ED1FC3 /* MutationEventClearState.swift in Sources */, + D8FF6207250EB4C3000BFB4B /* NetworkStatusEvent.swift in Sources */, 2149E5C82388684F00873955 /* SQLStatement.swift in Sources */, FAED5742238B52CE008EBED8 /* ModelStorageBehavior.swift in Sources */, 2149E5C62388684F00873955 /* StorageEngineAdapter.swift in Sources */, From 336ff47b3415519b5fbcee39fc7a3601e507be35 Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Sun, 13 Sep 2020 16:41:10 -0700 Subject: [PATCH 02/14] fixed an indentation --- .../AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift index 9fb3f5ac90..761552662b 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift @@ -343,7 +343,7 @@ class RemoteSyncEngine: RemoteSyncEngineBehavior { private func onReceiveNetworkStatus(networkStatus: ReachabilityUpdate) { let networkStatusEvent = NetworkStatusEvent(active: networkStatus.isOnline) let networkStatusEventPayload = HubPayload(eventName: HubPayload.EventName.DataStore.networkStatus, - data: networkStatusEvent) + data: networkStatusEvent) Amplify.Hub.dispatch(to: .dataStore, payload: networkStatusEventPayload) } From 44c98f51a236677592a9caf5d61b2bdcd9a08269 Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Mon, 14 Sep 2020 15:39:44 -0700 Subject: [PATCH 03/14] fixed unit test --- .../Sync/RemoteSyncEngine.swift | 17 ++++++++--------- .../Sync/RemoteSyncEngineTests.swift | 9 +++++---- .../Mocks/MockAPICategoryPlugin.swift | 5 ++++- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift index 761552662b..83f7825cd9 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift @@ -185,15 +185,14 @@ class RemoteSyncEngine: RemoteSyncEngineBehavior { self.api = api self.auth = auth - if networkReachabilityPublisher == nil { - if let reachability = api as? APICategoryReachabilityBehavior { - do { - networkReachabilityPublisher = try reachability.reachabilityPublisher() - networkReachabilitySink = networkReachabilityPublisher? - .sink(receiveValue: onReceiveNetworkStatus(networkStatus:)) - } catch { - log.error("\(#function): Unable to listen on reachability: \(error)") - } + if networkReachabilityPublisher == nil, + let reachability = api as? APICategoryReachabilityBehavior { + do { + networkReachabilityPublisher = try reachability.reachabilityPublisher() + networkReachabilitySink = networkReachabilityPublisher? + .sink(receiveValue: onReceiveNetworkStatus(networkStatus:)) + } catch { + log.error("\(#function): Unable to listen on reachability: \(error)") } } diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift index b79477b94d..86ef632346 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift @@ -25,6 +25,7 @@ class RemoteSyncEngineTests: XCTestCase { override func setUp() { super.setUp() + apiPlugin = MockAPICategoryPlugin() MockAWSInitialSyncOrchestrator.reset() storageAdapter = MockSQLiteStorageEngineAdapter() let mockOutgoingMutationQueue = MockOutgoingMutationQueue() @@ -118,7 +119,7 @@ class RemoteSyncEngineTests: XCTestCase { MockAWSInitialSyncOrchestrator.setResponseOnSync(result: .failure(DataStoreError.internalOperation("forceError", "none", nil))) - remoteSyncEngine.start() + remoteSyncEngine.start(api: apiPlugin) wait(for: [storageAdapterAvailable, subscriptionsPaused, @@ -177,7 +178,7 @@ class RemoteSyncEngineTests: XCTestCase { } }) - remoteSyncEngine.start() + remoteSyncEngine.start(api: apiPlugin) wait(for: [storageAdapterAvailable, subscriptionsPaused, @@ -248,7 +249,7 @@ class RemoteSyncEngineTests: XCTestCase { } }) - remoteSyncEngine.start() + remoteSyncEngine.start(api: apiPlugin) wait(for: [storageAdapterAvailable, subscriptionsPaused, @@ -325,7 +326,7 @@ class RemoteSyncEngineTests: XCTestCase { } }) - remoteSyncEngine.start() + remoteSyncEngine.start(api: apiPlugin) wait(for: [storageAdapterAvailable, subscriptionsPaused, diff --git a/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift b/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift index 5f26a33df2..3a612e9b71 100644 --- a/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift +++ b/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift @@ -9,7 +9,7 @@ import Amplify import Combine import Foundation -class MockAPICategoryPlugin: MessageReporter, APICategoryPlugin { +class MockAPICategoryPlugin: MessageReporter, APICategoryPlugin, APICategoryReachabilityBehavior { var responders = [ResponderKeys: Any]() // MARK: - Properties @@ -27,6 +27,9 @@ class MockAPICategoryPlugin: MessageReporter, APICategoryPlugin { listeners = [] onComplete() } + +// func reachabilityPublisher() throws -> AnyPublisher? + // MARK: - Request-based GraphQL methods From 7394116c230c99553a1195b2e2e5bfe5c6e3e441 Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Mon, 14 Sep 2020 20:42:49 -0700 Subject: [PATCH 04/14] added ready but not yet implemented --- .../DataStoreCategory+HubPayloadEventName.swift | 3 +++ .../DataStoreHubEventsTests.swift | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift index 25a0ea0d3d..d4abf0d915 100644 --- a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift +++ b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift @@ -41,4 +41,7 @@ public extension HubPayload.EventName.DataStore { /// Dispatched when DataStore starts and everytime network status changes /// HubPayload `NetworkStatusEvent` contains a boolean value `active` to norify network staus static let networkStatus = "DataStore.networkStatus" + + /// Dispatched when DataStore is ready, at this point, all data is available + static let ready = "DataStore.ready" } diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift index 2c06a5377f..13e5718ecb 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift @@ -28,11 +28,20 @@ class DataStoreHubEventTests: HubEventsIntegrationTestBase { /// - outboxStatus received, payload should be {isEmpty: true} func testDataStoreConfiguredDispatchesHubEvents() throws { + let networkStatusReceived = expectation(description: "networkStatus received") let subscriptionsEstablishedReceived = expectation(description: "subscriptionsEstablished received") let syncQueriesStartedReceived = expectation(description: "syncQueriesStarted received") let outboxStatusReceived = expectation(description: "outboxStatus received") let hubListener = Amplify.Hub.listen(to: .dataStore) { payload in + if payload.eventName == HubPayload.EventName.DataStore.networkStatus { + guard let networkStatusEvent = payload.data as? NetworkStatusEvent else { + XCTFail("Failed to cast payload data as NetworkStatusEvent") + return + } + XCTAssertEqual(networkStatusEvent.active, true) + } + if payload.eventName == HubPayload.EventName.DataStore.subscriptionsEstablished { XCTAssertNil(payload.data) subscriptionsEstablishedReceived.fulfill() From f2c90c3d8e2d5b072db4e0792ae2e9df88d47e17 Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Wed, 16 Sep 2020 09:52:20 -0700 Subject: [PATCH 05/14] ready for review --- .../DataStore/DataStoreCategory+HubPayloadEventName.swift | 3 --- .../Sync/RemoteSyncEngineTests.swift | 5 +++++ AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift | 3 --- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift index d4abf0d915..25a0ea0d3d 100644 --- a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift +++ b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift @@ -41,7 +41,4 @@ public extension HubPayload.EventName.DataStore { /// Dispatched when DataStore starts and everytime network status changes /// HubPayload `NetworkStatusEvent` contains a boolean value `active` to norify network staus static let networkStatus = "DataStore.networkStatus" - - /// Dispatched when DataStore is ready, at this point, all data is available - static let ready = "DataStore.ready" } diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift index 86ef632346..b550231a79 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift @@ -21,6 +21,11 @@ class RemoteSyncEngineTests: XCTestCase { var remoteSyncEngine: RemoteSyncEngine! var mockRequestRetryablePolicy: MockRequestRetryablePolicy! + var reachabilityPublisher: PassthroughSubject! + var publisher: AnyPublisher { + return reachabilityPublisher.eraseToAnyPublisher() + } + let defaultAsyncWaitTimeout = 2.0 override func setUp() { diff --git a/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift b/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift index 3a612e9b71..d1fbc927bd 100644 --- a/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift +++ b/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift @@ -27,9 +27,6 @@ class MockAPICategoryPlugin: MessageReporter, APICategoryPlugin, APICategoryReac listeners = [] onComplete() } - -// func reachabilityPublisher() throws -> AnyPublisher? - // MARK: - Request-based GraphQL methods From 1d96b55691de534324f8f1256bc6517cad074982 Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Wed, 16 Sep 2020 09:54:12 -0700 Subject: [PATCH 06/14] removed one publisher --- .../Sync/RemoteSyncEngineTests.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift index b550231a79..86ef632346 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/RemoteSyncEngineTests.swift @@ -21,11 +21,6 @@ class RemoteSyncEngineTests: XCTestCase { var remoteSyncEngine: RemoteSyncEngine! var mockRequestRetryablePolicy: MockRequestRetryablePolicy! - var reachabilityPublisher: PassthroughSubject! - var publisher: AnyPublisher { - return reachabilityPublisher.eraseToAnyPublisher() - } - let defaultAsyncWaitTimeout = 2.0 override func setUp() { From 20294d3005643f94c44013439da218566d5f984f Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Thu, 17 Sep 2020 21:55:54 -0700 Subject: [PATCH 07/14] fixed a typo --- .../DataStore/DataStoreCategory+HubPayloadEventName.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift index 25a0ea0d3d..e65f16ce3a 100644 --- a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift +++ b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift @@ -39,6 +39,6 @@ public extension HubPayload.EventName.DataStore { static let syncQueriesStarted = "DataStore.syncQueriesStarted" /// Dispatched when DataStore starts and everytime network status changes - /// HubPayload `NetworkStatusEvent` contains a boolean value `active` to norify network staus + /// HubPayload `NetworkStatusEvent` contains a boolean value `active` to notify network staus static let networkStatus = "DataStore.networkStatus" } From 6cb87f10cb387daf98f1cdd0cc427d6da1fc370b Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Mon, 21 Sep 2020 14:35:19 -0700 Subject: [PATCH 08/14] updated passthroughSubject to CurrentValueSubject in NetworkReachabilityNotifier --- .../Reachability/NetworkReachabilityNotifier.swift | 2 +- .../Sync/RemoteSyncEngine.swift | 1 + .../DataStoreHubEventsTests.swift | 8 ++++++-- .../TestSupport/HubEventsIntegrationTestBase.swift | 6 ++++-- AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/AmplifyPlugins/API/AWSAPICategoryPlugin/Reachability/NetworkReachabilityNotifier.swift b/AmplifyPlugins/API/AWSAPICategoryPlugin/Reachability/NetworkReachabilityNotifier.swift index 00b1c82c0d..4877bb4401 100644 --- a/AmplifyPlugins/API/AWSAPICategoryPlugin/Reachability/NetworkReachabilityNotifier.swift +++ b/AmplifyPlugins/API/AWSAPICategoryPlugin/Reachability/NetworkReachabilityNotifier.swift @@ -15,7 +15,7 @@ class NetworkReachabilityNotifier { private var reachability: NetworkReachabilityProviding? private var allowsCellularAccess = true - let reachabilityPublisher = PassthroughSubject() + let reachabilityPublisher = CurrentValueSubject(ReachabilityUpdate(isOnline: false)) var publisher: AnyPublisher { return reachabilityPublisher.eraseToAnyPublisher() } diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift index 83f7825cd9..f476e13940 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift @@ -191,6 +191,7 @@ class RemoteSyncEngine: RemoteSyncEngineBehavior { networkReachabilityPublisher = try reachability.reachabilityPublisher() networkReachabilitySink = networkReachabilityPublisher? .sink(receiveValue: onReceiveNetworkStatus(networkStatus:)) + log.info("reachability sink got set up") } catch { log.error("\(#function): Unable to listen on reachability: \(error)") } diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift index 13e5718ecb..947ab79646 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift @@ -40,8 +40,9 @@ class DataStoreHubEventTests: HubEventsIntegrationTestBase { return } XCTAssertEqual(networkStatusEvent.active, true) + networkStatusReceived.fulfill() } - + if payload.eventName == HubPayload.EventName.DataStore.subscriptionsEstablished { XCTAssertNil(payload.data) subscriptionsEstablishedReceived.fulfill() @@ -71,6 +72,9 @@ class DataStoreHubEventTests: HubEventsIntegrationTestBase { return } - waitForExpectations(timeout: networkTimeout, handler: nil) + startAmplify() + + waitForExpectations(timeout: 10, handler: nil) + Amplify.Hub.removeListener(hubListener) } } diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/TestSupport/HubEventsIntegrationTestBase.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/TestSupport/HubEventsIntegrationTestBase.swift index 57b5dd6d3c..32974113c6 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/TestSupport/HubEventsIntegrationTestBase.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/TestSupport/HubEventsIntegrationTestBase.swift @@ -21,9 +21,11 @@ class HubEventsIntegrationTestBase: XCTestCase { override func setUp() { super.setUp() - continueAfterFailure = false + Amplify.reset() + } + func startAmplify() { let bundle = Bundle(for: type(of: self)) guard let configFile = bundle.url(forResource: "amplifyconfiguration", withExtension: "json") else { XCTFail("Could not get URL for amplifyconfiguration.json from \(bundle)") @@ -33,8 +35,8 @@ class HubEventsIntegrationTestBase: XCTestCase { do { let configData = try Data(contentsOf: configFile) let amplifyConfig = try JSONDecoder().decode(AmplifyConfiguration.self, from: configData) - try Amplify.add(plugin: AWSAPIPlugin(modelRegistration: TestModelRegistration())) try Amplify.add(plugin: AWSDataStorePlugin(modelRegistration: TestModelRegistration())) + try Amplify.add(plugin: AWSAPIPlugin(modelRegistration: TestModelRegistration())) try Amplify.configure(amplifyConfig) } catch { XCTFail(String(describing: error)) diff --git a/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift b/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift index d1fbc927bd..0f0039f2c5 100644 --- a/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift +++ b/AmplifyTestCommon/Mocks/MockAPICategoryPlugin.swift @@ -109,7 +109,7 @@ class MockAPICategoryPlugin: MessageReporter, APICategoryPlugin, APICategoryReac @available(iOS 13.0, *) public func reachabilityPublisher() -> AnyPublisher? { - return nil + return Just(ReachabilityUpdate(isOnline: true)).eraseToAnyPublisher() } // MARK: - REST methods From 77c33d955665dc8ee93401d97e564dac5a59e3bc Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Mon, 28 Sep 2020 15:34:17 -0700 Subject: [PATCH 09/14] updated ReachabilityNotifierTests --- .../NetworkReachabilityNotifierTests.swift | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/AmplifyPlugins/API/AWSAPICategoryPluginTests/Reachability/NetworkReachabilityNotifierTests.swift b/AmplifyPlugins/API/AWSAPICategoryPluginTests/Reachability/NetworkReachabilityNotifierTests.swift index 8da1b1fdc2..f4680176d9 100644 --- a/AmplifyPlugins/API/AWSAPICategoryPluginTests/Reachability/NetworkReachabilityNotifierTests.swift +++ b/AmplifyPlugins/API/AWSAPICategoryPluginTests/Reachability/NetworkReachabilityNotifierTests.swift @@ -32,11 +32,16 @@ class NetworkReachabilityNotifierTests: XCTestCase { func testWifiConnectivity() { MockReachability.iConnection = .wifi let expect = expectation(description: ".sink receives value") + var values = [Bool]() let cancellable = notifier.publisher.sink(receiveCompletion: { _ in XCTFail("Not expecting any error") }, receiveValue: { value in - XCTAssert(value.isOnline) - expect.fulfill() + values.append(value.isOnline) + if values.count == 2 { + XCTAssertFalse(values[0]) + XCTAssertTrue(values[1]) + expect.fulfill() + } }) notification = Notification.init(name: .reachabilityChanged) NotificationCenter.default.post(notification) @@ -44,14 +49,20 @@ class NetworkReachabilityNotifierTests: XCTestCase { waitForExpectations(timeout: 1.0) cancellable.cancel() } + func testCellularConnectivity() { MockReachability.iConnection = .wifi let expect = expectation(description: ".sink receives value") + var values = [Bool]() let cancellable = notifier.publisher.sink(receiveCompletion: { _ in XCTFail("Not expecting any error") }, receiveValue: { value in - XCTAssert(value.isOnline) - expect.fulfill() + values.append(value.isOnline) + if values.count == 2 { + XCTAssertFalse(values[0]) + XCTAssertTrue(values[1]) + expect.fulfill() + } }) notification = Notification.init(name: .reachabilityChanged) @@ -59,17 +70,21 @@ class NetworkReachabilityNotifierTests: XCTestCase { waitForExpectations(timeout: 1.0) cancellable.cancel() - } func testNoConnectivity() { MockReachability.iConnection = .unavailable let expect = expectation(description: ".sink receives value") + var values = [Bool]() let cancellable = notifier.publisher.sink(receiveCompletion: { _ in XCTFail("Not expecting any error") }, receiveValue: { value in - XCTAssertFalse(value.isOnline) - expect.fulfill() + values.append(value.isOnline) + if values.count == 2 { + XCTAssertFalse(values[0]) + XCTAssertFalse(values[1]) + expect.fulfill() + } }) notification = Notification.init(name: .reachabilityChanged) @@ -81,18 +96,21 @@ class NetworkReachabilityNotifierTests: XCTestCase { func testWifiConnectivity_publisherGoesOutOfScope() { MockReachability.iConnection = .wifi - let expect = expectation(description: ".sink receives value") + let defaultValueExpect = expectation(description: ".sink receives value") + let completeExpect = expectation(description: ".sink receives value") let cancellable = notifier.publisher.sink(receiveCompletion: { _ in - expect.fulfill() - }, receiveValue: { _ in - XCTAssertFalse(true) + completeExpect.fulfill() + }, receiveValue: { value in + XCTAssertFalse(value.isOnline) + defaultValueExpect.fulfill() }) + wait(for: [defaultValueExpect], timeout: 1.0) notifier = nil notification = Notification.init(name: .reachabilityChanged) NotificationCenter.default.post(notification) - waitForExpectations(timeout: 1.0) + wait(for: [completeExpect], timeout: 1.0) cancellable.cancel() } } From 120d1888aa2ac039ea72b02c255cbebf0d1f9b97 Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Mon, 28 Sep 2020 15:35:14 -0700 Subject: [PATCH 10/14] plural --- .../NetworkReachabilityNotifierTests.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/AmplifyPlugins/API/AWSAPICategoryPluginTests/Reachability/NetworkReachabilityNotifierTests.swift b/AmplifyPlugins/API/AWSAPICategoryPluginTests/Reachability/NetworkReachabilityNotifierTests.swift index f4680176d9..4033fc84d8 100644 --- a/AmplifyPlugins/API/AWSAPICategoryPluginTests/Reachability/NetworkReachabilityNotifierTests.swift +++ b/AmplifyPlugins/API/AWSAPICategoryPluginTests/Reachability/NetworkReachabilityNotifierTests.swift @@ -31,7 +31,7 @@ class NetworkReachabilityNotifierTests: XCTestCase { func testWifiConnectivity() { MockReachability.iConnection = .wifi - let expect = expectation(description: ".sink receives value") + let expect = expectation(description: ".sink receives values") var values = [Bool]() let cancellable = notifier.publisher.sink(receiveCompletion: { _ in XCTFail("Not expecting any error") @@ -52,7 +52,7 @@ class NetworkReachabilityNotifierTests: XCTestCase { func testCellularConnectivity() { MockReachability.iConnection = .wifi - let expect = expectation(description: ".sink receives value") + let expect = expectation(description: ".sink receives values") var values = [Bool]() let cancellable = notifier.publisher.sink(receiveCompletion: { _ in XCTFail("Not expecting any error") @@ -74,7 +74,7 @@ class NetworkReachabilityNotifierTests: XCTestCase { func testNoConnectivity() { MockReachability.iConnection = .unavailable - let expect = expectation(description: ".sink receives value") + let expect = expectation(description: ".sink receives values") var values = [Bool]() let cancellable = notifier.publisher.sink(receiveCompletion: { _ in XCTFail("Not expecting any error") @@ -96,8 +96,8 @@ class NetworkReachabilityNotifierTests: XCTestCase { func testWifiConnectivity_publisherGoesOutOfScope() { MockReachability.iConnection = .wifi - let defaultValueExpect = expectation(description: ".sink receives value") - let completeExpect = expectation(description: ".sink receives value") + let defaultValueExpect = expectation(description: ".sink receives default value") + let completeExpect = expectation(description: ".sink receives completion") let cancellable = notifier.publisher.sink(receiveCompletion: { _ in completeExpect.fulfill() }, receiveValue: { value in From 2836469b8dde78f946a73a83503fb9f1151f7df8 Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Tue, 29 Sep 2020 10:51:27 -0700 Subject: [PATCH 11/14] removed one log info --- .../AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift index f476e13940..83f7825cd9 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift @@ -191,7 +191,6 @@ class RemoteSyncEngine: RemoteSyncEngineBehavior { networkReachabilityPublisher = try reachability.reachabilityPublisher() networkReachabilitySink = networkReachabilityPublisher? .sink(receiveValue: onReceiveNetworkStatus(networkStatus:)) - log.info("reachability sink got set up") } catch { log.error("\(#function): Unable to listen on reachability: \(error)") } From b2565011ea7cac42bdfebd7d78798c1c69e3899b Mon Sep 17 00:00:00 2001 From: RuiGuo <48600426+ruiguoamz@users.noreply.github.com> Date: Tue, 29 Sep 2020 11:37:34 -0700 Subject: [PATCH 12/14] Update DataStoreCategory+HubPayloadEventName.swift --- .../DataStore/DataStoreCategory+HubPayloadEventName.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift index 5729b02e83..4acf12de5c 100644 --- a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift +++ b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift @@ -39,7 +39,7 @@ public extension HubPayload.EventName.DataStore { static let syncQueriesStarted = "DataStore.syncQueriesStarted" /// Dispatched when DataStore starts and everytime network status changes - /// HubPayload `NetworkStatusEvent` contains a boolean value `active` to notify network staus + /// HubPayload `NetworkStatusEvent` contains a boolean value `active` to notify network status static let networkStatus = "DataStore.networkStatus" /// Dispatched when a local mutation is enqueued into the outgoing mutation queue `outbox` From 205ae90f607e1e5c095b96eb6c46a94a127c17a1 Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Tue, 29 Sep 2020 13:28:17 -0700 Subject: [PATCH 13/14] updated integration test --- .../DataStoreHubEventsTests.swift | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift index 3d92037345..2f1da7b912 100644 --- a/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift +++ b/AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift @@ -23,6 +23,7 @@ class DataStoreHubEventTests: HubEventsIntegrationTestBase { /// - When: /// - DataStore's remote sync engine is initialized /// - Then: + /// - networkStatus received, payload should be: {active: true} /// - subscriptionEstablished received, payload should be nil /// - syncQueriesStarted received, payload should be: {models: ["Post", "Comment"]} /// - outboxStatus received, payload should be {isEmpty: true} @@ -33,7 +34,7 @@ class DataStoreHubEventTests: HubEventsIntegrationTestBase { let syncQueriesStartedReceived = expectation(description: "syncQueriesStarted received") let outboxStatusReceived = expectation(description: "outboxStatus received") - let hubListener = Amplify.Hub.listen(to: .dataStore) { payload in + let hubListener = Amplify.Hub.publisher(for: .dataStore).sink { payload in if payload.eventName == HubPayload.EventName.DataStore.networkStatus { guard let networkStatusEvent = payload.data as? NetworkStatusEvent else { XCTFail("Failed to cast payload data as NetworkStatusEvent") @@ -67,15 +68,10 @@ class DataStoreHubEventTests: HubEventsIntegrationTestBase { } } - guard try HubListenerTestUtilities.waitForListener(with: hubListener, timeout: 5.0) else { - XCTFail("Listener not registered for hub") - return - } - startAmplify() waitForExpectations(timeout: networkTimeout, handler: nil) - Amplify.Hub.removeListener(hubListener) + hubListener.cancel() } /// - Given: @@ -95,7 +91,7 @@ class DataStoreHubEventTests: HubEventsIntegrationTestBase { let outboxMutationEnqueuedReceived = expectation(description: "outboxMutationEnqueued received") let outboxMutationProcessedReceived = expectation(description: "outboxMutationProcessed received") - let hubListener = Amplify.Hub.listen(to: .dataStore) { payload in + let hubListener = Amplify.Hub.publisher(for: .dataStore).sink { payload in if payload.eventName == HubPayload.EventName.DataStore.outboxMutationEnqueued { guard let outboxMutationEnqueuedEvent = payload.data as? OutboxMutationEvent else { XCTFail("Failed to cast payload data as OutboxMutationEvent") @@ -122,16 +118,11 @@ class DataStoreHubEventTests: HubEventsIntegrationTestBase { outboxMutationProcessedReceived.fulfill() } } - - guard try HubListenerTestUtilities.waitForListener(with: hubListener, timeout: 5.0) else { - XCTFail("Listener not registered for hub") - return - } - + + startAmplify() Amplify.DataStore.save(post) { _ in } waitForExpectations(timeout: networkTimeout, handler: nil) - - Amplify.Hub.removeListener(hubListener) + hubListener.cancel() } } From ff5177a7ce8c39f4077b5dd945ade795e2421e5b Mon Sep 17 00:00:00 2001 From: Guo <48600426+DongQuanRui@users.noreply.github.com> Date: Tue, 29 Sep 2020 13:32:33 -0700 Subject: [PATCH 14/14] updated integration test --- .../DataStore/DataStoreCategory+HubPayloadEventName.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift index 5729b02e83..4acf12de5c 100644 --- a/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift +++ b/Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift @@ -39,7 +39,7 @@ public extension HubPayload.EventName.DataStore { static let syncQueriesStarted = "DataStore.syncQueriesStarted" /// Dispatched when DataStore starts and everytime network status changes - /// HubPayload `NetworkStatusEvent` contains a boolean value `active` to notify network staus + /// HubPayload `NetworkStatusEvent` contains a boolean value `active` to notify network status static let networkStatus = "DataStore.networkStatus" /// Dispatched when a local mutation is enqueued into the outgoing mutation queue `outbox`