|
1 | 1 | /* |
2 | | - * Copyright (C) 2020-2023 Ignite Realtime Foundation. All rights reserved. |
| 2 | + * Copyright (C) 2020-2026 Ignite Realtime Foundation. All rights reserved. |
3 | 3 | * |
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | 5 | * you may not use this file except in compliance with the License. |
|
20 | 20 | import org.junit.jupiter.api.Test; |
21 | 21 | import org.xmpp.packet.JID; |
22 | 22 |
|
| 23 | +import java.util.Date; |
| 24 | + |
23 | 25 | import static org.junit.jupiter.api.Assertions.*; |
24 | 26 |
|
25 | 27 | /** |
|
29 | 31 | */ |
30 | 32 | public class LeafNodeTest |
31 | 33 | { |
| 34 | + /** Creates a minimal LeafNode for use in tests. */ |
| 35 | + private static LeafNode createTestLeafNode() { |
| 36 | + final DefaultNodeConfiguration config = new DefaultNodeConfiguration(true); |
| 37 | + return new LeafNode( |
| 38 | + new PubSubService.UniqueIdentifier("test-service-id"), |
| 39 | + null, |
| 40 | + "test-node-id", |
| 41 | + new JID("unit-test@example.org"), |
| 42 | + config); |
| 43 | + } |
| 44 | + |
32 | 45 | @Test |
33 | 46 | public void testSerialization() throws Exception |
34 | 47 | { |
@@ -59,4 +72,93 @@ public void testSerialization() throws Exception |
59 | 72 | assertTrue( result instanceof LeafNode ); |
60 | 73 | assertEquals( input, result ); |
61 | 74 | } |
| 75 | + |
| 76 | + // ========================================================================= |
| 77 | + // setLastPublishedItem / getPublishedItem — XEP-0060 §7.1.2 compliance |
| 78 | + // |
| 79 | + // When a publisher publishes an item with the same ItemID as a previously |
| 80 | + // published item, the server MUST overwrite the old item with the new one. |
| 81 | + // The in-memory 'lastPublished' cache must reflect the new item immediately, |
| 82 | + // even if both items share the same creation-date timestamp. |
| 83 | + // ========================================================================= |
| 84 | + |
| 85 | + /** |
| 86 | + * Regression test for XEP-0060 §7.1.2: publishing a second item with the same |
| 87 | + * ItemID must update the in-memory {@code lastPublished} reference, even when |
| 88 | + * the two items share the same creation-date (published within the same |
| 89 | + * millisecond, as is common in fast sequential integration tests). |
| 90 | + * |
| 91 | + * <p>Before the fix, {@code setLastPublishedItem} only updated {@code lastPublished} |
| 92 | + * when {@code item.getCreationDate().after(lastPublished.getCreationDate())} returned |
| 93 | + * {@code true}. If both items had the same timestamp the old item remained cached, |
| 94 | + * causing {@code getPublishedItem()} to serve the stale first-published payload. |
| 95 | + */ |
| 96 | + @Test |
| 97 | + public void testSetLastPublishedItem_SameIdSameTimestamp_UpdatesCache() { |
| 98 | + final LeafNode node = createTestLeafNode(); |
| 99 | + final JID publisher = new JID("user@example.org"); |
| 100 | + final Date sharedTimestamp = new Date(1_000_000L); |
| 101 | + |
| 102 | + // First publish: item1 with itemID="shared-id", payload conceptually "payload-1". |
| 103 | + final PublishedItem item1 = new PublishedItem(node, publisher, "shared-id", sharedTimestamp); |
| 104 | + node.setLastPublishedItem(item1); |
| 105 | + |
| 106 | + // Sanity: lastPublished should now be item1. |
| 107 | + assertSame(item1, node.getLastPublishedItem(), |
| 108 | + "After first publish, lastPublished must be item1"); |
| 109 | + |
| 110 | + // Second publish: item2 with SAME itemID and SAME timestamp (typical in fast tests). |
| 111 | + final PublishedItem item2 = new PublishedItem(node, publisher, "shared-id", sharedTimestamp); |
| 112 | + node.setLastPublishedItem(item2); |
| 113 | + |
| 114 | + // Assert: lastPublished must be updated to item2 (the overwriting item). |
| 115 | + // Before the fix this assertion would fail because the creation-date guard |
| 116 | + // prevented the update when both items shared the same timestamp. |
| 117 | + assertSame(item2, node.getLastPublishedItem(), |
| 118 | + "XEP-0060 §7.1.2: re-publishing with the same ItemID must update lastPublished " + |
| 119 | + "even when both items have the same creation-date"); |
| 120 | + } |
| 121 | + |
| 122 | + /** |
| 123 | + * Complementary test: publishing an item with a different ItemID but the same |
| 124 | + * timestamp must NOT overwrite {@code lastPublished}. Only items with newer |
| 125 | + * timestamps (or the same ID) should replace it. |
| 126 | + */ |
| 127 | + @Test |
| 128 | + public void testSetLastPublishedItem_DifferentIdSameTimestamp_DoesNotOverwrite() { |
| 129 | + final LeafNode node = createTestLeafNode(); |
| 130 | + final JID publisher = new JID("user@example.org"); |
| 131 | + final Date sharedTimestamp = new Date(1_000_000L); |
| 132 | + |
| 133 | + final PublishedItem item1 = new PublishedItem(node, publisher, "id-alpha", sharedTimestamp); |
| 134 | + node.setLastPublishedItem(item1); |
| 135 | + |
| 136 | + // A different item with a different ID but the same timestamp. |
| 137 | + final PublishedItem item2 = new PublishedItem(node, publisher, "id-beta", sharedTimestamp); |
| 138 | + node.setLastPublishedItem(item2); |
| 139 | + |
| 140 | + // item1 was the last published (by time) and has a different ID, |
| 141 | + // so it should remain as lastPublished (item2 is not newer). |
| 142 | + assertSame(item1, node.getLastPublishedItem(), |
| 143 | + "A different item published at the same timestamp must not displace lastPublished"); |
| 144 | + } |
| 145 | + |
| 146 | + /** |
| 147 | + * Sanity test: publishing a newer item (strictly later timestamp) with a |
| 148 | + * different ID must update {@code lastPublished} as before. |
| 149 | + */ |
| 150 | + @Test |
| 151 | + public void testSetLastPublishedItem_DifferentIdNewerTimestamp_UpdatesCache() { |
| 152 | + final LeafNode node = createTestLeafNode(); |
| 153 | + final JID publisher = new JID("user@example.org"); |
| 154 | + |
| 155 | + final PublishedItem item1 = new PublishedItem(node, publisher, "id-alpha", new Date(1_000L)); |
| 156 | + node.setLastPublishedItem(item1); |
| 157 | + |
| 158 | + final PublishedItem item2 = new PublishedItem(node, publisher, "id-beta", new Date(2_000L)); |
| 159 | + node.setLastPublishedItem(item2); |
| 160 | + |
| 161 | + assertSame(item2, node.getLastPublishedItem(), |
| 162 | + "A newer item (later timestamp, different ID) must update lastPublished"); |
| 163 | + } |
62 | 164 | } |
0 commit comments