amplify-swift/AmplifyPlugins/DataStore/Tests/AWSDataStorePluginTests/Sync/LocalSubscriptionTests.swift

241 lines
9.1 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import XCTest
import SQLite
import Combine
@testable import Amplify
@testable import AWSPluginsCore
@testable import AmplifyTestCommon
@testable import AWSDataStorePlugin
/// Tests behavior of local DataStore subscriptions (as opposed to remote API subscription behaviors)
class LocalSubscriptionTests: XCTestCase {
override func setUp() async throws {
try await super.setUp()
await Amplify.reset()
Amplify.Logging.logLevel = .warn
let storageAdapter: SQLiteStorageEngineAdapter
let storageEngine: StorageEngine
var stateMachine: MockStateMachine<RemoteSyncEngine.State, RemoteSyncEngine.Action>!
let validAPIPluginKey = "MockAPICategoryPlugin"
let validAuthPluginKey = "MockAuthCategoryPlugin"
do {
let connection = try Connection(.inMemory)
storageAdapter = try SQLiteStorageEngineAdapter(connection: connection)
try storageAdapter.setUp(modelSchemas: StorageEngine.systemModelSchemas)
let outgoingMutationQueue = NoOpMutationQueue()
let mutationDatabaseAdapter = try AWSMutationDatabaseAdapter(storageAdapter: storageAdapter)
let awsMutationEventPublisher = AWSMutationEventPublisher(eventSource: mutationDatabaseAdapter)
stateMachine = MockStateMachine(initialState: .notStarted,
resolver: RemoteSyncEngine.Resolver.resolve(currentState:action:))
let syncEngine = RemoteSyncEngine(
storageAdapter: storageAdapter,
dataStoreConfiguration: .default,
authModeStrategy: AWSDefaultAuthModeStrategy(),
outgoingMutationQueue: outgoingMutationQueue,
mutationEventIngester: mutationDatabaseAdapter,
mutationEventPublisher: awsMutationEventPublisher,
initialSyncOrchestratorFactory: NoOpInitialSyncOrchestrator.factory,
reconciliationQueueFactory: MockAWSIncomingEventReconciliationQueue.factory,
stateMachine: stateMachine,
networkReachabilityPublisher: nil,
requestRetryablePolicy: MockRequestRetryablePolicy()
)
storageEngine = StorageEngine(storageAdapter: storageAdapter,
dataStoreConfiguration: .default,
syncEngine: syncEngine,
validAPIPluginKey: validAPIPluginKey,
validAuthPluginKey: validAuthPluginKey)
} catch {
XCTFail(String(describing: error))
return
}
let storageEngineBehaviorFactory: StorageEngineBehaviorFactory = {_, _, _, _, _, _ throws in
return storageEngine
}
let dataStorePublisher = DataStorePublisher()
let dataStorePlugin = AWSDataStorePlugin(modelRegistration: TestModelRegistration(),
storageEngineBehaviorFactory: storageEngineBehaviorFactory,
dataStorePublisher: dataStorePublisher,
validAPIPluginKey: validAPIPluginKey,
validAuthPluginKey: validAuthPluginKey)
let dataStoreConfig = DataStoreCategoryConfiguration(plugins: [
"awsDataStorePlugin": true
])
// Since these tests use syncable models, we have to set up an API category also
let apiConfig = APICategoryConfiguration(plugins: ["MockAPICategoryPlugin": true])
let apiPlugin = MockAPICategoryPlugin()
let amplifyConfig = AmplifyConfiguration(api: apiConfig, dataStore: dataStoreConfig)
do {
try Amplify.add(plugin: apiPlugin)
try Amplify.add(plugin: dataStorePlugin)
try Amplify.configure(amplifyConfig)
} catch {
XCTFail(String(describing: error))
return
}
}
/// - Given: A configured Amplify system on iOS 13 or higher
/// - When:
/// - I get an async sequence observing a model
/// - Then:
/// - I receive notifications for updates to that model
func testObserve() async throws {
let receivedMutationEvent = asyncExpectation(description: "Received mutation event")
let subscription = Task {
let mutationEvents = Amplify.DataStore.observe(Post.self)
do {
for try await _ in mutationEvents {
await receivedMutationEvent.fulfill()
}
} catch {
XCTFail("Unexpected error: \(error)")
}
}
let model = Post(id: UUID().uuidString,
title: "Test Post",
content: "Test Post Content",
createdAt: .now(),
updatedAt: nil,
draft: false,
rating: nil,
comments: [])
_ = try await Amplify.DataStore.save(model)
await waitForExpectations([receivedMutationEvent], timeout: 1.0)
subscription.cancel()
}
/// - Given: A configured DataStore
/// - When:
/// - I subscribe to model events
/// - Then:
/// - I am notified of `create` mutations
func testCreate() async throws {
let receivedMutationEvent = asyncExpectation(description: "Received mutation event")
let subscription = Task {
let mutationEvents = Amplify.DataStore.observe(Post.self)
do {
for try await mutationEvent in mutationEvents {
if mutationEvent.mutationType == MutationEvent.MutationType.create.rawValue {
await receivedMutationEvent.fulfill()
}
}
} catch {
XCTFail("Unexpected error: \(error)")
}
}
let model = Post(id: UUID().uuidString,
title: "Test Post",
content: "Test Post Content",
createdAt: .now(),
updatedAt: nil,
draft: false,
rating: nil,
comments: [])
_ = try await Amplify.DataStore.save(model)
await waitForExpectations([receivedMutationEvent], timeout: 1.0)
subscription.cancel()
}
/// - Given: A configured DataStore
/// - When:
/// - I subscribe to model events
/// - Then:
/// - I am notified of `update` mutations
func testUpdate() async throws {
let originalContent = "Content as of \(Date())"
let model = Post(id: UUID().uuidString,
title: "Test Post",
content: originalContent,
createdAt: .now(),
updatedAt: nil,
draft: false,
rating: nil,
comments: [])
_ = try await Amplify.DataStore.save(model)
let newContent = "Updated content as of \(Date())"
var newModel = model
newModel.content = newContent
newModel.updatedAt = .now()
let receivedMutationEvent = asyncExpectation(description: "Received mutation event")
let subscription = Task {
let mutationEvents = Amplify.DataStore.observe(Post.self)
do {
for try await _ in mutationEvents {
await receivedMutationEvent.fulfill()
}
} catch {
XCTFail("Unexpected error: \(error)")
}
}
_ = try await Amplify.DataStore.save(newModel)
await waitForExpectations([receivedMutationEvent], timeout: 1.0)
subscription.cancel()
}
/// - Given: A configured DataStore
/// - When:
/// - I subscribe to model events
/// - Then:
/// - I am notified of `delete` mutations
func testDelete() async throws {
let receivedMutationEvent = asyncExpectation(description: "Received mutation event")
let subscription = Task {
let mutationEvents = Amplify.DataStore.observe(Post.self)
do {
for try await mutationEvent in mutationEvents {
if mutationEvent.mutationType == MutationEvent.MutationType.delete.rawValue {
await receivedMutationEvent.fulfill()
}
}
} catch {
XCTFail("Unexpected error: \(error)")
}
}
let model = Post(title: "Test Post",
content: "Test Post Content",
createdAt: .now())
_ = try await Amplify.DataStore.save(model)
_ = try await Amplify.DataStore.delete(model)
await waitForExpectations([receivedMutationEvent], timeout: 1.0)
subscription.cancel()
}
}