Skip to content

Commit 8bf24ae

Browse files
akrherzguusdk
authored andcommitted
Add pubsub/PubSubEngineTest
1 parent c635c65 commit 8bf24ae

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright (C) 2025-2026 Ignite Realtime Foundation. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.jivesoftware.openfire.pubsub;
17+
18+
import org.dom4j.Element;
19+
import org.jivesoftware.openfire.PacketRouter;
20+
import org.jivesoftware.openfire.pubsub.models.PublisherModel;
21+
import org.junit.jupiter.api.Test;
22+
import org.junit.jupiter.api.extension.ExtendWith;
23+
import org.mockito.ArgumentCaptor;
24+
import org.mockito.Mockito;
25+
import org.mockito.junit.jupiter.MockitoExtension;
26+
import org.xmpp.packet.IQ;
27+
import org.xmpp.packet.JID;
28+
import org.xmpp.packet.PacketError;
29+
30+
import static org.junit.jupiter.api.Assertions.*;
31+
32+
/**
33+
* Verifies compliance-relevant behavior of {@link PubSubEngine} against XEP-0060.
34+
*/
35+
@ExtendWith(MockitoExtension.class)
36+
public class PubSubEngineTest
37+
{
38+
/**
39+
* XEP-0060 §8.5.3.1: Purging a collection node MUST return a feature-not-implemented
40+
* error with the 'purge-nodes' unsupported feature, not a ClassCastException.
41+
*
42+
* Verifies the fix for a bug where a ClassCastException was thrown when attempting to
43+
* purge a collection node, because the node was cast to LeafNode before checking
44+
* whether it was a collection node.
45+
*/
46+
@Test
47+
public void testPurgeCollectionNodeReturnsFeatureNotImplemented() throws Exception
48+
{
49+
// Setup fixture.
50+
final PacketRouter mockRouter = Mockito.mock(PacketRouter.class);
51+
final PubSubEngine engine = new PubSubEngine(mockRouter);
52+
53+
final PubSubService mockService = Mockito.mock(PubSubService.class);
54+
55+
final Node mockNode = Mockito.mock(Node.class);
56+
Mockito.when(mockNode.isCollectionNode()).thenReturn(true);
57+
Mockito.when(mockNode.isAdmin(Mockito.any(JID.class))).thenReturn(true);
58+
Mockito.when(mockService.getNode(Mockito.anyString())).thenReturn(mockNode);
59+
60+
final JID ownerJID = new JID("owner", "example.org", null);
61+
final IQ iq = new IQ(IQ.Type.set);
62+
iq.setFrom(ownerJID);
63+
final Element pubsubElement = iq.setChildElement("pubsub", "http://jabber.org/protocol/pubsub#owner");
64+
final Element purgeElement = pubsubElement.addElement("purge");
65+
purgeElement.addAttribute("node", "test-node");
66+
67+
// Execute system under test.
68+
engine.process(mockService, iq);
69+
70+
// Verify result: error response with feature-not-implemented and 'purge-nodes'.
71+
final ArgumentCaptor<IQ> packetCaptor = ArgumentCaptor.forClass(IQ.class);
72+
Mockito.verify(mockRouter).route(packetCaptor.capture());
73+
final IQ response = packetCaptor.getValue();
74+
assertEquals(IQ.Type.error, response.getType());
75+
assertEquals(PacketError.Condition.feature_not_implemented, response.getError().getCondition());
76+
77+
final Element pubsubError = response.getError().getElement()
78+
.element("unsupported");
79+
assertNotNull(pubsubError, "Expected a pubsub 'unsupported' error element");
80+
assertEquals("purge-nodes", pubsubError.attributeValue("feature"),
81+
"Expected 'purge-nodes' as the unsupported feature");
82+
}
83+
84+
/**
85+
* XEP-0060 §7.1.3.5: If the payload size exceeds a service-defined maximum, the service
86+
* MUST return a &lt;not-acceptable/&gt; error with a pubsub-specific condition of
87+
* &lt;payload-too-big/&gt;.
88+
*/
89+
@Test
90+
public void testPublishOversizedPayloadReturnsPayloadTooBig() throws Exception
91+
{
92+
// Setup fixture.
93+
final PacketRouter mockRouter = Mockito.mock(PacketRouter.class);
94+
final PubSubEngine engine = new PubSubEngine(mockRouter);
95+
96+
final PubSubService mockService = Mockito.mock(PubSubService.class);
97+
98+
// Create a LeafNode mock configured with a very small max payload size (10 bytes).
99+
final LeafNode mockLeafNode = Mockito.mock(LeafNode.class);
100+
Mockito.when(mockLeafNode.isCollectionNode()).thenReturn(false);
101+
Mockito.when(mockLeafNode.getPublisherModel()).thenReturn(PublisherModel.open);
102+
Mockito.when(mockLeafNode.isItemRequired()).thenReturn(true);
103+
Mockito.when(mockLeafNode.getMaxPayloadSize()).thenReturn(10);
104+
Mockito.when(mockService.getNode(Mockito.anyString())).thenReturn(mockLeafNode);
105+
106+
final JID publisherJID = new JID("publisher", "example.org", "res");
107+
final IQ iq = new IQ(IQ.Type.set);
108+
iq.setFrom(publisherJID);
109+
final Element pubsubElement = iq.setChildElement("pubsub", "http://jabber.org/protocol/pubsub");
110+
final Element publishElement = pubsubElement.addElement("publish");
111+
publishElement.addAttribute("node", "test-node");
112+
final Element itemElement = publishElement.addElement("item");
113+
// Build a payload that is clearly larger than the configured maximum of 10 bytes.
114+
final Element payload = itemElement.addElement("payload");
115+
payload.setText("this-text-is-definitely-longer-than-10-bytes");
116+
117+
// Execute system under test. The publish action is submitted asynchronously; wait for it.
118+
engine.process(mockService, iq).get();
119+
120+
// Verify result: error response with not-acceptable and payload-too-big.
121+
final ArgumentCaptor<IQ> packetCaptor = ArgumentCaptor.forClass(IQ.class);
122+
Mockito.verify(mockRouter).route(packetCaptor.capture());
123+
final IQ response = packetCaptor.getValue();
124+
assertEquals(IQ.Type.error, response.getType());
125+
assertEquals(PacketError.Condition.not_acceptable, response.getError().getCondition());
126+
127+
final Element pubsubError = response.getError().getElement()
128+
.element("payload-too-big");
129+
assertNotNull(pubsubError, "Expected a 'payload-too-big' pubsub error element");
130+
}
131+
}

0 commit comments

Comments
 (0)