241 lines
9.1 KiB
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()
|
|
}
|
|
|
|
}
|