mirror of
https://github.com/aculix/knotchy.git
synced 2026-10-27 07:15:53 +00:00
Initial release
This commit is contained in:
commit
4b67728cce
108 files changed
+13310
No files matched your search
@@ -0,0 +1,204 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import KnotchyCore
|
||||
|
||||
@MainActor
|
||||
@Suite(.timeLimit(.minutes(1)))
|
||||
struct SessionNewLinkTests {
|
||||
private let first = "knotchy-00000001"
|
||||
private let second = "knotchy-00000002"
|
||||
|
||||
@Test func fromLiveTheOldVMIsDestroyedAndTheNewOneStartsAtOnce() async {
|
||||
let h = Harness()
|
||||
let old = await h.goLive()
|
||||
h.controller.open(Harness.otherURL)
|
||||
#expect(h.state == .starting(.booting, folded: false))
|
||||
#expect(h.controller.openedURL == Harness.otherURL)
|
||||
#expect(old.isClosed)
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.backend.calls == [.sweep(keeping: []), .preflight, .start(first), .destroy(first), .preflight, .start(second)])
|
||||
}
|
||||
|
||||
@Test func aStartThatHasNotBegunNeverRuns() async {
|
||||
let h = Harness()
|
||||
h.controller.open(Harness.url)
|
||||
h.controller.open(Harness.otherURL)
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.backend.calls == [.sweep(keeping: []), .preflight, .start(second)])
|
||||
#expect(h.controller.liveIDs.snapshot == [second])
|
||||
}
|
||||
|
||||
@Test func aSupersededStartIsDestroyedRightAfterItReturns() async {
|
||||
let h = Harness()
|
||||
h.backend.hold(.start)
|
||||
h.controller.open(Harness.url)
|
||||
await waitUntil("start runs") { h.backend.parkedCount(.start) == 1 }
|
||||
h.controller.open(Harness.otherURL)
|
||||
#expect(h.controller.liveIDs.snapshot == [first, second])
|
||||
|
||||
h.backend.release(.start)
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.backend.calls == [.sweep(keeping: []), .preflight, .start(first), .destroy(first), .preflight, .start(second)])
|
||||
await waitUntil("the new session connects") { h.connector.socketPaths == ["/fake/\(second).sock"] }
|
||||
#expect(h.controller.liveIDs.snapshot == [second])
|
||||
}
|
||||
|
||||
@Test func aConnectThatReturnsAfterANewLinkIsClosed() async {
|
||||
let h = Harness()
|
||||
h.connector.hold()
|
||||
h.controller.open(Harness.url)
|
||||
await waitUntil("connect runs") { h.connector.parkedCount == 1 }
|
||||
h.backend.hold(.start)
|
||||
h.controller.open(Harness.otherURL)
|
||||
await waitUntil("the new start runs") { h.backend.parkedCount(.start) == 1 }
|
||||
|
||||
h.connector.release()
|
||||
await waitUntil("the late stream is closed") { h.connector.connections.first?.isClosed == true }
|
||||
#expect(h.state == .starting(.booting, folded: false))
|
||||
#expect(h.controller.connection == nil)
|
||||
|
||||
h.backend.release(.start)
|
||||
await waitUntil("the new session connects") { h.state == .starting(.loading, folded: false) }
|
||||
#expect((h.controller.connection as? FakeStreamConnection)?.socketPath == "/fake/\(second).sock")
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.backend.calls == [.sweep(keeping: []), .preflight, .start(first), .destroy(first), .preflight, .start(second)])
|
||||
}
|
||||
|
||||
@Test func aSupersededStartThatFailsLeavesTheNewSessionAlone() async {
|
||||
let h = Harness()
|
||||
h.backend.hold(.start)
|
||||
h.backend.hold(.destroy)
|
||||
h.controller.open(Harness.url)
|
||||
await waitUntil("start runs") { h.backend.parkedCount(.start) == 1 }
|
||||
h.controller.open(Harness.otherURL)
|
||||
h.backend.failStarts(with: VMBackendError.failed("boom"))
|
||||
h.backend.release(.start)
|
||||
await waitUntil("the old VM's destroy runs") { h.backend.parkedCount(.destroy) == 1 }
|
||||
#expect(h.state == .starting(.booting, folded: false)) // Not the old start's error card.
|
||||
h.backend.failStarts(with: nil)
|
||||
h.backend.release(.destroy)
|
||||
await waitUntil("the new session connects") { h.state == .starting(.loading, folded: false) }
|
||||
}
|
||||
|
||||
@Test func anOldSessionsStuckDestroyDoesNotDriveTheCurrentPill() async {
|
||||
let h = Harness()
|
||||
await h.goLive()
|
||||
h.backend.hold(.destroy)
|
||||
h.backend.failDestroys(with: VMBackendError.destroyStuck(id: first))
|
||||
h.controller.destroy()
|
||||
await waitUntil("destroy runs") { h.backend.parkedCount(.destroy) == 1 }
|
||||
h.controller.open(Harness.otherURL)
|
||||
h.controller.destroy() // The new session never started a VM, so this one succeeds.
|
||||
h.backend.release(.destroy)
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.state == .destroyed)
|
||||
}
|
||||
|
||||
@Test func liveIDsCoverASupersededSessionUntilItsDestroyIsConfirmed() async {
|
||||
let h = Harness()
|
||||
await h.goLive()
|
||||
h.backend.hold(.destroy)
|
||||
h.controller.open(Harness.otherURL)
|
||||
await waitUntil("destroy runs") { h.backend.parkedCount(.destroy) == 1 }
|
||||
#expect(h.controller.liveIDs.snapshot == [first, second])
|
||||
h.backend.release(.destroy)
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.controller.liveIDs.snapshot == [second])
|
||||
}
|
||||
|
||||
@Test func fromDestroyingTheNewSessionStartsAfterTheDestroy() async {
|
||||
let h = Harness()
|
||||
await h.goLive()
|
||||
h.backend.hold(.destroy)
|
||||
h.controller.destroy()
|
||||
await waitUntil("destroy runs") { h.backend.parkedCount(.destroy) == 1 }
|
||||
h.controller.open(Harness.otherURL)
|
||||
#expect(h.state == .starting(.booting, folded: false))
|
||||
|
||||
h.backend.release(.destroy)
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.backend.calls.suffix(3) == [.destroy(first), .preflight, .start(second)])
|
||||
await waitUntil("loading") { h.state == .starting(.loading, folded: false) }
|
||||
}
|
||||
|
||||
@Test func fromTheCollapsedPillTheNewLinkOpensThePanel() async {
|
||||
let h = Harness()
|
||||
await h.goLive()
|
||||
h.controller.clickedOutside()
|
||||
h.controller.open(Harness.otherURL)
|
||||
#expect(h.state == .starting(.booting, folded: false))
|
||||
#expect(h.controller.countdown == nil)
|
||||
}
|
||||
|
||||
@Test func fromDestroyedTheCheckmarkIsCutShort() async {
|
||||
let h = Harness()
|
||||
await h.goLive()
|
||||
h.controller.destroy()
|
||||
await waitUntil("destroyed") { h.state == .destroyed }
|
||||
h.controller.open(Harness.otherURL)
|
||||
#expect(h.state == .starting(.booting, folded: false))
|
||||
h.advance(by: .seconds(2))
|
||||
#expect(h.state != .idle)
|
||||
}
|
||||
|
||||
@Test func fromSessionEndedThePillIsCutShort() async {
|
||||
let h = Harness()
|
||||
let stream = await h.goLive()
|
||||
stream.emit(.ended(.closed))
|
||||
await waitUntil("ended") { h.state == .failed(.ended(.closed)) }
|
||||
h.controller.open(Harness.otherURL)
|
||||
#expect(h.state == .starting(.booting, folded: false))
|
||||
h.advance(by: .seconds(3))
|
||||
#expect(h.state != .idle)
|
||||
}
|
||||
|
||||
@Test func fromTheErrorCardTheNewLinkStarts() async {
|
||||
let h = Harness()
|
||||
h.backend.failStarts(with: VMBackendError.failed("boom"))
|
||||
h.controller.open(Harness.url)
|
||||
await waitUntil("failed") { h.state == .failed(.start("boom")) }
|
||||
h.backend.failStarts(with: nil)
|
||||
h.controller.open(Harness.otherURL)
|
||||
#expect(h.state == .starting(.booting, folded: false))
|
||||
await waitUntil("the new start runs") { h.backend.calls.contains(.start(second)) }
|
||||
}
|
||||
|
||||
@Test func fromAStuckDestroyTheStuckVMStaysOnPendingCleanup() async {
|
||||
let h = Harness()
|
||||
await h.goLive()
|
||||
h.backend.failDestroys(with: VMBackendError.destroyStuck(id: first))
|
||||
h.backend.failForceDestroys(with: VMBackendError.destroyStuck(id: first))
|
||||
h.controller.destroy()
|
||||
await waitUntil("stuck") { h.state == .failed(.destroyStuck) }
|
||||
h.controller.open(Harness.otherURL)
|
||||
#expect(h.state == .starting(.booting, folded: false))
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.controller.liveIDs.snapshot == [first, second])
|
||||
}
|
||||
|
||||
@Test func fromSetupRequiredPreflightRunsAgain() async {
|
||||
let h = Harness()
|
||||
h.backend.queuePreflight(.issue(.imageMissing))
|
||||
h.controller.open(Harness.url)
|
||||
await waitUntil("setup required") { h.state == .setupRequired(.imageMissing, error: nil) }
|
||||
h.controller.open(Harness.otherURL)
|
||||
#expect(h.state == .starting(.booting, folded: false))
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.backend.calls == [.sweep(keeping: []), .preflight, .preflight, .start(second)])
|
||||
}
|
||||
|
||||
@Test func backendCallsNeverOverlap() async {
|
||||
let h = Harness()
|
||||
h.backend.hold(.start)
|
||||
h.controller.open(Harness.url)
|
||||
await waitUntil("start runs") { h.backend.parkedCount(.start) == 1 }
|
||||
h.controller.open(Harness.otherURL)
|
||||
h.controller.open(Harness.url)
|
||||
h.controller.destroy()
|
||||
h.controller.open(Harness.otherURL)
|
||||
h.backend.release(.start)
|
||||
await h.controller.waitForBackendIdle()
|
||||
#expect(h.backend.maxConcurrentCalls == 1)
|
||||
#expect(h.controller.liveIDs.snapshot == ["knotchy-00000004"])
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user