amplify-swift/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/hierarchical-state-machine-.../StateMachineTests.swift

156 lines
5.1 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import XCTest
@testable import AWSCognitoAuthPlugin
class StateMachineTests: XCTestCase {
func testDefaultState() async {
let testMachine = CounterStateMachine.logging()
let state = await testMachine.currentState
XCTAssertEqual(state.value, 0)
}
func testBasicReceive() async {
let testMachine = CounterStateMachine.logging()
let increment = Counter.Event(id: "1", eventType: .increment)
await testMachine.send(increment)
let state = await testMachine.currentState
XCTAssertEqual(state.value, 1)
}
/// Given:
/// - A state machine
/// When:
/// - The StateMachine receives multiple events concurrently
/// Then:
/// - It applies the events in order of receipt
func testConcurrentReceive() async {
// Logging will significantly impact performance on these tight loops, so adjust expectation
// timeout accordingly if you need to log
let testMachine = CounterStateMachine.default()
let increment = Counter.Event(id: "increment", eventType: .increment)
let decrement = Counter.Event(id: "decrement", eventType: .decrement)
let taskCompletion = expectation(description: "Completed sending event")
taskCompletion.expectedFulfillmentCount = 1_000
Task {
for i in 1...1_000 {
if i.isMultiple(of: 2) {
await testMachine.send(increment)
} else {
await testMachine.send(decrement)
}
taskCompletion.fulfill()
}
}
await waitForExpectations(timeout: 1)
let state = await testMachine.currentState
XCTAssertEqual(state.value, 0)
}
/// Given:
/// - A state machine
/// When:
/// - The StateMachine receives an event
/// - A caller reads the current state
/// Then:
/// - The read blocks until the state is resolved
///
/// The way we assert this is to immediately read the current value after
/// receiving an event. `receive` is asynchronous, so we'd expect some of
/// the current values to be out of sync if the state machine didn't
/// properly serialize access.
func testConcurrentReceiveAndRead() async {
// Logging will significantly impact performance on these tight loops, so adjust expectation
// timeout accordingly if you need to log
let testMachine = CounterStateMachine.default()
let increment = Counter.Event(id: "1", eventType: .increment)
for iteration in 1 ... 10 {
await testMachine.send(increment)
let state = await testMachine.currentState
XCTAssertEqual(state.value, iteration)
}
}
/// Given:
/// - A state machine
/// When:
/// - The state machine receives a resolution that includes actions
/// Then:
/// - It executes the action
func testExecutesEffects() async {
let action1WasExecuted = expectation(description: "action1WasExecuted")
let action2WasExecuted = expectation(description: "action2WasExecuted")
let action1 = BasicAction(identifier: "basic") { _, _ in
action1WasExecuted.fulfill()
}
let action2 = BasicAction(identifier: "basic") { _, _ in
action2WasExecuted.fulfill()
}
let testMachine = CounterStateMachine.logging()
let event = Counter.Event(
id: "1",
eventType: .incrementAndDoActions([action1, action2])
)
await testMachine.send(event)
await waitForExpectations(timeout: 0.1)
}
/// Given:
/// - A State machine
/// When:
/// - The state machine receives a resolution that includes an effect
/// - The effect `dispatches` a new event
/// Then:
/// - The StateMachine processes the new event
func testDispatchesFromAction() async {
let action1WasExecuted = expectation(description: "action1WasExecuted")
let action2WasExecuted = expectation(description: "action2WasExecuted")
let executionCount = AtomicValue(initialValue: 0)
let action1 = BasicAction(identifier: "basic") { dispatcher, _ in
action1WasExecuted.fulfill()
XCTAssertEqual(executionCount.getAndSet(1), 0)
let action2 = BasicAction(identifier: "basic") { _, _ in
XCTAssertEqual(executionCount.getAndSet(2), 1)
action2WasExecuted.fulfill()
}
let event = Counter.Event(
id: "2",
eventType: .incrementAndDoActions([action2])
)
Task {
await dispatcher.send(event)
}
}
let testMachine = CounterStateMachine.logging()
let event = Counter.Event(
id: "1",
eventType: .incrementAndDoActions([action1])
)
await testMachine.send(event)
await waitForExpectations(timeout: 0.1)
XCTAssertEqual(executionCount.get(), 2)
}
}