//// A replayed host call must never run twice, and only a call an earlier
//// daemon started without answering may come back as "outcome unknown". The
//// replay that reaches this ledger needs a daemon restart between a call and
//// its acknowledgement, which E2E cannot place; the ledger is driven here.
import albedo/daemon/store
import albedo/harness/extensions/python/link
import gleam/option
import gleeunit/should
fn recorded() -> #(store.Store, link.Record) {
let assert Ok(ledger) = store.start(":memory:", "")
let record =
link.Record(
session: "s",
kernel: "k1",
token: "t",
run_dir: "/nowhere",
cwd: "/tmp",
modules: "[]",
out_seq: 0,
owned: "{}",
)
let assert Ok(_) = link.create(ledger, record)
#(ledger, record)
}
pub fn a_replayed_call_is_answered_not_run_again_test() -> Nil {
let #(ledger, record) = recorded()
link.call(ledger, record, "c1") |> should.equal(link.Fresh)
let assert Ok(_) = link.reply(ledger, record, "c1", 1, "{\"type\":\"reply\"}")
// The kernel never saw our ack and sends the call again: its reply is
// already on the way through the outbox.
link.call(ledger, record, "c1") |> should.equal(link.Answered)
link.pending(ledger, record) |> should.equal([#(1, "{\"type\":\"reply\"}")])
// Once the kernel has the reply, the call and its frame are gone.
let assert Ok(_) = link.ack(ledger, record, 1)
link.pending(ledger, record) |> should.equal([])
store.close(ledger)
}
pub fn a_call_an_earlier_daemon_never_answered_is_unknown_test() -> Nil {
let #(ledger, record) = recorded()
link.call(ledger, record, "c1") |> should.equal(link.Fresh)
// The daemon restarted before answering: a replay must not run it again.
link.call(ledger, record, "c1") |> should.equal(link.Unknown)
store.close(ledger)
}
pub fn a_restarted_daemon_resends_and_keeps_counting_test() -> Nil {
let #(ledger, record) = recorded()
let assert Ok(_) = link.persist(ledger, record, 1, "{\"a\":1}")
let assert Ok(_) = link.persist(ledger, record, 2, "{\"a\":2}")
let assert Ok(_) = link.ack(ledger, record, 1)
let assert Ok(found) = link.find(ledger, "s") |> option.to_result(Nil)
found.out_seq |> should.equal(2)
link.pending(ledger, found) |> should.equal([#(2, "{\"a\":2}")])
let assert Ok(_) = link.forget(ledger, found)
link.find(ledger, "s") |> should.equal(option.None)
store.close(ledger)
}