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();