From 5289eb509fe1d86a39e24ce9a880928337fa4938 Mon Sep 17 00:00:00 2001 From: Dai Ha Date: Thu, 10 Sep 2026 16:58:55 +0700 Subject: [PATCH] fleetd #437: pin the ack hit/miss contract in the AMQP contract test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AmqpReplyInboxContractTest is the one contract-group class CI actually runs, and it never asserted on ack()'s return value at all — so the exact defect this ticket fixes (reporting success for an ack that removed nothing) was unpinned in the adapter fleetd runs live. Add ackReportsHitVsMissAgainstARealBroker: a msgId never held for an owned target returns false without throwing, a real held reply returns true and is removed, and acking the same msgId again returns false. Ran against both broker modes the class supports: Testcontainers (AMQP_URI unset) and an external broker via AMQP_URI (the CI shape, using a disposable container — not the shared local LavinMQ instance). --- .../fleet/msg/AmqpReplyInboxContractTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/fleetd/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxContractTest.java b/fleetd/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxContractTest.java index b310062..8f2e35a 100644 --- a/fleetd/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxContractTest.java +++ b/fleetd/src/test/java/dev/ltms/fleet/msg/AmqpReplyInboxContractTest.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -221,6 +222,31 @@ class AmqpReplyInboxContractTest { } } + @Test + void ackReportsHitVsMissAgainstARealBroker() throws Exception { + // fleetd #437: fleet_ack said "acknowledged " for a message it never touched, + // because ReplyInbox.ack() (void) could not tell a hit from a miss. Pin the fixed + // boolean contract against a real broker — the adapter fleetd actually runs live. + String target = "worker-ack-contract-" + System.nanoTime(); + try (AmqpReplyInbox inbox = AmqpReplyInbox.open(uri())) { + inbox.own(target); + + // Never held for this target at all: must report false, not throw. + assertFalse(inbox.ack(target, "never-held"), + "acking a msgId never held for an owned target must report false"); + + // A real message: first ack removes it and reports true... + inbox.publish(target, "m1", "ack me"); + assertEquals(1, awaitPeek(inbox, target).size(), "the published reply should be held"); + assertTrue(inbox.ack(target, "m1"), "acking a held reply must report true"); + assertTrue(inbox.peek(target).isEmpty(), "an acked reply is dropped"); + + // ...and the second ack of the SAME msgId has nothing left to remove: false. + assertFalse(inbox.ack(target, "m1"), + "acking the same msgId twice must report false the second time"); + } + } + @Test void confirmedPublishDeliversNormally() throws Exception { String target = "worker-confirm-" + System.nanoTime();