Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Sources/Nirux/Model/MissionEventCLI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,16 @@ enum MissionEventCLI {

/// Wait for the next unconsumed child question/completion belonging to
/// this parent column. Questions stay pending until a response is sent;
/// completion is acknowledged immediately after it is printed.
/// completion is acknowledged after it is printed, and `receive` returns
/// only once Nirux recorded that (or after `confirmationTimeout`), so
/// running it again right away does not print the same completion again.
static func receive(
arguments: [String],
environment: [String: String] = ProcessInfo.processInfo.environment,
now: @escaping () -> TimeInterval = { Date().timeIntervalSince1970 },
eventsURL: URL = MissionEventCenter.defaultEventsURL,
missionsURL: URL = MissionStore.defaultFileURL,
confirmationTimeout: TimeInterval = 5,
pollInterval: TimeInterval = 0.2
) -> Int32 {
guard let context = parentContext(environment) else { return notAMissionTerminal(child: false) }
Expand Down Expand Up @@ -340,6 +343,13 @@ enum MissionEventCLI {
timestamp: now()
)
guard append(acknowledgement, to: eventsURL) else { return 1 }
_ = waitForLedger(
&ledger, timeout: confirmationTimeout, pollInterval: pollInterval
) { missions in
missions.lazy.flatMap(\.events).contains(where: {
$0.id == event.id && $0.parentConsumedAt != nil
}) ? true : nil
}
}
return 0
}
Expand Down
30 changes: 30 additions & 0 deletions Tests/NiruxTests/MissionAskTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ final class MissionAskTests: XCTestCase {
environment: parentEnvironment,
eventsURL: fixture.eventsURL,
missionsURL: fixture.missionsURL,
confirmationTimeout: 0,
pollInterval: 0.01
)
}
Expand Down Expand Up @@ -301,6 +302,35 @@ final class MissionAskTests: XCTestCase {
), 1)
}

func testReceiveDeliversACompletionOnceWhenRunAgainRightAway() async throws {
let fixture = try makeFixture()
complete(fixture)
let environment = parentEnvironment
let eventsURL = fixture.eventsURL
let missionsURL = fixture.missionsURL
let receive: @Sendable () -> Int32 = {
MissionEventCLI.receive(
arguments: ["--timeout", "0"],
environment: environment,
eventsURL: eventsURL,
missionsURL: missionsURL,
pollInterval: 0.01
)
}
// The parent runs `receive` again as soon as the first one returns.
let twice = Task.detached { (receive(), receive()) }
// Nirux drains the queue a moment after the acknowledgement lands.
try await Task.sleep(nanoseconds: 200_000_000)
let deadline = Date().addingTimeInterval(5)
while fixture.store.missions[0].events[0].parentConsumedAt == nil, Date() < deadline {
fixture.center.drain()
try await Task.sleep(nanoseconds: 10_000_000)
}
let (first, second) = await twice.value
XCTAssertEqual(first, 0, "prints the completion")
XCTAssertEqual(second, 4, "the completion is not printed again")
}

func testReplyStopsWhenTheQuestionWasAlreadyAnswered() throws {
let fixture = try makeFixture()
XCTAssertEqual(ask("Which API?", in: fixture), 3)
Expand Down
1 change: 1 addition & 0 deletions Tests/NiruxTests/MissionTellTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ final class MissionTellTests: XCTestCase {
environment: parentEnvironment(),
eventsURL: fixture.eventsURL,
missionsURL: fixture.missionsURL,
confirmationTimeout: 0,
pollInterval: 0.01
)
}
Expand Down
2 changes: 2 additions & 0 deletions Tests/NiruxTests/MissionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ final class MissionTests: XCTestCase {
now: { 40 },
eventsURL: eventsURL,
missionsURL: missionsURL,
confirmationTimeout: 0,
pollInterval: 0.01
), 0)
let acknowledgement = try decodeSingleEvent(from: eventsURL)
Expand Down Expand Up @@ -387,6 +388,7 @@ extension MissionTests {
now: { 40 },
eventsURL: eventsURL,
missionsURL: missionsURL,
confirmationTimeout: 0,
pollInterval: 0.01
), 0)
let center = MissionEventCenter(store: store, eventsURL: eventsURL, isEnabled: { true })
Expand Down
Loading