1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2025-09-15 03:59:38 +02:00

Prefix subprojects with 'smack-'

instead of using the old baseName=smack appendix=project.name approach,
we are now going convention over configuration and renaming the
subprojects directories to the proper name.

Having a prefix is actually very helpful, because the resulting
libraries will be named like the subproject. And a core-4.0.0-rc1.jar is
not as explicit about what it actually *is* as a
smack-core-4.0.0-rc1.jar.

SMACK-265
This commit is contained in:
Florian Schmaus 2014-04-28 19:27:53 +02:00
parent b6fb1f3743
commit 91fd15ad86
758 changed files with 42 additions and 42 deletions

View file

@ -0,0 +1,32 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class ExtensionsProviderInitializerTest {
@Test
public void testExtensionProviderInitializer() {
ExtensionsProviderInitializer ei = new ExtensionsProviderInitializer();
ei.initialize();
assertTrue(ei.getExceptions().size() == 0);
}
}

View file

@ -0,0 +1,32 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class ExtensionsStartupClassesTest {
@Test
public void testExtensiosnStartupClasses() {
ExtensionsStartupClasses esc = new ExtensionsStartupClasses();
esc.initialize();
assertTrue(esc.getExceptions().size() == 0);
}
}

View file

@ -0,0 +1,26 @@
/**
*
* Copyright 2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx;
public class InitExtensions {
static {
(new ExtensionsProviderInitializer()).initialize();
(new ExtensionsStartupClasses()).initialize();
}
}

View file

@ -0,0 +1,122 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.Test;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
import org.jivesoftware.smackx.vcardtemp.provider.VCardProvider;
public class VCardUnitTest {
@Test
public void testNoWorkHomeSpecifier_EMAIL() throws Throwable {
VCard card = VCardProvider.createVCardFromXML("<vcard><EMAIL><USERID>foo@fee.www.bar</USERID></EMAIL></vcard>");
assertEquals("foo@fee.www.bar", card.getEmailHome());
}
@Test
public void testNoWorkHomeSpecifier_TEL() throws Throwable {
VCard card = VCardProvider.createVCardFromXML("<vcard><TEL><FAX/><NUMBER>3443233</NUMBER></TEL></vcard>");
assertEquals("3443233", card.getPhoneWork("FAX"));
}
@Test
public void testNoWorkHomeSpecifier_ADDR() throws Throwable {
VCard card = VCardProvider.createVCardFromXML("<vcard><ADR><STREET>Some street</STREET><FF>ddss</FF></ADR></vcard>");
assertEquals("Some street", card.getAddressFieldWork("STREET"));
assertEquals("ddss", card.getAddressFieldWork("FF"));
}
@Test
public void testFN() throws Throwable {
VCard card = VCardProvider.createVCardFromXML("<vcard><FN>kir max</FN></vcard>");
assertEquals("kir max", card.getField("FN"));
// assertEquals("kir max", card.getFullName());
}
private final static String MIME_TYPE = "testtype";
private final static String VCARD_XML = "<vcard><PHOTO><BINVAL>" + getAvatarEncoded() + "</BINVAL><TYPE>" + MIME_TYPE + "</TYPE></PHOTO></vcard>";
@Test
public void testPhoto() throws Throwable {
VCard vc = VCardProvider.createVCardFromXML(VCARD_XML);
byte[] avatar = vc.getAvatar();
String mimeType = vc.getAvatarMimeType();
assertEquals(mimeType, MIME_TYPE);
byte[] expectedAvatar = getAvatarBinary();
assertTrue(Arrays.equals(avatar, expectedAvatar));
}
public static byte[] getAvatarBinary() {
return StringUtils.decodeBase64(getAvatarEncoded());
}
private static String getAvatarEncoded() {
return "/9j/4AAQSkZJRgABAQEASABIAAD/4QAWRXhpZgAATU0AKgAAAAgAAAAAAAD/2wBDAAUDBAQEAwUE\n" +
"BAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/\n" +
"2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e\n" +
"Hh4eHh4eHh4eHh7/wAARCABQAFADASIAAhEBAxEB/8QAHAAAAgIDAQEAAAAAAAAAAAAABwgFBgID\n" +
"BAkB/8QAORAAAgEDAwIDBwIDBwUAAAAAAQIDBAURAAYSITEHE0EIFBUiMlFxYbEjUqEkQoGR0eHw\n" +
"M0NicsH/xAAZAQADAQEBAAAAAAAAAAAAAAACAwQBAAX/xAAgEQACAgMAAwADAAAAAAAAAAAAAQIR\n" +
"AxIhBBMxMmGR/9oADAMBAAIRAxEAPwDOor6ir6RqwhH0hfX9fx++t1FbGmYRUyEg4A6k5Ot9staw\n" +
"ny4FP8R+RDNkE9s6s1TR2yzW0190QVGOiq/0k/bj21Ko2/0Miv6bKSOKyW1aeAqzjq5B+pvXXKdy\n" +
"BRyYkYOqVd9xw1crSQWiCKnXIXCDl/nj9tUu80016u8dPPdKyC3ypzMMT4ZmGAUz9hkHJz3xqlTa\n" +
"4ilRk/oYJd8WunJjlr6NJT2RplB/fWUO7AwBDhhjIIPTVSsXhltF6FXlslLKGHzNLlmb9e+uC8bC\n" +
"t9muNHJa2qKeJ5eJhErFGABbA69Ppx+M6KUnR3Y/UFa17pilK8I5JSTjIIA/rqJ3TYWeve8UlH5a\n" +
"VKjzgGGCw7N+cd/wNDykNdBKI5KgD5sjI6aJW3qyueDyJI/MjIwSDlW/00vdPjMyRlVFMqoOMhjZ\n" +
"WR/5WGD/AIffUVUUoZ8EaIlDQJXVr0VTGfLlbA/8WJ6ah9zbdms1XGkh5JMnJGx9uhB/UHQShy0T\n" +
"X2iatSxSX96RXTIYRL64Oev761+L7UduTlc3ZII8BEHdjj0GrPZbRTVV5MskKJ5vE5Ax17Hr/wA9\n" +
"NUv2p57BtHbluul4q55qjzpFo7fM4Z6h1CgovqEGQWbOACO5KqdriDxy1fQSVO8DXF4LfZ3SmQdW\n" +
"diCfX0H21Xqu+Ri726oWadY3ZgyDDBBhcgEfc4z+NBi7XGqula9VVPlmJIUdFQfZR6D/AIdc8Ukk\n" +
"MqSxO0ciMGR1OCpHYg+h0aib7h69rCoa2RK7FSVGVHpqq+KNS1NV2aGeOsZ0qTxkhcqEVhxYnH5H\n" +
"X0xoXeDfjlNZsWnejz1dGSiwV0cYaSEDCkSAYLrj5uXV8g/VkYZyJbRfrRDdqCWiudG2QskTpLFK\n" +
"uSGAIJBwQR+Rps6cEGpbWAzdFpv07T8I63hEAIwwPXPc4Hr+dTnh8246CzPdUmm8mneNJ6eo+vkx\n" +
"IIH3HTP40cK+009SvvMYCiTv9gfXX21USUswWWKCcN0yy9QNI1oZJ7dIinSasus7UsL8iiuxxhQD\n" +
"+v37nXd4g2mtjstFVVlQ0s5qWV1KBRllznH7/jVlsdsaTckwY8YXwf0C46n/AC1xeLknvtdQW2PJ\n" +
"bLSOq+nLB/Yf10VtRaJH+RYLrZaSyxz1k9XFT0VPG0ss8zBI4kUFmLMegUKCST0AGvNvxs35W+JH\n" +
"iRdN0VUk3u8r+TQRSEjyaZOka8eTBSR8zBTjm7kd9Nr7fPiDd7LsW0bZs881Ku4pJxWzxS8S1PEq\n" +
"coCMZw5mXJBHRCpyHI0i2iquAXfSV2rYLnuW8xWq1QiSaTqzMcJEg7u59FGf2AySASJv3wVu1ktE\n" +
"V0sM816jBVJ6dIP46HAHNVBPJS2eg6qCPqALC5+DO2327sVLpMh9+uwWpIDdocfwh0JByCWz0Pz4\n" +
"PbRXscVQLYWqj8zDOMems7ZbHxl69m+iOa6fiFf8L+Fe/VPw/wA/3j3XzW8nzePHzOGccuPTljOO\n" +
"mmO8TPDSy7qc1dseC1Xnk7M6wgRVGcn+IB2bkf8AqDJwTkN0wud5oJrVd622VDxvNR1EkEjRklSy\n" +
"MVJGQDjI+w0TVE08cofQneylfrlafF2gt9NXSQ2+5RzR11PnMc4SGR05A+oYDBHUZIzhiC5lPV07\n" +
"SBlmHQ9j/rpV/ZB2tSXw7pu3u6SXS1rS+5yN1KLJ53mADsCQijPfGR2Jywe3qoeeUcYcdMY7aXKT\n" +
"TLfGxp47YSTc/crcayni8xuisxOPxqFo6ee43ISVEhWpq34tIf8Atqx/c6kaFTLZ5CygoHQnp07j\n" +
"UxV0kFPNNIsfFoqlXBX8jQyl0kyJKXBS/boqZrpZtk3CKCY00T1sckvA8UZxAUUnsCQjED14t9jp\n" +
"W9ej1bbrbuKxVtnvlFFWUFbmOaGQfKQT0P3BBAIIwQQCCCAdKn4kezjuayxz3Pacvx+2qSwp8BKy\n" +
"NfmOOPaXACjK4ZmPRNV5MTXUIj8Iza/jfclaODdlL8QiUn+1UyKk3949U6I390dOOAM/MdT27vaF\n" +
"5U4ptq2Tjzw0k9xHUd8qqI3/AKnkW+44+ugPV01RR1c1JVwS09RBI0csUqFXjdTgqwPUEEEEHWrS\n" +
"KH+/JVWXCbxM3nJVvULdhGWYkKtPGVUfYZUnA/Uk6gNxXu5bguJuN2mjnqigRpFgSMsB25cAMnHT\n" +
"J64AHYDVs234Q75vfkyfDIrbTy8szXCdYfLxn6kyZBkjA+X1B7ddWOP2e94StxhvO25TnrwqJiF/\n" +
"J8rWnOOWa7ZXtgeMO/djW2ntW3rnSwW2Kfz3pGoICs7Egt5j8PMbIAXPLkFAAIwMNB4d7xsW/bdS\n" +
"3iyAwVYZYq+hZ8yUrkdc/wAynB4t2IB7EMoTbeG3rjtXctbt+6iL3ujcK5ifmjggMrKfsVIIyAev\n" +
"UA5GurZ28dwbRW5fAK+Sje40vu0siMQyDkDzTrgSABlDd1DtjBIIySs7HkeN9HFvftPeGFjWp2/D\n" +
"T326SU8oV6yhghemkYYzwZpVLAHI5YwcZBIIJLuyN5WDxB2jJubbVX59FUModJFCy08gC8opFyeL\n" +
"rkZGSCCCCVIJ8vdO97EsZtfgZWS148lbjeZZ6Y8gecYSKItgHp88bjBwemexBIuKF3bCZMDTgggg\n" +
"GZSNStuhLRlyAAGP9P8AfOoKW6Udbeqe38i0kANQwHoFHrq0WpG9yp+fdkBb8nrr1GhexDbk2zaN\n" +
"x0vul8tlHcaZG8xI6qBZVVwCOYDAjOCRn9Toe1GwNsWyqBpduWihqkBaKogoo43AIwcMoBHQkaNP\n" +
"lgxYx6ai9xWb4lQfwQBURLyjP3HqupM2NfUPwZNWAi4WmvimKxvLxB6FW1O7XpK1VXzeROe7tqSq\n" +
"/PilaGWNkkU4ZWHUayo5nV8Fv8MakU2uHr+1uIvHtW+Hl5oNy1G+6fFZaK4RLO0a/NRyKixgOP5W\n" +
"4jD9snicHiWBGvTnaFtnnmSeZCsQIKgj6v8AbV5jlDS1AXsqBRqqGJyVs8bM0pcEL9mz2e7pvivi\n" +
"3BvCirLZteMLLDHKjRS3QlQyiPsRCQQTIO4PFDnLI9NBZKKgpaCjtdPDR0YaPhBGgRI1UfKiqOgA\n" +
"CgADtrKoqPLpKaXPVXUdPtnXTNUBLlTQR4xHlj+gHT/7pjw8oTsf/9k=";
}
}

View file

@ -0,0 +1,107 @@
/**
*
* Copyright 2014 Vyacheslav Blinov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.amp;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.amp.packet.AMPExtension;
import org.jivesoftware.smackx.amp.provider.AMPExtensionProvider;
import org.junit.Before;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class AMPExtensionTest {
private InputStream CORRECT_SENDING_STANZA_STREAM;
private InputStream INCORRECT_RECEIVING_STANZA_STREAM;
@Before
public void setUp() throws IOException {
CORRECT_SENDING_STANZA_STREAM = getClass().getResourceAsStream("correct_stanza_test.xml");
INCORRECT_RECEIVING_STANZA_STREAM = getClass().getResourceAsStream("incorrect_stanza_test.xml");
}
@Test
public void isCorrectToXmlTransform() throws IOException {
String correctStanza = toString(CORRECT_SENDING_STANZA_STREAM);
AMPExtension ext = new AMPExtension();
ext.addRule(new AMPExtension.Rule(AMPExtension.Action.alert, new AMPDeliverCondition(AMPDeliverCondition.Value.direct)));
ext.addRule(new AMPExtension.Rule(AMPExtension.Action.drop, new AMPDeliverCondition(AMPDeliverCondition.Value.forward)));
ext.addRule(new AMPExtension.Rule(AMPExtension.Action.error, new AMPDeliverCondition(AMPDeliverCondition.Value.gateway)));
ext.addRule(new AMPExtension.Rule(AMPExtension.Action.notify, new AMPDeliverCondition(AMPDeliverCondition.Value.none)));
ext.addRule(new AMPExtension.Rule(AMPExtension.Action.notify, new AMPDeliverCondition(AMPDeliverCondition.Value.stored)));
ext.addRule(new AMPExtension.Rule(AMPExtension.Action.notify, new AMPExpireAtCondition("2004-09-10T08:33:14Z")));
ext.addRule(new AMPExtension.Rule(AMPExtension.Action.notify, new AMPMatchResourceCondition(AMPMatchResourceCondition.Value.any)));
ext.addRule(new AMPExtension.Rule(AMPExtension.Action.notify, new AMPMatchResourceCondition(AMPMatchResourceCondition.Value.exact)));
ext.addRule(new AMPExtension.Rule(AMPExtension.Action.notify, new AMPMatchResourceCondition(AMPMatchResourceCondition.Value.other)));
assertEquals(correctStanza, ext.toXML());
}
@Test
public void isCorrectFromXmlErrorHandling() throws Exception {
AMPExtensionProvider ampProvider = new AMPExtensionProvider();
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(INCORRECT_RECEIVING_STANZA_STREAM, "UTF-8");
assertEquals(XmlPullParser.START_TAG, parser.next());
assertEquals(AMPExtension.ELEMENT, parser.getName());
PacketExtension extension = ampProvider.parseExtension(parser);
assertTrue(extension instanceof AMPExtension);
AMPExtension amp = (AMPExtension) extension;
assertEquals(0, amp.getRulesCount());
assertEquals(AMPExtension.Status.alert, amp.getStatus());
assertEquals("bernardo@hamlet.lit/elsinore", amp.getFrom());
assertEquals("francisco@hamlet.lit", amp.getTo());
}
@Test
public void isCorrectFromXmlDeserialization() throws Exception {
AMPExtensionProvider ampProvider = new AMPExtensionProvider();
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(CORRECT_SENDING_STANZA_STREAM, "UTF-8");
assertEquals(XmlPullParser.START_TAG, parser.next());
assertEquals(AMPExtension.ELEMENT, parser.getName());
PacketExtension extension = ampProvider.parseExtension(parser);
assertTrue(extension instanceof AMPExtension);
AMPExtension amp = (AMPExtension) extension;
assertEquals(9, amp.getRulesCount());
}
private String toString(InputStream stream) throws IOException {
byte[] data = new byte[stream.available()];
stream.read(data);
stream.close();
return new String(data, Charset.defaultCharset());
}
}

View file

@ -0,0 +1,82 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.bytestreams.ibb.CloseListener;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.powermock.reflect.Whitebox;
/**
* Test for the CloseListener class.
*
* @author Henning Staib
*/
public class CloseListenerTest {
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
/**
* If a close request to an unknown session is received it should be replied
* with an &lt;item-not-found/&gt; error.
*
* @throws Exception should not happen
*/
@Test
public void shouldReplyErrorIfSessionIsUnknown() throws Exception {
// mock connection
XMPPConnection connection = mock(XMPPConnection.class);
// initialize InBandBytestreamManager to get the CloseListener
InBandBytestreamManager byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
// get the CloseListener from InBandByteStreamManager
CloseListener closeListener = Whitebox.getInternalState(byteStreamManager,
CloseListener.class);
Close close = new Close("unknownSessionId");
close.setFrom(initiatorJID);
close.setTo(targetJID);
closeListener.processPacket(close);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// capture reply to the In-Band Bytestream close request
ArgumentCaptor<IQ> argument = ArgumentCaptor.forClass(IQ.class);
verify(connection).sendPacket(argument.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, argument.getValue().getTo());
assertEquals(IQ.Type.ERROR, argument.getValue().getType());
assertEquals(XMPPError.Condition.item_not_found.toString(),
argument.getValue().getError().getCondition());
}
}

View file

@ -0,0 +1,84 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.bytestreams.ibb.DataListener;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.powermock.reflect.Whitebox;
/**
* Test for the CloseListener class.
*
* @author Henning Staib
*/
public class DataListenerTest {
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
/**
* If a data packet of an unknown session is received it should be replied
* with an &lt;item-not-found/&gt; error.
*
* @throws Exception should not happen
*/
@Test
public void shouldReplyErrorIfSessionIsUnknown() throws Exception {
// mock connection
XMPPConnection connection = mock(XMPPConnection.class);
// initialize InBandBytestreamManager to get the DataListener
InBandBytestreamManager byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
// get the DataListener from InBandByteStreamManager
DataListener dataListener = Whitebox.getInternalState(byteStreamManager,
DataListener.class);
DataPacketExtension dpe = new DataPacketExtension("unknownSessionID", 0, "Data");
Data data = new Data(dpe);
data.setFrom(initiatorJID);
data.setTo(targetJID);
dataListener.processPacket(data);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// capture reply to the In-Band Bytestream close request
ArgumentCaptor<IQ> argument = ArgumentCaptor.forClass(IQ.class);
verify(connection).sendPacket(argument.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, argument.getValue().getTo());
assertEquals(IQ.Type.ERROR, argument.getValue().getType());
assertEquals(XMPPError.Condition.item_not_found.toString(),
argument.getValue().getError().getCondition());
}
}

View file

@ -0,0 +1,73 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
/**
* Utility methods to create packets.
*
* @author Henning Staib
*/
public class IBBPacketUtils {
/**
* Returns an error IQ.
*
* @param from the senders JID
* @param to the recipients JID
* @param xmppError the XMPP error
* @return an error IQ
*/
public static IQ createErrorIQ(String from, String to, XMPPError xmppError) {
IQ errorIQ = new IQ() {
public String getChildElementXML() {
return null;
}
};
errorIQ.setType(IQ.Type.ERROR);
errorIQ.setFrom(from);
errorIQ.setTo(to);
errorIQ.setError(xmppError);
return errorIQ;
}
/**
* Returns a result IQ.
*
* @param from the senders JID
* @param to the recipients JID
* @return a result IQ
*/
public static IQ createResultIQ(String from, String to) {
IQ result = new IQ() {
public String getChildElementXML() {
return null;
}
};
result.setType(IQ.Type.RESULT);
result.setFrom(from);
result.setTo(to);
return result;
}
}

View file

@ -0,0 +1,37 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import org.jivesoftware.smackx.bytestreams.ibb.packet.CloseTest;
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtensionTest;
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataTest;
import org.jivesoftware.smackx.bytestreams.ibb.packet.OpenTest;
import org.jivesoftware.smackx.bytestreams.ibb.provider.OpenIQProviderTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses( { CloseTest.class, DataPacketExtensionTest.class, DataTest.class,
OpenTest.class, OpenIQProviderTest.class, CloseListenerTest.class,
DataListenerTest.class, InBandBytestreamManagerTest.class,
InBandBytestreamRequestTest.class,
InBandBytestreamSessionMessageTest.class,
InBandBytestreamSessionTest.class, InitiationListenerTest.class })
public class IBBTestsSuite {
// the class remains completely empty,
// being used only as a holder for the above annotations
}

View file

@ -0,0 +1,196 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.StanzaType;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.jivesoftware.util.ConnectionUtils;
import org.jivesoftware.util.Protocol;
import org.jivesoftware.util.Verification;
import org.junit.Before;
import org.junit.Test;
/**
* Test for InBandBytestreamManager.
*
* @author Henning Staib
*/
public class InBandBytestreamManagerTest {
// settings
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
String xmppServer = "xmpp-server";
String sessionID = "session_id";
// protocol verifier
Protocol protocol;
// mocked XMPP connection
XMPPConnection connection;
/**
* Initialize fields used in the tests.
* @throws XMPPException
* @throws SmackException
*/
@Before
public void setup() throws XMPPException, SmackException {
// build protocol verifier
protocol = new Protocol();
// create mocked XMPP connection
connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID,
xmppServer);
}
/**
* Test that
* {@link InBandBytestreamManager#getByteStreamManager(XMPPConnection)} returns
* one bytestream manager for every connection
*/
@Test
public void shouldHaveOneManagerForEveryConnection() {
// mock two connections
XMPPConnection connection1 = mock(XMPPConnection.class);
XMPPConnection connection2 = mock(XMPPConnection.class);
// get bytestream manager for the first connection twice
InBandBytestreamManager conn1ByteStreamManager1 = InBandBytestreamManager.getByteStreamManager(connection1);
InBandBytestreamManager conn1ByteStreamManager2 = InBandBytestreamManager.getByteStreamManager(connection1);
// get bytestream manager for second connection
InBandBytestreamManager conn2ByteStreamManager1 = InBandBytestreamManager.getByteStreamManager(connection2);
// assertions
assertEquals(conn1ByteStreamManager1, conn1ByteStreamManager2);
assertNotSame(conn1ByteStreamManager1, conn2ByteStreamManager1);
}
/**
* Invoking {@link InBandBytestreamManager#establishSession(String)} should
* throw an exception if the given target does not support in-band
* bytestream.
* @throws SmackException
* @throws XMPPException
*/
@Test
public void shouldFailIfTargetDoesNotSupportIBB() throws SmackException, XMPPException {
InBandBytestreamManager byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
try {
XMPPError xmppError = new XMPPError(
XMPPError.Condition.feature_not_implemented);
IQ errorIQ = IBBPacketUtils.createErrorIQ(targetJID, initiatorJID, xmppError);
protocol.addResponse(errorIQ);
// start In-Band Bytestream
byteStreamManager.establishSession(targetJID);
fail("exception should be thrown");
}
catch (XMPPErrorException e) {
assertEquals(XMPPError.Condition.feature_not_implemented.toString(),
e.getXMPPError().getCondition());
}
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotAllowTooBigDefaultBlockSize() {
InBandBytestreamManager byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
byteStreamManager.setDefaultBlockSize(1000000);
}
@Test
public void shouldCorrectlySetDefaultBlockSize() {
InBandBytestreamManager byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
byteStreamManager.setDefaultBlockSize(1024);
assertEquals(1024, byteStreamManager.getDefaultBlockSize());
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotAllowTooBigMaximumBlockSize() {
InBandBytestreamManager byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
byteStreamManager.setMaximumBlockSize(1000000);
}
@Test
public void shouldCorrectlySetMaximumBlockSize() {
InBandBytestreamManager byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
byteStreamManager.setMaximumBlockSize(1024);
assertEquals(1024, byteStreamManager.getMaximumBlockSize());
}
@Test
public void shouldUseConfiguredStanzaType() throws SmackException {
InBandBytestreamManager byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
byteStreamManager.setStanza(StanzaType.MESSAGE);
protocol.addResponse(null, new Verification<Open, IQ>() {
public void verify(Open request, IQ response) {
assertEquals(StanzaType.MESSAGE, request.getStanza());
}
});
try {
// start In-Band Bytestream
byteStreamManager.establishSession(targetJID);
}
catch (XMPPException e) {
protocol.verifyAll();
}
}
@Test
public void shouldReturnSession() throws Exception {
InBandBytestreamManager byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
IQ success = IBBPacketUtils.createResultIQ(targetJID, initiatorJID);
protocol.addResponse(success, Verification.correspondingSenderReceiver,
Verification.requestTypeSET);
// start In-Band Bytestream
InBandBytestreamSession session = byteStreamManager.establishSession(targetJID);
assertNotNull(session);
assertNotNull(session.getInputStream());
assertNotNull(session.getOutputStream());
protocol.verifyAll();
}
}

View file

@ -0,0 +1,119 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
/**
* Test for InBandBytestreamRequest.
*
* @author Henning Staib
*/
public class InBandBytestreamRequestTest {
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
String sessionID = "session_id";
XMPPConnection connection;
InBandBytestreamManager byteStreamManager;
Open initBytestream;
/**
* Initialize fields used in the tests.
*/
@Before
public void setup() {
// mock connection
connection = mock(XMPPConnection.class);
// initialize InBandBytestreamManager to get the InitiationListener
byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
// create a In-Band Bytestream open packet
initBytestream = new Open(sessionID, 4096);
initBytestream.setFrom(initiatorJID);
initBytestream.setTo(targetJID);
}
/**
* Test reject() method.
* @throws NotConnectedException
*/
@Test
public void shouldReplyWithErrorIfRequestIsRejected() throws NotConnectedException {
InBandBytestreamRequest ibbRequest = new InBandBytestreamRequest(
byteStreamManager, initBytestream);
// reject request
ibbRequest.reject();
// capture reply to the In-Band Bytestream open request
ArgumentCaptor<IQ> argument = ArgumentCaptor.forClass(IQ.class);
verify(connection).sendPacket(argument.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, argument.getValue().getTo());
assertEquals(IQ.Type.ERROR, argument.getValue().getType());
assertEquals(XMPPError.Condition.no_acceptable.toString(),
argument.getValue().getError().getCondition());
}
/**
* Test accept() method.
*
* @throws Exception should not happen
*/
@Test
public void shouldReturnSessionIfRequestIsAccepted() throws Exception {
InBandBytestreamRequest ibbRequest = new InBandBytestreamRequest(
byteStreamManager, initBytestream);
// accept request
InBandBytestreamSession session = ibbRequest.accept();
// capture reply to the In-Band Bytestream open request
ArgumentCaptor<IQ> argument = ArgumentCaptor.forClass(IQ.class);
verify(connection).sendPacket(argument.capture());
// assert that reply is the correct acknowledgment packet
assertEquals(initiatorJID, argument.getValue().getTo());
assertEquals(IQ.Type.RESULT, argument.getValue().getType());
assertNotNull(session);
assertNotNull(session.getInputStream());
assertNotNull(session.getOutputStream());
}
}

View file

@ -0,0 +1,376 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Random;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.StanzaType;
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.jivesoftware.util.ConnectionUtils;
import org.jivesoftware.util.Protocol;
import org.jivesoftware.util.Verification;
import org.junit.Before;
import org.junit.Test;
import org.powermock.reflect.Whitebox;
/**
* Test for InBandBytestreamSession.
* <p>
* Tests sending data encapsulated in message stanzas.
*
* @author Henning Staib
*/
public class InBandBytestreamSessionMessageTest {
// settings
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
String xmppServer = "xmpp-server";
String sessionID = "session_id";
int blockSize = 10;
// protocol verifier
Protocol protocol;
// mocked XMPP connection
XMPPConnection connection;
InBandBytestreamManager byteStreamManager;
Open initBytestream;
Verification<Message, IQ> incrementingSequence;
/**
* Initialize fields used in the tests.
* @throws XMPPException
* @throws SmackException
*/
@Before
public void setup() throws XMPPException, SmackException {
// build protocol verifier
protocol = new Protocol();
// create mocked XMPP connection
connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID, xmppServer);
// initialize InBandBytestreamManager to get the InitiationListener
byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
// create a In-Band Bytestream open packet with message stanza
initBytestream = new Open(sessionID, blockSize, StanzaType.MESSAGE);
initBytestream.setFrom(initiatorJID);
initBytestream.setTo(targetJID);
incrementingSequence = new Verification<Message, IQ>() {
long lastSeq = 0;
public void verify(Message request, IQ response) {
DataPacketExtension dpe = (DataPacketExtension) request.getExtension(
DataPacketExtension.ELEMENT_NAME, InBandBytestreamManager.NAMESPACE);
assertEquals(lastSeq++, dpe.getSeq());
}
};
}
/**
* Test the output stream write(byte[]) method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendThreeDataPackets1() throws Exception {
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// verify the data packets
protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence);
byte[] controlData = new byte[blockSize * 3];
OutputStream outputStream = session.getOutputStream();
outputStream.write(controlData);
outputStream.flush();
protocol.verifyAll();
}
/**
* Test the output stream write(byte) method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendThreeDataPackets2() throws Exception {
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// verify the data packets
protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence);
byte[] controlData = new byte[blockSize * 3];
OutputStream outputStream = session.getOutputStream();
for (byte b : controlData) {
outputStream.write(b);
}
outputStream.flush();
protocol.verifyAll();
}
/**
* Test the output stream write(byte[], int, int) method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendThreeDataPackets3() throws Exception {
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// verify the data packets
protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence);
byte[] controlData = new byte[(blockSize * 3) - 2];
OutputStream outputStream = session.getOutputStream();
int off = 0;
for (int i = 1; i <= 7; i++) {
outputStream.write(controlData, off, i);
off += i;
}
outputStream.flush();
protocol.verifyAll();
}
/**
* Test the output stream flush() method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendThirtyDataPackets() throws Exception {
byte[] controlData = new byte[blockSize * 3];
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// verify the data packets
for (int i = 0; i < controlData.length; i++) {
protocol.addResponse(null, incrementingSequence);
}
OutputStream outputStream = session.getOutputStream();
for (byte b : controlData) {
outputStream.write(b);
outputStream.flush();
}
protocol.verifyAll();
}
/**
* Test successive calls to the output stream flush() method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendNothingOnSuccessiveCallsToFlush() throws Exception {
byte[] controlData = new byte[blockSize * 3];
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// verify the data packets
protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence);
OutputStream outputStream = session.getOutputStream();
outputStream.write(controlData);
outputStream.flush();
outputStream.flush();
outputStream.flush();
protocol.verifyAll();
}
/**
* If a data packet is received out of order the session should be closed. See XEP-0047 Section
* 2.2.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendCloseRequestIfInvalidSequenceReceived() throws Exception {
// confirm close request
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
protocol.addResponse(resultIQ, Verification.requestTypeSET,
Verification.correspondingSenderReceiver);
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// build invalid packet with out of order sequence
String base64Data = StringUtils.encodeBase64("Data");
DataPacketExtension dpe = new DataPacketExtension(sessionID, 123, base64Data);
Message dataMessage = new Message();
dataMessage.addExtension(dpe);
// add data packets
listener.processPacket(dataMessage);
// read until exception is thrown
try {
inputStream.read();
fail("exception should be thrown");
}
catch (IOException e) {
assertTrue(e.getMessage().contains("Packets out of sequence"));
}
protocol.verifyAll();
}
/**
* Test the input stream read(byte[], int, int) method.
*
* @throws Exception should not happen
*/
@Test
public void shouldReadAllReceivedData1() throws Exception {
// create random data
Random rand = new Random();
byte[] controlData = new byte[3 * blockSize];
rand.nextBytes(controlData);
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// verify data packet and notify listener
for (int i = 0; i < controlData.length / blockSize; i++) {
String base64Data = StringUtils.encodeBase64(controlData, i * blockSize, blockSize,
false);
DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data);
Message dataMessage = new Message();
dataMessage.addExtension(dpe);
listener.processPacket(dataMessage);
}
byte[] bytes = new byte[3 * blockSize];
int read = 0;
read = inputStream.read(bytes, 0, blockSize);
assertEquals(blockSize, read);
read = inputStream.read(bytes, 10, blockSize);
assertEquals(blockSize, read);
read = inputStream.read(bytes, 20, blockSize);
assertEquals(blockSize, read);
// verify data
for (int i = 0; i < bytes.length; i++) {
assertEquals(controlData[i], bytes[i]);
}
protocol.verifyAll();
}
/**
* Test the input stream read() method.
*
* @throws Exception should not happen
*/
@Test
public void shouldReadAllReceivedData2() throws Exception {
// create random data
Random rand = new Random();
byte[] controlData = new byte[3 * blockSize];
rand.nextBytes(controlData);
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// verify data packet and notify listener
for (int i = 0; i < controlData.length / blockSize; i++) {
String base64Data = StringUtils.encodeBase64(controlData, i * blockSize, blockSize,
false);
DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data);
Message dataMessage = new Message();
dataMessage.addExtension(dpe);
listener.processPacket(dataMessage);
}
// read data
byte[] bytes = new byte[3 * blockSize];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) inputStream.read();
}
// verify data
for (int i = 0; i < bytes.length; i++) {
assertEquals(controlData[i], bytes[i]);
}
protocol.verifyAll();
}
}

View file

@ -0,0 +1,720 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Random;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.jivesoftware.util.ConnectionUtils;
import org.jivesoftware.util.Protocol;
import org.jivesoftware.util.Verification;
import org.junit.Before;
import org.junit.Test;
import org.powermock.reflect.Whitebox;
/**
* Test for InBandBytestreamSession.
* <p>
* Tests the basic behavior of an In-Band Bytestream session along with sending data encapsulated in
* IQ stanzas.
*
* @author Henning Staib
*/
public class InBandBytestreamSessionTest {
// settings
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
String xmppServer = "xmpp-server";
String sessionID = "session_id";
int blockSize = 10;
// protocol verifier
Protocol protocol;
// mocked XMPP connection
XMPPConnection connection;
InBandBytestreamManager byteStreamManager;
Open initBytestream;
Verification<Data, IQ> incrementingSequence;
/**
* Initialize fields used in the tests.
* @throws XMPPException
* @throws SmackException
*/
@Before
public void setup() throws XMPPException, SmackException {
// build protocol verifier
protocol = new Protocol();
// create mocked XMPP connection
connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID, xmppServer);
// initialize InBandBytestreamManager to get the InitiationListener
byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
// create a In-Band Bytestream open packet
initBytestream = new Open(sessionID, blockSize);
initBytestream.setFrom(initiatorJID);
initBytestream.setTo(targetJID);
incrementingSequence = new Verification<Data, IQ>() {
long lastSeq = 0;
public void verify(Data request, IQ response) {
assertEquals(lastSeq++, request.getDataPacketExtension().getSeq());
}
};
}
/**
* Test the output stream write(byte[]) method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendThreeDataPackets1() throws Exception {
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// set acknowledgments for the data packets
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence);
byte[] controlData = new byte[blockSize * 3];
OutputStream outputStream = session.getOutputStream();
outputStream.write(controlData);
outputStream.flush();
protocol.verifyAll();
}
/**
* Test the output stream write(byte) method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendThreeDataPackets2() throws Exception {
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// set acknowledgments for the data packets
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence);
byte[] controlData = new byte[blockSize * 3];
OutputStream outputStream = session.getOutputStream();
for (byte b : controlData) {
outputStream.write(b);
}
outputStream.flush();
protocol.verifyAll();
}
/**
* Test the output stream write(byte[], int, int) method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendThreeDataPackets3() throws Exception {
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// set acknowledgments for the data packets
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence);
byte[] controlData = new byte[(blockSize * 3) - 2];
OutputStream outputStream = session.getOutputStream();
int off = 0;
for (int i = 1; i <= 7; i++) {
outputStream.write(controlData, off, i);
off += i;
}
outputStream.flush();
protocol.verifyAll();
}
/**
* Test the output stream flush() method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendThirtyDataPackets() throws Exception {
byte[] controlData = new byte[blockSize * 3];
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// set acknowledgments for the data packets
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
for (int i = 0; i < controlData.length; i++) {
protocol.addResponse(resultIQ, incrementingSequence);
}
OutputStream outputStream = session.getOutputStream();
for (byte b : controlData) {
outputStream.write(b);
outputStream.flush();
}
protocol.verifyAll();
}
/**
* Test successive calls to the output stream flush() method.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendNothingOnSuccessiveCallsToFlush() throws Exception {
byte[] controlData = new byte[blockSize * 3];
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
// set acknowledgments for the data packets
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence);
OutputStream outputStream = session.getOutputStream();
outputStream.write(controlData);
outputStream.flush();
outputStream.flush();
outputStream.flush();
protocol.verifyAll();
}
/**
* Test that the data is correctly chunked.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendDataCorrectly() throws Exception {
// create random data
Random rand = new Random();
final byte[] controlData = new byte[256 * blockSize];
rand.nextBytes(controlData);
// compares the data of each packet with the control data
Verification<Data, IQ> dataVerification = new Verification<Data, IQ>() {
public void verify(Data request, IQ response) {
byte[] decodedData = request.getDataPacketExtension().getDecodedData();
int seq = (int) request.getDataPacketExtension().getSeq();
for (int i = 0; i < decodedData.length; i++) {
assertEquals(controlData[(seq * blockSize) + i], decodedData[i]);
}
}
};
// set acknowledgments for the data packets
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
for (int i = 0; i < controlData.length / blockSize; i++) {
protocol.addResponse(resultIQ, incrementingSequence, dataVerification);
}
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
OutputStream outputStream = session.getOutputStream();
outputStream.write(controlData);
outputStream.flush();
protocol.verifyAll();
}
/**
* If the input stream is closed the output stream should not be closed as well.
*
* @throws Exception should not happen
*/
@Test
public void shouldNotCloseBothStreamsIfOutputStreamIsClosed() throws Exception {
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
OutputStream outputStream = session.getOutputStream();
outputStream.close();
// verify data packet confirmation is of type RESULT
protocol.addResponse(null, Verification.requestTypeRESULT);
// insert data to read
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
String base64Data = StringUtils.encodeBase64("Data");
DataPacketExtension dpe = new DataPacketExtension(sessionID, 0, base64Data);
Data data = new Data(dpe);
listener.processPacket(data);
// verify no packet send
protocol.verifyAll();
try {
outputStream.flush();
fail("should throw an exception");
}
catch (IOException e) {
assertTrue(e.getMessage().contains("closed"));
}
assertTrue(inputStream.read() != 0);
}
/**
* Valid data packets should be confirmed.
*
* @throws Exception should not happen
*/
@Test
public void shouldConfirmReceivedDataPacket() throws Exception {
// verify data packet confirmation is of type RESULT
protocol.addResponse(null, Verification.requestTypeRESULT);
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
String base64Data = StringUtils.encodeBase64("Data");
DataPacketExtension dpe = new DataPacketExtension(sessionID, 0, base64Data);
Data data = new Data(dpe);
listener.processPacket(data);
protocol.verifyAll();
}
/**
* If the data packet has a sequence that is already used an 'unexpected-request' error should
* be returned. See XEP-0047 Section 2.2.
*
* @throws Exception should not happen
*/
@Test
public void shouldReplyWithErrorIfAlreadyUsedSequenceIsReceived() throws Exception {
// verify reply to first valid data packet is of type RESULT
protocol.addResponse(null, Verification.requestTypeRESULT);
// verify reply to invalid data packet is an error
protocol.addResponse(null, Verification.requestTypeERROR, new Verification<IQ, IQ>() {
public void verify(IQ request, IQ response) {
assertEquals(XMPPError.Condition.unexpected_request.toString(),
request.getError().getCondition());
}
});
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// build data packets
String base64Data = StringUtils.encodeBase64("Data");
DataPacketExtension dpe = new DataPacketExtension(sessionID, 0, base64Data);
Data data1 = new Data(dpe);
Data data2 = new Data(dpe);
// notify listener
listener.processPacket(data1);
listener.processPacket(data2);
protocol.verifyAll();
}
/**
* If the data packet contains invalid Base64 encoding an 'bad-request' error should be
* returned. See XEP-0047 Section 2.2.
*
* @throws Exception should not happen
*/
@Test
public void shouldReplyWithErrorIfDataIsInvalid() throws Exception {
// verify reply to invalid data packet is an error
protocol.addResponse(null, Verification.requestTypeERROR, new Verification<IQ, IQ>() {
public void verify(IQ request, IQ response) {
assertEquals(XMPPError.Condition.bad_request.toString(),
request.getError().getCondition());
}
});
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// build data packets
DataPacketExtension dpe = new DataPacketExtension(sessionID, 0, "AA=BB");
Data data = new Data(dpe);
// notify listener
listener.processPacket(data);
protocol.verifyAll();
}
/**
* If a data packet is received out of order the session should be closed. See XEP-0047 Section
* 2.2.
*
* @throws Exception should not happen
*/
@Test
public void shouldSendCloseRequestIfInvalidSequenceReceived() throws Exception {
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
// confirm data packet with invalid sequence
protocol.addResponse(resultIQ);
// confirm close request
protocol.addResponse(resultIQ, Verification.requestTypeSET,
Verification.correspondingSenderReceiver);
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// build invalid packet with out of order sequence
String base64Data = StringUtils.encodeBase64("Data");
DataPacketExtension dpe = new DataPacketExtension(sessionID, 123, base64Data);
Data data = new Data(dpe);
// add data packets
listener.processPacket(data);
// read until exception is thrown
try {
inputStream.read();
fail("exception should be thrown");
}
catch (IOException e) {
assertTrue(e.getMessage().contains("Packets out of sequence"));
}
protocol.verifyAll();
}
/**
* Test the input stream read(byte[], int, int) method.
*
* @throws Exception should not happen
*/
@Test
public void shouldReadAllReceivedData1() throws Exception {
// create random data
Random rand = new Random();
byte[] controlData = new byte[3 * blockSize];
rand.nextBytes(controlData);
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// set data packet acknowledgment and notify listener
for (int i = 0; i < controlData.length / blockSize; i++) {
protocol.addResponse(resultIQ);
String base64Data = StringUtils.encodeBase64(controlData, i * blockSize, blockSize,
false);
DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data);
Data data = new Data(dpe);
listener.processPacket(data);
}
byte[] bytes = new byte[3 * blockSize];
int read = 0;
read = inputStream.read(bytes, 0, blockSize);
assertEquals(blockSize, read);
read = inputStream.read(bytes, 10, blockSize);
assertEquals(blockSize, read);
read = inputStream.read(bytes, 20, blockSize);
assertEquals(blockSize, read);
// verify data
for (int i = 0; i < bytes.length; i++) {
assertEquals(controlData[i], bytes[i]);
}
protocol.verifyAll();
}
/**
* Test the input stream read() method.
*
* @throws Exception should not happen
*/
@Test
public void shouldReadAllReceivedData2() throws Exception {
// create random data
Random rand = new Random();
byte[] controlData = new byte[3 * blockSize];
rand.nextBytes(controlData);
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// set data packet acknowledgment and notify listener
for (int i = 0; i < controlData.length / blockSize; i++) {
protocol.addResponse(resultIQ);
String base64Data = StringUtils.encodeBase64(controlData, i * blockSize, blockSize,
false);
DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data);
Data data = new Data(dpe);
listener.processPacket(data);
}
// read data
byte[] bytes = new byte[3 * blockSize];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) inputStream.read();
}
// verify data
for (int i = 0; i < bytes.length; i++) {
assertEquals(controlData[i], bytes[i]);
}
protocol.verifyAll();
}
/**
* If the output stream is closed the input stream should not be closed as well.
*
* @throws Exception should not happen
*/
@Test
public void shouldNotCloseBothStreamsIfInputStreamIsClosed() throws Exception {
// acknowledgment for data packet
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
protocol.addResponse(resultIQ);
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// build data packet
String base64Data = StringUtils.encodeBase64("Data");
DataPacketExtension dpe = new DataPacketExtension(sessionID, 0, base64Data);
Data data = new Data(dpe);
// add data packets
listener.processPacket(data);
inputStream.close();
protocol.verifyAll();
try {
while (inputStream.read() != -1) {
}
inputStream.read();
fail("should throw an exception");
}
catch (IOException e) {
assertTrue(e.getMessage().contains("closed"));
}
session.getOutputStream().flush();
}
/**
* If the session is closed the input stream and output stream should be closed as well.
*
* @throws Exception should not happen
*/
@Test
public void shouldCloseBothStreamsIfSessionIsClosed() throws Exception {
// acknowledgment for data packet
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
protocol.addResponse(resultIQ);
// acknowledgment for close request
protocol.addResponse(resultIQ, Verification.correspondingSenderReceiver,
Verification.requestTypeSET);
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// build data packet
String base64Data = StringUtils.encodeBase64("Data");
DataPacketExtension dpe = new DataPacketExtension(sessionID, 0, base64Data);
Data data = new Data(dpe);
// add data packets
listener.processPacket(data);
session.close();
protocol.verifyAll();
try {
while (inputStream.read() != -1) {
}
inputStream.read();
fail("should throw an exception");
}
catch (IOException e) {
assertTrue(e.getMessage().contains("closed"));
}
try {
session.getOutputStream().flush();
fail("should throw an exception");
}
catch (IOException e) {
assertTrue(e.getMessage().contains("closed"));
}
}
/**
* If the input stream is closed concurrently there should be no deadlock.
*
* @throws Exception should not happen
*/
@Test
public void shouldNotDeadlockIfInputStreamIsClosed() throws Exception {
// acknowledgment for data packet
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
protocol.addResponse(resultIQ);
// get IBB sessions data packet listener
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID);
final InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// build data packet
String base64Data = StringUtils.encodeBase64("Data");
DataPacketExtension dpe = new DataPacketExtension(sessionID, 0, base64Data);
Data data = new Data(dpe);
// add data packets
listener.processPacket(data);
Thread closer = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(200);
inputStream.close();
}
catch (Exception e) {
fail(e.getMessage());
}
}
});
closer.start();
try {
byte[] bytes = new byte[20];
while (inputStream.read(bytes) != -1) {
}
inputStream.read();
fail("should throw an exception");
}
catch (IOException e) {
assertTrue(e.getMessage().contains("closed"));
}
protocol.verifyAll();
}
}

View file

@ -0,0 +1,333 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamListener;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
import org.jivesoftware.smackx.bytestreams.ibb.InitiationListener;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.powermock.reflect.Whitebox;
/**
* Test for the InitiationListener class.
*
* @author Henning Staib
*/
public class InitiationListenerTest {
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
String sessionID = "session_id";
XMPPConnection connection;
InBandBytestreamManager byteStreamManager;
InitiationListener initiationListener;
Open initBytestream;
/**
* Initialize fields used in the tests.
*/
@Before
public void setup() {
// mock connection
connection = mock(XMPPConnection.class);
// initialize InBandBytestreamManager to get the InitiationListener
byteStreamManager = InBandBytestreamManager.getByteStreamManager(connection);
// get the InitiationListener from InBandByteStreamManager
initiationListener = Whitebox.getInternalState(byteStreamManager, InitiationListener.class);
// create a In-Band Bytestream open packet
initBytestream = new Open(sessionID, 4096);
initBytestream.setFrom(initiatorJID);
initBytestream.setTo(targetJID);
}
/**
* If no listeners are registered for incoming In-Band Bytestream requests, all request should
* be rejected with an error.
*
* @throws Exception should not happen
*/
@Test
public void shouldRespondWithError() throws Exception {
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// capture reply to the In-Band Bytestream open request
ArgumentCaptor<IQ> argument = ArgumentCaptor.forClass(IQ.class);
verify(connection).sendPacket(argument.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, argument.getValue().getTo());
assertEquals(IQ.Type.ERROR, argument.getValue().getType());
assertEquals(XMPPError.Condition.no_acceptable.toString(),
argument.getValue().getError().getCondition());
}
/**
* Open request with a block size that exceeds the maximum block size should be replied with an
* resource-constraint error.
*
* @throws Exception should not happen
*/
@Test
public void shouldRejectRequestWithTooBigBlockSize() throws Exception {
byteStreamManager.setMaximumBlockSize(1024);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// capture reply to the In-Band Bytestream open request
ArgumentCaptor<IQ> argument = ArgumentCaptor.forClass(IQ.class);
verify(connection).sendPacket(argument.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, argument.getValue().getTo());
assertEquals(IQ.Type.ERROR, argument.getValue().getType());
assertEquals(XMPPError.Condition.resource_constraint.toString(),
argument.getValue().getError().getCondition());
}
/**
* If a listener for all requests is registered it should be notified on incoming requests.
*
* @throws Exception should not happen
*/
@Test
public void shouldInvokeListenerForAllRequests() throws Exception {
// add listener
InBandBytestreamListener listener = mock(InBandBytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(listener);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert listener is called once
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(listener).incomingBytestreamRequest(byteStreamRequest.capture());
// assert that listener is called for the correct request
assertEquals(initiatorJID, byteStreamRequest.getValue().getFrom());
}
/**
* If a listener for a specific user in registered it should be notified on incoming requests
* for that user.
*
* @throws Exception should not happen
*/
@Test
public void shouldInvokeListenerForUser() throws Exception {
// add listener
InBandBytestreamListener listener = mock(InBandBytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(listener, initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert listener is called once
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(listener).incomingBytestreamRequest(byteStreamRequest.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, byteStreamRequest.getValue().getFrom());
}
/**
* If listener for a specific user is registered it should not be notified on incoming requests
* from other users.
*
* @throws Exception should not happen
*/
@Test
public void shouldNotInvokeListenerForUser() throws Exception {
// add listener for request of user "other_initiator"
InBandBytestreamListener listener = mock(InBandBytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(listener, "other_" + initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert listener is not called
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(listener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// capture reply to the In-Band Bytestream open request
ArgumentCaptor<IQ> argument = ArgumentCaptor.forClass(IQ.class);
verify(connection).sendPacket(argument.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, argument.getValue().getTo());
assertEquals(IQ.Type.ERROR, argument.getValue().getType());
assertEquals(XMPPError.Condition.no_acceptable.toString(),
argument.getValue().getError().getCondition());
}
/**
* If a user specific listener and an all requests listener is registered only the user specific
* listener should be notified.
*
* @throws Exception should not happen
*/
@Test
public void shouldNotInvokeAllRequestsListenerIfUserListenerExists() throws Exception {
// add listener for all request
InBandBytestreamListener allRequestsListener = mock(InBandBytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(allRequestsListener);
// add listener for request of user "initiator"
InBandBytestreamListener userRequestsListener = mock(InBandBytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(userRequestsListener, initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert user request listener is called once
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(userRequestsListener).incomingBytestreamRequest(byteStreamRequest.capture());
// assert all requests listener is not called
byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(allRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
}
/**
* If a user specific listener and an all requests listener is registered only the all requests
* listener should be notified on an incoming request for another user.
*
* @throws Exception should not happen
*/
@Test
public void shouldInvokeAllRequestsListenerIfUserListenerExists() throws Exception {
// add listener for all request
InBandBytestreamListener allRequestsListener = mock(InBandBytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(allRequestsListener);
// add listener for request of user "other_initiator"
InBandBytestreamListener userRequestsListener = mock(InBandBytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(userRequestsListener, "other_"
+ initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert user request listener is not called
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(userRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// assert all requests listener is called
byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(allRequestsListener).incomingBytestreamRequest(byteStreamRequest.capture());
}
/**
* If a request with a specific session ID should be ignored no listeners should be notified.
*
* @throws Exception should not happen
*/
@Test
public void shouldIgnoreInBandBytestreamRequestOnce() throws Exception {
// add listener for all request
InBandBytestreamListener allRequestsListener = mock(InBandBytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(allRequestsListener);
// add listener for request of user "initiator"
InBandBytestreamListener userRequestsListener = mock(InBandBytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(userRequestsListener, initiatorJID);
// ignore session ID
byteStreamManager.ignoreBytestreamRequestOnce(sessionID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert user request listener is not called
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(userRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// assert all requests listener is not called
byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(allRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// run the listener with the initiation packet again
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert user request listener is called on the second request with the
// same session ID
verify(userRequestsListener).incomingBytestreamRequest(byteStreamRequest.capture());
// assert all requests listener is not called
byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(allRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
}
}

View file

@ -0,0 +1,85 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb.packet;
import static org.junit.Assert.assertEquals;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import java.util.Properties;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
import org.junit.Test;
import com.jamesmurty.utils.XMLBuilder;
/**
* Test for the Close class.
*
* @author Henning Staib
*/
public class CloseTest {
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArguments1() {
new Close(null);
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArguments2() {
new Close("");
}
@Test
public void shouldBeOfIQTypeSET() {
Close close = new Close("sessionID");
assertEquals(IQ.Type.SET, close.getType());
}
@Test
public void shouldSetAllFieldsCorrectly() {
Close close = new Close("sessionID");
assertEquals("sessionID", close.getSessionID());
}
private static Properties outputProperties = new Properties();
{
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void shouldReturnValidIQStanzaXML() throws Exception {
String control = XMLBuilder.create("iq")
.a("from", "romeo@montague.lit/orchard")
.a("to", "juliet@capulet.lit/balcony")
.a("id", "us71g45j")
.a("type", "set")
.e("close")
.a("xmlns", "http://jabber.org/protocol/ibb")
.a("sid", "i781hf64")
.asString(outputProperties);
Close close = new Close("i781hf64");
close.setFrom("romeo@montague.lit/orchard");
close.setTo("juliet@capulet.lit/balcony");
close.setPacketID("us71g45j");
assertXMLEqual(control, close.toXML().toString());
}
}

View file

@ -0,0 +1,99 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb.packet;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.util.Properties;
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
import org.junit.Test;
import com.jamesmurty.utils.XMLBuilder;
/**
* Test for the DataPacketExtension class.
*
* @author Henning Staib
*/
public class DataPacketExtensionTest {
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArgument1() {
new DataPacketExtension(null, 0, "data");
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArgument2() {
new DataPacketExtension("", 0, "data");
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArgument3() {
new DataPacketExtension("sessionID", -1, "data");
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArgument4() {
new DataPacketExtension("sessionID", 70000, "data");
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArgument5() {
new DataPacketExtension("sessionID", 0, null);
}
@Test
public void shouldSetAllFieldsCorrectly() {
DataPacketExtension data = new DataPacketExtension("sessionID", 0, "data");
assertEquals("sessionID", data.getSessionID());
assertEquals(0, data.getSeq());
assertEquals("data", data.getData());
}
@Test
public void shouldReturnNullIfDataIsInvalid() {
// pad character is not at end of data
DataPacketExtension data = new DataPacketExtension("sessionID", 0, "BBBB=CCC");
assertNull(data.getDecodedData());
// invalid Base64 character
data = new DataPacketExtension("sessionID", 0, new String(new byte[] { 123 }));
assertNull(data.getDecodedData());
}
private static Properties outputProperties = new Properties();
{
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void shouldReturnValidIQStanzaXML() throws Exception {
String control = XMLBuilder.create("data")
.a("xmlns", "http://jabber.org/protocol/ibb")
.a("seq", "0")
.a("sid", "i781hf64")
.t("DATA")
.asString(outputProperties);
DataPacketExtension data = new DataPacketExtension("i781hf64", 0, "DATA");
assertXMLEqual(control, data.toXML());
}
}

View file

@ -0,0 +1,90 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb.packet;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
import java.util.Properties;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
import org.junit.Test;
import com.jamesmurty.utils.XMLBuilder;
/**
* Test for the Data class.
*
* @author Henning Staib
*/
public class DataTest {
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArgument() {
new Data(null);
}
@Test
public void shouldBeOfIQTypeSET() {
DataPacketExtension dpe = mock(DataPacketExtension.class);
Data data = new Data(dpe);
assertEquals(IQ.Type.SET, data.getType());
}
private static Properties outputProperties = new Properties();
{
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void shouldReturnValidIQStanzaXML() throws Exception {
String encodedData = StringUtils.encodeBase64("Test");
String control = XMLBuilder.create("iq")
.a("from", "romeo@montague.lit/orchard")
.a("to", "juliet@capulet.lit/balcony")
.a("id", "kr91n475")
.a("type", "set")
.e("data")
.a("xmlns", "http://jabber.org/protocol/ibb")
.a("seq", "0")
.a("sid", "i781hf64")
.t(encodedData)
.asString(outputProperties);
DataPacketExtension dpe = mock(DataPacketExtension.class);
String dataTag = XMLBuilder.create("data")
.a("xmlns", "http://jabber.org/protocol/ibb")
.a("seq", "0")
.a("sid", "i781hf64")
.t(encodedData)
.asString(outputProperties);
when(dpe.toXML()).thenReturn(dataTag);
Data data = new Data(dpe);
data.setFrom("romeo@montague.lit/orchard");
data.setTo("juliet@capulet.lit/balcony");
data.setPacketID("kr91n475");
assertXMLEqual(control, data.toXML().toString());
}
}

View file

@ -0,0 +1,107 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb.packet;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.assertEquals;
import java.util.Properties;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.StanzaType;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.junit.Test;
import com.jamesmurty.utils.XMLBuilder;
/**
* Test for the Open class.
*
* @author Henning Staib
*/
public class OpenTest {
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArguments1() {
new Open(null, 1);
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArguments2() {
new Open("", 1);
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotInstantiateWithInvalidArguments3() {
new Open("sessionID", -1);
}
@Test
public void shouldSetIQStanzaAsDefault() {
Open open = new Open("sessionID", 4096);
assertEquals(StanzaType.IQ, open.getStanza());
}
@Test
public void shouldUseMessageStanzaIfGiven() {
Open open = new Open("sessionID", 4096, StanzaType.MESSAGE);
assertEquals(StanzaType.MESSAGE, open.getStanza());
}
@Test
public void shouldBeOfIQTypeSET() {
Open open = new Open("sessionID", 4096);
assertEquals(IQ.Type.SET, open.getType());
}
@Test
public void shouldSetAllFieldsCorrectly() {
Open open = new Open("sessionID", 4096, StanzaType.MESSAGE);
assertEquals("sessionID", open.getSessionID());
assertEquals(4096, open.getBlockSize());
assertEquals(StanzaType.MESSAGE, open.getStanza());
}
private static Properties outputProperties = new Properties();
{
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void shouldReturnValidIQStanzaXML() throws Exception {
String control = XMLBuilder.create("iq")
.a("from", "romeo@montague.lit/orchard")
.a("to", "juliet@capulet.lit/balcony")
.a("id", "jn3h8g65")
.a("type", "set")
.e("open")
.a("xmlns", "http://jabber.org/protocol/ibb")
.a("block-size", "4096")
.a("sid", "i781hf64")
.a("stanza", "iq")
.asString(outputProperties);
Open open = new Open("i781hf64", 4096, StanzaType.IQ);
open.setFrom("romeo@montague.lit/orchard");
open.setTo("juliet@capulet.lit/balcony");
open.setPacketID("jn3h8g65");
assertXMLEqual(control, open.toXML().toString());
}
}

View file

@ -0,0 +1,90 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.ibb.provider;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.StanzaType;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.jivesoftware.smackx.bytestreams.ibb.provider.OpenIQProvider;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import com.jamesmurty.utils.XMLBuilder;
/**
* Test for the OpenIQProvider class.
*
* @author Henning Staib
*/
public class OpenIQProviderTest {
private static Properties outputProperties = new Properties();
{
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void shouldCorrectlyParseIQStanzaAttribute() throws Exception {
String control = XMLBuilder.create("open")
.a("xmlns", "http://jabber.org/protocol/ibb")
.a("block-size", "4096")
.a("sid", "i781hf64")
.a("stanza", "iq")
.asString(outputProperties);
OpenIQProvider oip = new OpenIQProvider();
Open open = (Open) oip.parseIQ(getParser(control));
assertEquals(StanzaType.IQ, open.getStanza());
}
@Test
public void shouldCorrectlyParseMessageStanzaAttribute() throws Exception {
String control = XMLBuilder.create("open")
.a("xmlns", "http://jabber.org/protocol/ibb")
.a("block-size", "4096")
.a("sid", "i781hf64")
.a("stanza", "message")
.asString(outputProperties);
OpenIQProvider oip = new OpenIQProvider();
Open open = (Open) oip.parseIQ(getParser(control));
assertEquals(StanzaType.MESSAGE, open.getStanza());
}
private XmlPullParser getParser(String control) throws XmlPullParserException,
IOException {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setInput(new StringReader(control));
while (true) {
if (parser.next() == XmlPullParser.START_TAG
&& parser.getName().equals("open")) {
break;
}
}
return parser;
}
}

View file

@ -0,0 +1,311 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.socks5;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
import org.jivesoftware.smackx.bytestreams.socks5.InitiationListener;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamListener;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.powermock.reflect.Whitebox;
/**
* Test for the InitiationListener class.
*
* @author Henning Staib
*/
public class InitiationListenerTest {
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
String xmppServer = "xmpp-server";
String proxyJID = "proxy.xmpp-server";
String proxyAddress = "127.0.0.1";
String sessionID = "session_id";
XMPPConnection connection;
Socks5BytestreamManager byteStreamManager;
InitiationListener initiationListener;
Bytestream initBytestream;
/**
* Initialize fields used in the tests.
*/
@Before
public void setup() {
// mock connection
connection = mock(XMPPConnection.class);
// create service discovery manager for mocked connection
ServiceDiscoveryManager.getInstanceFor(connection);
// initialize Socks5ByteStreamManager to get the InitiationListener
byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
// get the InitiationListener from Socks5ByteStreamManager
initiationListener = Whitebox.getInternalState(byteStreamManager, InitiationListener.class);
// create a SOCKS5 Bytestream initiation packet
initBytestream = Socks5PacketUtils.createBytestreamInitiation(initiatorJID, targetJID,
sessionID);
initBytestream.addStreamHost(proxyJID, proxyAddress, 7777);
}
/**
* If no listeners are registered for incoming SOCKS5 Bytestream requests, all request should be
* rejected with an error.
*
* @throws Exception should not happen
*/
@Test
public void shouldRespondWithError() throws Exception {
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// capture reply to the SOCKS5 Bytestream initiation
ArgumentCaptor<IQ> argument = ArgumentCaptor.forClass(IQ.class);
verify(connection).sendPacket(argument.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, argument.getValue().getTo());
assertEquals(IQ.Type.ERROR, argument.getValue().getType());
assertEquals(XMPPError.Condition.no_acceptable.toString(),
argument.getValue().getError().getCondition());
}
/**
* If a listener for all requests is registered it should be notified on incoming requests.
*
* @throws Exception should not happen
*/
@Test
public void shouldInvokeListenerForAllRequests() throws Exception {
// add listener
Socks5BytestreamListener listener = mock(Socks5BytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(listener);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert listener is called once
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(listener).incomingBytestreamRequest(byteStreamRequest.capture());
// assert that listener is called for the correct request
assertEquals(initiatorJID, byteStreamRequest.getValue().getFrom());
}
/**
* If a listener for a specific user in registered it should be notified on incoming requests
* for that user.
*
* @throws Exception should not happen
*/
@Test
public void shouldInvokeListenerForUser() throws Exception {
// add listener
Socks5BytestreamListener listener = mock(Socks5BytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(listener, initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert listener is called once
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(listener).incomingBytestreamRequest(byteStreamRequest.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, byteStreamRequest.getValue().getFrom());
}
/**
* If listener for a specific user is registered it should not be notified on incoming requests
* from other users.
*
* @throws Exception should not happen
*/
@Test
public void shouldNotInvokeListenerForUser() throws Exception {
// add listener for request of user "other_initiator"
Socks5BytestreamListener listener = mock(Socks5BytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(listener, "other_" + initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert listener is not called
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(listener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// capture reply to the SOCKS5 Bytestream initiation
ArgumentCaptor<IQ> argument = ArgumentCaptor.forClass(IQ.class);
verify(connection).sendPacket(argument.capture());
// assert that reply is the correct error packet
assertEquals(initiatorJID, argument.getValue().getTo());
assertEquals(IQ.Type.ERROR, argument.getValue().getType());
assertEquals(XMPPError.Condition.no_acceptable.toString(),
argument.getValue().getError().getCondition());
}
/**
* If a user specific listener and an all requests listener is registered only the user specific
* listener should be notified.
*
* @throws Exception should not happen
*/
@Test
public void shouldNotInvokeAllRequestsListenerIfUserListenerExists() throws Exception {
// add listener for all request
Socks5BytestreamListener allRequestsListener = mock(Socks5BytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(allRequestsListener);
// add listener for request of user "initiator"
Socks5BytestreamListener userRequestsListener = mock(Socks5BytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(userRequestsListener, initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert user request listener is called once
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(userRequestsListener).incomingBytestreamRequest(byteStreamRequest.capture());
// assert all requests listener is not called
byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(allRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
}
/**
* If a user specific listener and an all requests listener is registered only the all requests
* listener should be notified on an incoming request for another user.
*
* @throws Exception should not happen
*/
@Test
public void shouldInvokeAllRequestsListenerIfUserListenerExists() throws Exception {
// add listener for all request
Socks5BytestreamListener allRequestsListener = mock(Socks5BytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(allRequestsListener);
// add listener for request of user "other_initiator"
Socks5BytestreamListener userRequestsListener = mock(Socks5BytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(userRequestsListener, "other_"
+ initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert user request listener is not called
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(userRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// assert all requests listener is called
byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(allRequestsListener).incomingBytestreamRequest(byteStreamRequest.capture());
}
/**
* If a request with a specific session ID should be ignored no listeners should be notified.
*
* @throws Exception should not happen
*/
@Test
public void shouldIgnoreSocks5BytestreamRequestOnce() throws Exception {
// add listener for all request
Socks5BytestreamListener allRequestsListener = mock(Socks5BytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(allRequestsListener);
// add listener for request of user "initiator"
Socks5BytestreamListener userRequestsListener = mock(Socks5BytestreamListener.class);
byteStreamManager.addIncomingBytestreamListener(userRequestsListener, initiatorJID);
// ignore session ID
byteStreamManager.ignoreBytestreamRequestOnce(sessionID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert user request listener is not called
ArgumentCaptor<BytestreamRequest> byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(userRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// assert all requests listener is not called
byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(allRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// run the listener with the initiation packet again
initiationListener.processPacket(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
// assert user request listener is called on the second request with the same session ID
verify(userRequestsListener).incomingBytestreamRequest(byteStreamRequest.capture());
// assert all requests listener is not called
byteStreamRequest = ArgumentCaptor.forClass(BytestreamRequest.class);
verify(allRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
}
}

View file

@ -0,0 +1,435 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.socks5;
import static org.junit.Assert.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils;
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
import org.jivesoftware.util.ConnectionUtils;
import org.jivesoftware.util.Protocol;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Tests for the Socks5BytestreamRequest class.
*
* @author Henning Staib
*/
public class Socks5ByteStreamRequestTest {
// settings
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
String xmppServer = "xmpp-server";
String proxyJID = "proxy.xmpp-server";
String proxyAddress = "127.0.0.1";
String sessionID = "session_id";
Protocol protocol;
XMPPConnection connection;
/**
* Initialize fields used in the tests.
* @throws XMPPException
* @throws SmackException
*/
@Before
public void setup() throws XMPPException, SmackException {
// build protocol verifier
protocol = new Protocol();
// create mocked XMPP connection
connection = ConnectionUtils.createMockedConnection(protocol, targetJID, xmppServer);
}
/**
* Accepting a SOCKS5 Bytestream request should fail if the request doesn't contain any Socks5
* proxies.
*
* @throws Exception should not happen
*/
@Test
public void shouldFailIfRequestHasNoStreamHosts() throws Exception {
try {
// build SOCKS5 Bytestream initialization request with no SOCKS5 proxies
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
initiatorJID, targetJID, sessionID);
// get SOCKS5 Bytestream manager for connection
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(
byteStreamManager, bytestreamInitialization);
// accept the stream (this is the call that is tested here)
byteStreamRequest.accept();
fail("exception should be thrown");
}
catch (XMPPErrorException e) {
assertTrue(e.getMessage().contains("Could not establish socket with any provided host"));
}
// verify targets response
assertEquals(1, protocol.getRequests().size());
Packet targetResponse = protocol.getRequests().remove(0);
assertTrue(IQ.class.isInstance(targetResponse));
assertEquals(initiatorJID, targetResponse.getTo());
assertEquals(IQ.Type.ERROR, ((IQ) targetResponse).getType());
assertEquals(XMPPError.Condition.item_not_found.toString(),
((IQ) targetResponse).getError().getCondition());
}
/**
* Accepting a SOCKS5 Bytestream request should fail if target is not able to connect to any of
* the provided SOCKS5 proxies.
*
* @throws Exception
*/
@Test
public void shouldFailIfRequestHasInvalidStreamHosts() throws Exception {
try {
// build SOCKS5 Bytestream initialization request
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
initiatorJID, targetJID, sessionID);
// add proxy that is not running
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7778);
// get SOCKS5 Bytestream manager for connection
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(
byteStreamManager, bytestreamInitialization);
// accept the stream (this is the call that is tested here)
byteStreamRequest.accept();
fail("exception should be thrown");
}
catch (XMPPErrorException e) {
assertTrue(e.getMessage().contains("Could not establish socket with any provided host"));
}
// verify targets response
assertEquals(1, protocol.getRequests().size());
Packet targetResponse = protocol.getRequests().remove(0);
assertTrue(IQ.class.isInstance(targetResponse));
assertEquals(initiatorJID, targetResponse.getTo());
assertEquals(IQ.Type.ERROR, ((IQ) targetResponse).getType());
assertEquals(XMPPError.Condition.item_not_found.toString(),
((IQ) targetResponse).getError().getCondition());
}
/**
* Target should not try to connect to SOCKS5 proxies that already failed twice.
*
* @throws Exception should not happen
*/
@Test
public void shouldBlacklistInvalidProxyAfter2Failures() throws Exception {
// build SOCKS5 Bytestream initialization request
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
initiatorJID, targetJID, sessionID);
bytestreamInitialization.addStreamHost("invalid." + proxyJID, "127.0.0.2", 7778);
// get SOCKS5 Bytestream manager for connection
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
// try to connect several times
for (int i = 0; i < 2; i++) {
try {
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(
byteStreamManager, bytestreamInitialization);
// set timeouts
byteStreamRequest.setTotalConnectTimeout(600);
byteStreamRequest.setMinimumConnectTimeout(300);
// accept the stream (this is the call that is tested here)
byteStreamRequest.accept();
fail("exception should be thrown");
}
catch (XMPPErrorException e) {
assertTrue(e.getMessage().contains(
"Could not establish socket with any provided host"));
}
// verify targets response
assertEquals(1, protocol.getRequests().size());
Packet targetResponse = protocol.getRequests().remove(0);
assertTrue(IQ.class.isInstance(targetResponse));
assertEquals(initiatorJID, targetResponse.getTo());
assertEquals(IQ.Type.ERROR, ((IQ) targetResponse).getType());
assertEquals(XMPPError.Condition.item_not_found.toString(),
((IQ) targetResponse).getError().getCondition());
}
// create test data for stream
byte[] data = new byte[] { 1, 2, 3 };
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7779);
assertTrue(socks5Proxy.isRunning());
// add a valid SOCKS5 proxy
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7779);
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager,
bytestreamInitialization);
// set timeouts
byteStreamRequest.setTotalConnectTimeout(600);
byteStreamRequest.setMinimumConnectTimeout(300);
// accept the stream (this is the call that is tested here)
InputStream inputStream = byteStreamRequest.accept().getInputStream();
// create digest to get the socket opened by target
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
// test stream by sending some data
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
outputStream.write(data);
// verify that data is transferred correctly
byte[] result = new byte[3];
inputStream.read(result);
assertArrayEquals(data, result);
// verify targets response
assertEquals(1, protocol.getRequests().size());
Packet targetResponse = protocol.getRequests().remove(0);
assertEquals(Bytestream.class, targetResponse.getClass());
assertEquals(initiatorJID, targetResponse.getTo());
assertEquals(IQ.Type.RESULT, ((Bytestream) targetResponse).getType());
assertEquals(proxyJID, ((Bytestream) targetResponse).getUsedHost().getJID());
}
/**
* Target should not not blacklist any SOCKS5 proxies regardless of failing connections.
*
* @throws Exception should not happen
*/
@Test
public void shouldNotBlacklistInvalidProxy() throws Exception {
// disable blacklisting
Socks5BytestreamRequest.setConnectFailureThreshold(0);
// build SOCKS5 Bytestream initialization request
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
initiatorJID, targetJID, sessionID);
bytestreamInitialization.addStreamHost("invalid." + proxyJID, "127.0.0.2", 7778);
// get SOCKS5 Bytestream manager for connection
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
// try to connect several times
for (int i = 0; i < 10; i++) {
try {
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(
byteStreamManager, bytestreamInitialization);
// set timeouts
byteStreamRequest.setTotalConnectTimeout(600);
byteStreamRequest.setMinimumConnectTimeout(300);
// accept the stream (this is the call that is tested here)
byteStreamRequest.accept();
fail("exception should be thrown");
}
catch (XMPPException e) {
assertTrue(e.getMessage().contains(
"Could not establish socket with any provided host"));
}
// verify targets response
assertEquals(1, protocol.getRequests().size());
Packet targetResponse = protocol.getRequests().remove(0);
assertTrue(IQ.class.isInstance(targetResponse));
assertEquals(initiatorJID, targetResponse.getTo());
assertEquals(IQ.Type.ERROR, ((IQ) targetResponse).getType());
assertEquals(XMPPError.Condition.item_not_found.toString(),
((IQ) targetResponse).getError().getCondition());
}
// enable blacklisting
Socks5BytestreamRequest.setConnectFailureThreshold(2);
}
/**
* If the SOCKS5 Bytestream request contains multiple SOCKS5 proxies and the first one doesn't
* respond, the connection attempt to this proxy should not consume the whole timeout for
* connecting to the proxies.
*
* @throws Exception should not happen
*/
@Test
public void shouldNotTimeoutIfFirstSocks5ProxyDoesNotRespond() throws Exception {
// start a local SOCKS5 proxy
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7778);
// create a fake SOCKS5 proxy that doesn't respond to a request
ServerSocket serverSocket = new ServerSocket(7779);
// build SOCKS5 Bytestream initialization request
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
initiatorJID, targetJID, sessionID);
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7779);
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7778);
// create test data for stream
byte[] data = new byte[] { 1, 2, 3 };
// get SOCKS5 Bytestream manager for connection
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager,
bytestreamInitialization);
// set timeouts
byteStreamRequest.setTotalConnectTimeout(2000);
byteStreamRequest.setMinimumConnectTimeout(1000);
// accept the stream (this is the call that is tested here)
InputStream inputStream = byteStreamRequest.accept().getInputStream();
// assert that client tries to connect to dumb SOCKS5 proxy
Socket socket = serverSocket.accept();
assertNotNull(socket);
// create digest to get the socket opened by target
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
// test stream by sending some data
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
outputStream.write(data);
// verify that data is transferred correctly
byte[] result = new byte[3];
inputStream.read(result);
assertArrayEquals(data, result);
// verify targets response
assertEquals(1, protocol.getRequests().size());
Packet targetResponse = protocol.getRequests().remove(0);
assertEquals(Bytestream.class, targetResponse.getClass());
assertEquals(initiatorJID, targetResponse.getTo());
assertEquals(IQ.Type.RESULT, ((Bytestream) targetResponse).getType());
assertEquals(proxyJID, ((Bytestream) targetResponse).getUsedHost().getJID());
serverSocket.close();
}
/**
* Accepting the SOCKS5 Bytestream request should be successfully.
*
* @throws Exception should not happen
*/
@Test
public void shouldAcceptSocks5BytestreamRequestAndReceiveData() throws Exception {
// start a local SOCKS5 proxy
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7778);
// build SOCKS5 Bytestream initialization request
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
initiatorJID, targetJID, sessionID);
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7778);
// create test data for stream
byte[] data = new byte[] { 1, 2, 3 };
// get SOCKS5 Bytestream manager for connection
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager,
bytestreamInitialization);
// accept the stream (this is the call that is tested here)
InputStream inputStream = byteStreamRequest.accept().getInputStream();
// create digest to get the socket opened by target
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
// test stream by sending some data
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
outputStream.write(data);
// verify that data is transferred correctly
byte[] result = new byte[3];
inputStream.read(result);
assertArrayEquals(data, result);
// verify targets response
assertEquals(1, protocol.getRequests().size());
Packet targetResponse = protocol.getRequests().remove(0);
assertEquals(Bytestream.class, targetResponse.getClass());
assertEquals(initiatorJID, targetResponse.getTo());
assertEquals(IQ.Type.RESULT, ((Bytestream) targetResponse).getType());
assertEquals(proxyJID, ((Bytestream) targetResponse).getUsedHost().getJID());
}
/**
* Stop eventually started local SOCKS5 test proxy.
*/
@After
public void cleanUp() {
Socks5TestProxy.stopProxy();
Socks5Proxy.setLocalSocks5ProxyEnabled(true);
}
}

View file

@ -0,0 +1,316 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.socks5;
import static org.junit.Assert.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Client;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5ClientForInitiator;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils;
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
import org.jivesoftware.util.ConnectionUtils;
import org.jivesoftware.util.Protocol;
import org.jivesoftware.util.Verification;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Test for Socks5ClientForInitiator class.
*
* @author Henning Staib
*/
public class Socks5ClientForInitiatorTest {
// settings
String initiatorJID = "initiator@xmpp-server/Smack";
String targetJID = "target@xmpp-server/Smack";
String xmppServer = "xmpp-server";
String proxyJID = "proxy.xmpp-server";
String proxyAddress = "127.0.0.1";
int proxyPort = 7890;
String sessionID = "session_id";
// protocol verifier
Protocol protocol;
// mocked XMPP connection
XMPPConnection connection;
/**
* Initialize fields used in the tests.
* @throws XMPPException
* @throws SmackException
*/
@Before
public void setup() throws XMPPException, SmackException {
// build protocol verifier
protocol = new Protocol();
// create mocked XMPP connection
connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID, xmppServer);
}
/**
* If the target is not connected to the local SOCKS5 proxy an exception should be thrown.
*
* @throws Exception should not happen
*/
@Test
public void shouldFailIfTargetIsNotConnectedToLocalSocks5Proxy() throws Exception {
// start a local SOCKS5 proxy
Socks5Proxy.setLocalSocks5ProxyPort(proxyPort);
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
socks5Proxy.start();
// build stream host information for local SOCKS5 proxy
StreamHost streamHost = new StreamHost(connection.getUser(),
socks5Proxy.getLocalAddresses().get(0));
streamHost.setPort(socks5Proxy.getPort());
// create digest to get the socket opened by target
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
connection, sessionID, targetJID);
try {
socks5Client.getSocket(10000);
fail("exception should be thrown");
}
catch (SmackException e) {
assertTrue(e.getMessage().contains("target is not connected to SOCKS5 proxy"));
protocol.verifyAll(); // assert no XMPP messages were sent
}
socks5Proxy.stop();
}
/**
* Initiator and target should successfully connect to the local SOCKS5 proxy.
*
* @throws Exception should not happen
*/
@Test
public void shouldSuccessfullyConnectThroughLocalSocks5Proxy() throws Exception {
// start a local SOCKS5 proxy
Socks5Proxy.setLocalSocks5ProxyPort(proxyPort);
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
socks5Proxy.start();
// test data
final byte[] data = new byte[] { 1, 2, 3 };
// create digest
final String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
// allow connection of target with this digest
socks5Proxy.addTransfer(digest);
// build stream host information
final StreamHost streamHost = new StreamHost(connection.getUser(),
socks5Proxy.getLocalAddresses().get(0));
streamHost.setPort(socks5Proxy.getPort());
// target connects to local SOCKS5 proxy
Thread targetThread = new Thread() {
@Override
public void run() {
try {
Socks5Client targetClient = new Socks5Client(streamHost, digest);
Socket socket = targetClient.getSocket(10000);
socket.getOutputStream().write(data);
}
catch (Exception e) {
fail(e.getMessage());
}
}
};
targetThread.start();
Thread.sleep(200);
// initiator connects
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
connection, sessionID, targetJID);
Socket socket = socks5Client.getSocket(10000);
// verify test data
InputStream in = socket.getInputStream();
for (int i = 0; i < data.length; i++) {
assertEquals(data[i], in.read());
}
targetThread.join();
protocol.verifyAll(); // assert no XMPP messages were sent
socks5Proxy.removeTransfer(digest);
socks5Proxy.stop();
}
/**
* If the initiator can connect to a SOCKS5 proxy but activating the stream fails an exception
* should be thrown.
*
* @throws Exception should not happen
*/
@Test
public void shouldFailIfActivateSocks5ProxyFails() throws Exception {
// build error response as reply to the stream activation
XMPPError xmppError = new XMPPError(XMPPError.Condition.internal_server_error);
IQ error = new IQ() {
public String getChildElementXML() {
return null;
}
};
error.setType(Type.ERROR);
error.setFrom(proxyJID);
error.setTo(initiatorJID);
error.setError(xmppError);
protocol.addResponse(error, Verification.correspondingSenderReceiver,
Verification.requestTypeSET);
// start a local SOCKS5 proxy
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(proxyPort);
socks5Proxy.start();
StreamHost streamHost = new StreamHost(proxyJID, socks5Proxy.getAddress());
streamHost.setPort(socks5Proxy.getPort());
// create digest to get the socket opened by target
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
connection, sessionID, targetJID);
try {
socks5Client.getSocket(10000);
fail("exception should be thrown");
}
catch (XMPPErrorException e) {
assertTrue(XMPPError.Condition.internal_server_error.equals(e.getXMPPError().getCondition()));
protocol.verifyAll();
}
socks5Proxy.stop();
}
/**
* Target and initiator should successfully connect to a "remote" SOCKS5 proxy and the initiator
* activates the bytestream.
*
* @throws Exception should not happen
*/
@Test
public void shouldSuccessfullyEstablishConnectionAndActivateSocks5Proxy() throws Exception {
// build activation confirmation response
IQ activationResponse = new IQ() {
@Override
public String getChildElementXML() {
return null;
}
};
activationResponse.setFrom(proxyJID);
activationResponse.setTo(initiatorJID);
activationResponse.setType(IQ.Type.RESULT);
protocol.addResponse(activationResponse, Verification.correspondingSenderReceiver,
Verification.requestTypeSET, new Verification<Bytestream, IQ>() {
public void verify(Bytestream request, IQ response) {
// verify that the correct stream should be activated
assertNotNull(request.getToActivate());
assertEquals(targetJID, request.getToActivate().getTarget());
}
});
// start a local SOCKS5 proxy
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(proxyPort);
socks5Proxy.start();
StreamHost streamHost = new StreamHost(proxyJID, socks5Proxy.getAddress());
streamHost.setPort(socks5Proxy.getPort());
// create digest to get the socket opened by target
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
connection, sessionID, targetJID);
Socket initiatorSocket = socks5Client.getSocket(10000);
InputStream in = initiatorSocket.getInputStream();
Socket targetSocket = socks5Proxy.getSocket(digest);
OutputStream out = targetSocket.getOutputStream();
// verify test data
for (int i = 0; i < 10; i++) {
out.write(i);
assertEquals(i, in.read());
}
protocol.verifyAll();
initiatorSocket.close();
targetSocket.close();
socks5Proxy.stop();
}
/**
* Reset default port for local SOCKS5 proxy.
*/
@After
public void cleanup() {
Socks5Proxy.setLocalSocks5ProxyPort(7777);
}
}

View file

@ -0,0 +1,335 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.socks5;
import static org.junit.Assert.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Client;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils;
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Test for Socks5Client class.
*
* @author Henning Staib
*/
public class Socks5ClientTest {
// settings
private String serverAddress = "127.0.0.1";
private int serverPort = 7890;
private String proxyJID = "proxy.xmpp-server";
private String digest = "digest";
private ServerSocket serverSocket;
/**
* Initialize fields used in the tests.
*
* @throws Exception should not happen
*/
@Before
public void setup() throws Exception {
// create SOCKS5 proxy server socket
serverSocket = new ServerSocket(serverPort);
}
/**
* A SOCKS5 client MUST close connection if server doesn't accept any of the given
* authentication methods. (See RFC1928 Section 3)
*
* @throws Exception should not happen
*/
@Test
public void shouldCloseSocketIfServerDoesNotAcceptAuthenticationMethod() throws Exception {
// start thread to connect to SOCKS5 proxy
Thread serverThread = new Thread() {
@Override
public void run() {
StreamHost streamHost = new StreamHost(proxyJID, serverAddress);
streamHost.setPort(serverPort);
Socks5Client socks5Client = new Socks5Client(streamHost, digest);
try {
socks5Client.getSocket(10000);
fail("exception should be thrown");
}
catch (SmackException e) {
assertTrue(e.getMessage().contains(
"SOCKS5 negotiation failed"));
}
catch (Exception e) {
fail(e.getMessage());
}
}
};
serverThread.start();
// accept connection form client
Socket socket = serverSocket.accept();
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
// validate authentication request
assertEquals((byte) 0x05, (byte) in.read()); // version
assertEquals((byte) 0x01, (byte) in.read()); // number of supported auth methods
assertEquals((byte) 0x00, (byte) in.read()); // no-authentication method
// respond that no authentication method is accepted
out.write(new byte[] { (byte) 0x05, (byte) 0xFF });
out.flush();
// wait for client to shutdown
serverThread.join();
// assert socket is closed
assertEquals(-1, in.read());
}
/**
* The SOCKS5 client should close connection if server replies in an unsupported way.
*
* @throws Exception should not happen
*/
@Test
public void shouldCloseSocketIfServerRepliesInUnsupportedWay() throws Exception {
// start thread to connect to SOCKS5 proxy
Thread serverThread = new Thread() {
@Override
public void run() {
StreamHost streamHost = new StreamHost(proxyJID, serverAddress);
streamHost.setPort(serverPort);
Socks5Client socks5Client = new Socks5Client(streamHost, digest);
try {
socks5Client.getSocket(10000);
fail("exception should be thrown");
}
catch (SmackException e) {
assertTrue(e.getMessage().contains(
"Unsupported SOCKS5 address type"));
}
catch (Exception e) {
fail(e.getMessage());
}
}
};
serverThread.start();
// accept connection from client
Socket socket = serverSocket.accept();
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
// validate authentication request
assertEquals((byte) 0x05, (byte) in.read()); // version
assertEquals((byte) 0x01, (byte) in.read()); // number of supported auth methods
assertEquals((byte) 0x00, (byte) in.read()); // no-authentication method
// respond that no no-authentication method is used
out.write(new byte[] { (byte) 0x05, (byte) 0x00 });
out.flush();
Socks5Utils.receiveSocks5Message(in);
// reply with unsupported address type
out.write(new byte[] { (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00 });
out.flush();
// wait for client to shutdown
serverThread.join();
// assert socket is closed
assertEquals(-1, in.read());
}
/**
* The SOCKS5 client should close connection if server replies with an error.
*
* @throws Exception should not happen
*/
@Test
public void shouldCloseSocketIfServerRepliesWithError() throws Exception {
// start thread to connect to SOCKS5 proxy
Thread serverThread = new Thread() {
@Override
public void run() {
StreamHost streamHost = new StreamHost(proxyJID, serverAddress);
streamHost.setPort(serverPort);
Socks5Client socks5Client = new Socks5Client(streamHost, digest);
try {
socks5Client.getSocket(10000);
fail("exception should be thrown");
}
catch (SmackException e) {
assertTrue(e.getMessage().contains(
"SOCKS5 negotiation failed"));
}
catch (Exception e) {
fail(e.getMessage());
}
}
};
serverThread.start();
Socket socket = serverSocket.accept();
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
// validate authentication request
assertEquals((byte) 0x05, (byte) in.read()); // version
assertEquals((byte) 0x01, (byte) in.read()); // number of supported auth methods
assertEquals((byte) 0x00, (byte) in.read()); // no-authentication method
// respond that no no-authentication method is used
out.write(new byte[] { (byte) 0x05, (byte) 0x00 });
out.flush();
Socks5Utils.receiveSocks5Message(in);
// reply with full SOCKS5 message with an error code (01 = general SOCKS server
// failure)
out.write(new byte[] { (byte) 0x05, (byte) 0x01, (byte) 0x00, (byte) 0x03 });
byte[] address = digest.getBytes();
out.write(address.length);
out.write(address);
out.write(new byte[] { (byte) 0x00, (byte) 0x00 });
out.flush();
// wait for client to shutdown
serverThread.join();
// assert socket is closed
assertEquals(-1, in.read());
}
/**
* The SOCKS5 client should successfully connect to the SOCKS5 server
*
* @throws Exception should not happen
*/
@Test
public void shouldSuccessfullyConnectToSocks5Server() throws Exception {
// start thread to connect to SOCKS5 proxy
Thread serverThread = new Thread() {
@Override
public void run() {
StreamHost streamHost = new StreamHost(proxyJID, serverAddress);
streamHost.setPort(serverPort);
Socks5Client socks5Client = new Socks5Client(streamHost, digest);
try {
Socket socket = socks5Client.getSocket(10000);
assertNotNull(socket);
socket.getOutputStream().write(123);
socket.close();
}
catch (Exception e) {
fail(e.getMessage());
}
}
};
serverThread.start();
Socket socket = serverSocket.accept();
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
// validate authentication request
assertEquals((byte) 0x05, (byte) in.read()); // version
assertEquals((byte) 0x01, (byte) in.read()); // number of supported auth methods
assertEquals((byte) 0x00, (byte) in.read()); // no-authentication method
// respond that no no-authentication method is used
out.write(new byte[] { (byte) 0x05, (byte) 0x00 });
out.flush();
byte[] address = digest.getBytes();
assertEquals((byte) 0x05, (byte) in.read()); // version
assertEquals((byte) 0x01, (byte) in.read()); // connect request
assertEquals((byte) 0x00, (byte) in.read()); // reserved byte (always 0)
assertEquals((byte) 0x03, (byte) in.read()); // address type (domain)
assertEquals(address.length, (byte) in.read()); // address length
for (int i = 0; i < address.length; i++) {
assertEquals(address[i], (byte) in.read()); // address
}
assertEquals((byte) 0x00, (byte) in.read()); // port
assertEquals((byte) 0x00, (byte) in.read());
// reply with success SOCKS5 message
out.write(new byte[] { (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x03 });
out.write(address.length);
out.write(address);
out.write(new byte[] { (byte) 0x00, (byte) 0x00 });
out.flush();
// wait for client to shutdown
serverThread.join();
// verify data sent from client
assertEquals(123, in.read());
// assert socket is closed
assertEquals(-1, in.read());
}
/**
* Close fake SOCKS5 proxy.
*
* @throws Exception should not happen
*/
@After
public void cleanup() throws Exception {
serverSocket.close();
}
}

View file

@ -0,0 +1,122 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.socks5;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
/**
* A collection of utility methods to create XMPP packets.
*
* @author Henning Staib
*/
public class Socks5PacketUtils {
/**
* Returns a SOCKS5 Bytestream initialization request packet. The Request doesn't contain any
* SOCKS5 proxies.
*
* @param from the initiator
* @param to the target
* @param sessionID the session ID
* @return SOCKS5 Bytestream initialization request packet
*/
public static Bytestream createBytestreamInitiation(String from, String to, String sessionID) {
Bytestream bytestream = new Bytestream();
bytestream.getPacketID();
bytestream.setFrom(from);
bytestream.setTo(to);
bytestream.setSessionID(sessionID);
bytestream.setType(IQ.Type.SET);
return bytestream;
}
/**
* Returns a response to a SOCKS5 Bytestream initialization request. The packet doesn't contain
* the uses-host information.
*
* @param from the target
* @param to the initiator
* @return response to a SOCKS5 Bytestream initialization request
*/
public static Bytestream createBytestreamResponse(String from, String to) {
Bytestream streamHostInfo = new Bytestream();
streamHostInfo.getPacketID();
streamHostInfo.setFrom(from);
streamHostInfo.setTo(to);
streamHostInfo.setType(IQ.Type.RESULT);
return streamHostInfo;
}
/**
* Returns a response to an item discovery request. The packet doesn't contain any items.
*
* @param from the XMPP server
* @param to the XMPP client
* @return response to an item discovery request
*/
public static DiscoverItems createDiscoverItems(String from, String to) {
DiscoverItems discoverItems = new DiscoverItems();
discoverItems.getPacketID();
discoverItems.setFrom(from);
discoverItems.setTo(to);
discoverItems.setType(IQ.Type.RESULT);
return discoverItems;
}
/**
* Returns a response to an info discovery request. The packet doesn't contain any infos.
*
* @param from the target
* @param to the initiator
* @return response to an info discovery request
*/
public static DiscoverInfo createDiscoverInfo(String from, String to) {
DiscoverInfo discoverInfo = new DiscoverInfo();
discoverInfo.getPacketID();
discoverInfo.setFrom(from);
discoverInfo.setTo(to);
discoverInfo.setType(IQ.Type.RESULT);
return discoverInfo;
}
/**
* Returns a response IQ for a activation request to the proxy.
*
* @param from JID of the proxy
* @param to JID of the client who wants to activate the SOCKS5 Bytestream
* @return response IQ for a activation request to the proxy
*/
public static IQ createActivationConfirmation(String from, String to) {
IQ response = new IQ() {
@Override
public String getChildElementXML() {
return null;
}
};
response.getPacketID();
response.setFrom(from);
response.setTo(to);
response.setType(IQ.Type.RESULT);
return response;
}
}

View file

@ -0,0 +1,377 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.socks5;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.Test;
/**
* Test for Socks5Proxy class.
*
* @author Henning Staib
*/
public class Socks5ProxyTest {
/**
* The SOCKS5 proxy should be a singleton used by all XMPP connections
*/
@Test
public void shouldBeASingleton() {
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
Socks5Proxy proxy1 = Socks5Proxy.getSocks5Proxy();
Socks5Proxy proxy2 = Socks5Proxy.getSocks5Proxy();
assertNotNull(proxy1);
assertNotNull(proxy2);
assertSame(proxy1, proxy2);
}
/**
* The SOCKS5 proxy should not be started if disabled by configuration.
*/
@Test
public void shouldNotBeRunningIfDisabled() {
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
assertFalse(proxy.isRunning());
}
/**
* The SOCKS5 proxy should use a free port above the one configured.
*
* @throws Exception should not happen
*/
@Test
public void shouldUseFreePortOnNegativeValues() throws Exception {
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
assertFalse(proxy.isRunning());
ServerSocket serverSocket = new ServerSocket(0);
Socks5Proxy.setLocalSocks5ProxyPort(-serverSocket.getLocalPort());
proxy.start();
assertTrue(proxy.isRunning());
serverSocket.close();
assertTrue(proxy.getPort() > serverSocket.getLocalPort());
}
/**
* When inserting new network addresses to the proxy the order should remain in the order they
* were inserted.
*/
@Test
public void shouldPreserveAddressOrderOnInsertions() {
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
List<String> addresses = new ArrayList<String>(proxy.getLocalAddresses());
addresses.add("1");
addresses.add("2");
addresses.add("3");
for (String address : addresses) {
proxy.addLocalAddress(address);
}
List<String> localAddresses = proxy.getLocalAddresses();
for (int i = 0; i < addresses.size(); i++) {
assertEquals(addresses.get(i), localAddresses.get(i));
}
}
/**
* When replacing network addresses of the proxy the order should remain in the order if the
* given list.
*/
@Test
public void shouldPreserveAddressOrderOnReplace() {
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
List<String> addresses = new ArrayList<String>(proxy.getLocalAddresses());
addresses.add("1");
addresses.add("2");
addresses.add("3");
proxy.replaceLocalAddresses(addresses);
List<String> localAddresses = proxy.getLocalAddresses();
for (int i = 0; i < addresses.size(); i++) {
assertEquals(addresses.get(i), localAddresses.get(i));
}
}
/**
* Inserting the same address multiple times should not cause the proxy to return this address
* multiple times.
*/
@Test
public void shouldNotReturnMultipleSameAddress() {
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
proxy.addLocalAddress("same");
proxy.addLocalAddress("same");
proxy.addLocalAddress("same");
assertEquals(2, proxy.getLocalAddresses().size());
}
/**
* There should be only one thread executing the SOCKS5 proxy process.
*/
@Test
public void shouldOnlyStartOneServerThread() {
int threadCount = Thread.activeCount();
Socks5Proxy.setLocalSocks5ProxyPort(7890);
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
proxy.start();
assertTrue(proxy.isRunning());
assertEquals(threadCount + 1, Thread.activeCount());
proxy.start();
assertTrue(proxy.isRunning());
assertEquals(threadCount + 1, Thread.activeCount());
proxy.stop();
assertFalse(proxy.isRunning());
assertEquals(threadCount, Thread.activeCount());
proxy.start();
assertTrue(proxy.isRunning());
assertEquals(threadCount + 1, Thread.activeCount());
proxy.stop();
}
/**
* If the SOCKS5 proxy accepts a connection that is not a SOCKS5 connection it should close the
* corresponding socket.
*
* @throws Exception should not happen
*/
@Test
public void shouldCloseSocketIfNoSocks5Request() throws Exception {
Socks5Proxy.setLocalSocks5ProxyPort(7890);
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
proxy.start();
@SuppressWarnings("resource")
Socket socket = new Socket(proxy.getLocalAddresses().get(0), proxy.getPort());
OutputStream out = socket.getOutputStream();
out.write(new byte[] { 1, 2, 3 });
int res;
try {
res = socket.getInputStream().read();
} catch (SocketException e) {
res = -1;
}
assertEquals(-1, res);
proxy.stop();
}
/**
* The SOCKS5 proxy should reply with an error message if no supported authentication methods
* are given in the SOCKS5 request.
*
* @throws Exception should not happen
*/
@Test
public void shouldRespondWithErrorIfNoSupportedAuthenticationMethod() throws Exception {
Socks5Proxy.setLocalSocks5ProxyPort(7890);
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
proxy.start();
@SuppressWarnings("resource")
Socket socket = new Socket(proxy.getLocalAddresses().get(0), proxy.getPort());
OutputStream out = socket.getOutputStream();
// request username/password-authentication
out.write(new byte[] { (byte) 0x05, (byte) 0x01, (byte) 0x02 });
InputStream in = socket.getInputStream();
assertEquals((byte) 0x05, (byte) in.read());
assertEquals((byte) 0xFF, (byte) in.read());
assertEquals(-1, in.read());
proxy.stop();
}
/**
* The SOCKS5 proxy should respond with an error message if the client is not allowed to connect
* with the proxy.
*
* @throws Exception should not happen
*/
@Test
public void shouldRespondWithErrorIfConnectionIsNotAllowed() throws Exception {
Socks5Proxy.setLocalSocks5ProxyPort(7890);
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
proxy.start();
@SuppressWarnings("resource")
Socket socket = new Socket(proxy.getLocalAddresses().get(0), proxy.getPort());
OutputStream out = socket.getOutputStream();
out.write(new byte[] { (byte) 0x05, (byte) 0x01, (byte) 0x00 });
InputStream in = socket.getInputStream();
assertEquals((byte) 0x05, (byte) in.read());
assertEquals((byte) 0x00, (byte) in.read());
// send valid SOCKS5 message
out.write(new byte[] { (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x01,
(byte) 0xAA, (byte) 0x00, (byte) 0x00 });
// verify error message
assertEquals((byte) 0x05, (byte) in.read());
assertFalse((byte) 0x00 == (byte) in.read()); // something other than 0 == success
assertEquals((byte) 0x00, (byte) in.read());
assertEquals((byte) 0x03, (byte) in.read());
assertEquals((byte) 0x01, (byte) in.read());
assertEquals((byte) 0xAA, (byte) in.read());
assertEquals((byte) 0x00, (byte) in.read());
assertEquals((byte) 0x00, (byte) in.read());
assertEquals(-1, in.read());
proxy.stop();
}
/**
* A Client should successfully establish a connection to the SOCKS5 proxy.
*
* @throws Exception should not happen
*/
@Test
public void shouldSuccessfullyEstablishConnection() throws Exception {
Socks5Proxy.setLocalSocks5ProxyPort(7890);
Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy();
proxy.start();
assertTrue(proxy.isRunning());
String digest = new String(new byte[] { (byte) 0xAA });
// add digest to allow connection
proxy.addTransfer(digest);
@SuppressWarnings("resource")
Socket socket = new Socket(proxy.getLocalAddresses().get(0), proxy.getPort());
OutputStream out = socket.getOutputStream();
out.write(new byte[] { (byte) 0x05, (byte) 0x01, (byte) 0x00 });
InputStream in = socket.getInputStream();
assertEquals((byte) 0x05, (byte) in.read());
assertEquals((byte) 0x00, (byte) in.read());
// send valid SOCKS5 message
out.write(new byte[] { (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x01,
(byte) 0xAA, (byte) 0x00, (byte) 0x00 });
// verify response
assertEquals((byte) 0x05, (byte) in.read());
assertEquals((byte) 0x00, (byte) in.read()); // success
assertEquals((byte) 0x00, (byte) in.read());
assertEquals((byte) 0x03, (byte) in.read());
assertEquals((byte) 0x01, (byte) in.read());
assertEquals((byte) 0xAA, (byte) in.read());
assertEquals((byte) 0x00, (byte) in.read());
assertEquals((byte) 0x00, (byte) in.read());
Thread.sleep(200);
Socket remoteSocket = proxy.getSocket(digest);
// remove digest
proxy.removeTransfer(digest);
// test stream
OutputStream remoteOut = remoteSocket.getOutputStream();
byte[] data = new byte[] { 1, 2, 3, 4, 5 };
remoteOut.write(data);
remoteOut.flush();
for (int i = 0; i < data.length; i++) {
assertEquals(data[i], in.read());
}
remoteSocket.close();
assertEquals(-1, in.read());
proxy.stop();
}
/**
* Reset SOCKS5 proxy settings.
*/
@After
public void cleanup() {
Socks5Proxy.setLocalSocks5ProxyEnabled(true);
Socks5Proxy.setLocalSocks5ProxyPort(7777);
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
try {
String address = InetAddress.getLocalHost().getHostAddress();
List<String> addresses = new ArrayList<String>();
addresses.add(address);
socks5Proxy.replaceLocalAddresses(addresses);
}
catch (UnknownHostException e) {
// ignore
}
socks5Proxy.stop();
}
}

View file

@ -0,0 +1,289 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.bytestreams.socks5;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils;
/**
* Simple SOCKS5 proxy for testing purposes. It is almost the same as the Socks5Proxy class but the
* port can be configured more easy and it all connections are allowed.
*
* @author Henning Staib
*/
public class Socks5TestProxy {
/* SOCKS5 proxy singleton */
private static Socks5TestProxy socks5Server;
/* reusable implementation of a SOCKS5 proxy server process */
private Socks5ServerProcess serverProcess;
/* thread running the SOCKS5 server process */
private Thread serverThread;
/* server socket to accept SOCKS5 connections */
private ServerSocket serverSocket;
/* assigns a connection to a digest */
private final Map<String, Socket> connectionMap = new ConcurrentHashMap<String, Socket>();
/* port of the test proxy */
private int port = 7777;
/**
* Private constructor.
*/
private Socks5TestProxy(int port) {
this.serverProcess = new Socks5ServerProcess();
this.port = port;
}
/**
* Returns the local SOCKS5 proxy server
*
* @param port of the test proxy
* @return the local SOCKS5 proxy server
*/
public static synchronized Socks5TestProxy getProxy(int port) {
if (socks5Server == null) {
socks5Server = new Socks5TestProxy(port);
socks5Server.start();
}
return socks5Server;
}
/**
* Stops the test proxy
*/
public static synchronized void stopProxy() {
if (socks5Server != null) {
socks5Server.stop();
socks5Server = null;
}
}
/**
* Starts the local SOCKS5 proxy server. If it is already running, this method does nothing.
*/
public synchronized void start() {
if (isRunning()) {
return;
}
try {
this.serverSocket = new ServerSocket(this.port);
this.serverThread = new Thread(this.serverProcess);
this.serverThread.start();
}
catch (IOException e) {
e.printStackTrace();
// do nothing
}
}
/**
* Stops the local SOCKS5 proxy server. If it is not running this method does nothing.
*/
public synchronized void stop() {
if (!isRunning()) {
return;
}
try {
this.serverSocket.close();
}
catch (IOException e) {
// do nothing
e.printStackTrace();
}
if (this.serverThread != null && this.serverThread.isAlive()) {
try {
this.serverThread.interrupt();
this.serverThread.join();
}
catch (InterruptedException e) {
// do nothing
e.printStackTrace();
}
}
this.serverThread = null;
this.serverSocket = null;
}
/**
* Returns the host address of the local SOCKS5 proxy server.
*
* @return the host address of the local SOCKS5 proxy server
*/
public String getAddress() {
try {
return InetAddress.getLocalHost().getHostAddress();
}
catch (UnknownHostException e) {
return null;
}
}
/**
* Returns the port of the local SOCKS5 proxy server. If it is not running -1 will be returned.
*
* @return the port of the local SOCKS5 proxy server or -1 if proxy is not running
*/
public int getPort() {
if (!isRunning()) {
return -1;
}
return this.serverSocket.getLocalPort();
}
/**
* Returns the socket for the given digest.
*
* @param digest identifying the connection
* @return socket or null if there is no socket for the given digest
*/
public Socket getSocket(String digest) {
return this.connectionMap.get(digest);
}
/**
* Returns true if the local SOCKS5 proxy server is running, otherwise false.
*
* @return true if the local SOCKS5 proxy server is running, otherwise false
*/
public boolean isRunning() {
return this.serverSocket != null;
}
/**
* Implementation of a simplified SOCKS5 proxy server.
*
* @author Henning Staib
*/
class Socks5ServerProcess implements Runnable {
public void run() {
while (true) {
Socket socket = null;
try {
if (Socks5TestProxy.this.serverSocket.isClosed()
|| Thread.currentThread().isInterrupted()) {
return;
}
// accept connection
socket = Socks5TestProxy.this.serverSocket.accept();
// initialize connection
establishConnection(socket);
}
catch (SocketException e) {
/* do nothing */
}
catch (Exception e) {
try {
e.printStackTrace();
socket.close();
}
catch (IOException e1) {
/* Do Nothing */
}
}
}
}
/**
* Negotiates a SOCKS5 connection and stores it on success.
*
* @param socket connection to the client
* @throws SmackException if client requests a connection in an unsupported way
* @throws IOException if a network error occurred
*/
private void establishConnection(Socket socket) throws IOException, SmackException {
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(socket.getInputStream());
// first byte is version should be 5
int b = in.read();
if (b != 5) {
throw new SmackException("Only SOCKS5 supported");
}
// second byte number of authentication methods supported
b = in.read();
// read list of supported authentication methods
byte[] auth = new byte[b];
in.readFully(auth);
byte[] authMethodSelectionResponse = new byte[2];
authMethodSelectionResponse[0] = (byte) 0x05; // protocol version
// only authentication method 0, no authentication, supported
boolean noAuthMethodFound = false;
for (int i = 0; i < auth.length; i++) {
if (auth[i] == (byte) 0x00) {
noAuthMethodFound = true;
break;
}
}
if (!noAuthMethodFound) {
authMethodSelectionResponse[1] = (byte) 0xFF; // no acceptable methods
out.write(authMethodSelectionResponse);
out.flush();
throw new SmackException("Authentication method not supported");
}
authMethodSelectionResponse[1] = (byte) 0x00; // no-authentication method
out.write(authMethodSelectionResponse);
out.flush();
// receive connection request
byte[] connectionRequest = Socks5Utils.receiveSocks5Message(in);
// extract digest
String responseDigest = new String(connectionRequest, 5, connectionRequest[4]);
connectionRequest[1] = (byte) 0x00; // set return status to 0 (success)
out.write(connectionRequest);
out.flush();
// store connection
Socks5TestProxy.this.connectionMap.put(responseDigest, socket);
}
}
}

View file

@ -0,0 +1,243 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.caps;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.util.Base32Encoder;
import org.jivesoftware.smack.util.Base64FileUrlEncoder;
import org.jivesoftware.smack.util.StringEncoder;
import org.jivesoftware.smackx.caps.EntityCapsManager;
import org.jivesoftware.smackx.caps.cache.EntityCapsPersistentCache;
import org.jivesoftware.smackx.caps.cache.SimpleDirectoryPersistentCache;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.xdata.FormField;
import org.jivesoftware.smackx.xdata.packet.DataForm;
import org.junit.Test;
public class EntityCapsManagerTest {
/**
* <a href="http://xmpp.org/extensions/xep-0115.html#ver-gen-complex">XEP-
* 0115 Complex Generation Example</a>
*/
@Test
public void testComplexGenerationExample() {
DiscoverInfo di = createComplexSamplePacket();
String ver = EntityCapsManager.generateVerificationString(di, "sha-1");
assertEquals("q07IKJEyjvHSyhy//CH0CxmKi8w=", ver);
}
@Test
public void testSimpleDirectoryCacheBase64() throws IOException {
EntityCapsManager.persistentCache = null;
testSimpleDirectoryCache(Base64FileUrlEncoder.getInstance());
}
@Test
public void testSimpleDirectoryCacheBase32() throws IOException {
EntityCapsManager.persistentCache = null;
testSimpleDirectoryCache(Base32Encoder.getInstance());
}
@Test
public void testVerificationDuplicateFeatures() {
DiscoverInfo di = createMalformedDiscoverInfo();
assertTrue(di.containsDuplicateFeatures());
}
@Test
public void testVerificationDuplicateIdentities() {
DiscoverInfo di = createMalformedDiscoverInfo();
assertTrue(di.containsDuplicateIdentities());
}
@Test
public void testVerificationDuplicateDataForm() {
DiscoverInfo di = createMalformedDiscoverInfo();
assertTrue(EntityCapsManager.verifyPacketExtensions(di));
}
private void testSimpleDirectoryCache(StringEncoder stringEncoder) throws IOException {
EntityCapsPersistentCache cache = new SimpleDirectoryPersistentCache(createTempDirectory());
EntityCapsManager.setPersistentCache(cache);
DiscoverInfo di = createComplexSamplePacket();
String nodeVer = di.getNode() + "#" + EntityCapsManager.generateVerificationString(di, "sha-1");
// Save the data in EntityCapsManager
EntityCapsManager.addDiscoverInfoByNode(nodeVer, di);
// Lose all the data
EntityCapsManager.caps.clear();
// Restore the data from the persistent Cache
cache.replay();
DiscoverInfo restored_di = EntityCapsManager.getDiscoveryInfoByNodeVer(nodeVer);
assertNotNull(restored_di);
assertEquals(di.toXML().toString(), restored_di.toXML().toString());
}
private static DiscoverInfo createComplexSamplePacket() {
DiscoverInfo di = new DiscoverInfo();
di.setFrom("benvolio@capulet.lit/230193");
di.setPacketID("disco1");
di.setTo("juliet@capulet.lit/chamber");
di.setType(IQ.Type.RESULT);
Collection<DiscoverInfo.Identity> identities = new LinkedList<DiscoverInfo.Identity>();
DiscoverInfo.Identity i = new DiscoverInfo.Identity("client", "Psi 0.11", "pc");
i.setLanguage("en");
identities.add(i);
i = new DiscoverInfo.Identity("client", "Ψ 0.11", "pc");
i.setLanguage("el");
identities.add(i);
di.addIdentities(identities);
di.addFeature("http://jabber.org/protocol/disco#items");
di.addFeature(EntityCapsManager.NAMESPACE);
di.addFeature("http://jabber.org/protocol/muc");
di.addFeature("http://jabber.org/protocol/disco#info");
DataForm df = new DataForm("result");
FormField ff = new FormField("os");
ff.addValue("Mac");
df.addField(ff);
ff = new FormField("FORM_TYPE");
ff.setType("hidden");
ff.addValue("urn:xmpp:dataforms:softwareinfo");
df.addField(ff);
ff = new FormField("ip_version");
ff.addValue("ipv4");
ff.addValue("ipv6");
df.addField(ff);
ff = new FormField("os_version");
ff.addValue("10.5.1");
df.addField(ff);
ff = new FormField("software");
ff.addValue("Psi");
df.addField(ff);
ff = new FormField("software_version");
ff.addValue("0.11");
df.addField(ff);
di.addExtension(df);
return di;
}
private static DiscoverInfo createMalformedDiscoverInfo() {
DiscoverInfo di = new DiscoverInfo();
di.setFrom("benvolio@capulet.lit/230193");
di.setPacketID("disco1");
di.setTo(")juliet@capulet.lit/chamber");
di.setType(IQ.Type.RESULT);
Collection<DiscoverInfo.Identity> identities = new LinkedList<DiscoverInfo.Identity>();
DiscoverInfo.Identity i = new DiscoverInfo.Identity("client", "Psi 0.11", "pc");
i.setLanguage("en");
identities.add(i);
i = new DiscoverInfo.Identity("client", "Ψ 0.11", "pc");
i.setLanguage("el");
identities.add(i);
di.addIdentities(identities);
// Failure 1: Duplicate identities
i = new DiscoverInfo.Identity("client", "Ψ 0.11", "pc");
i.setLanguage("el");
identities.add(i);
di.addIdentities(identities);
di.addFeature("http://jabber.org/protocol/disco#items");
di.addFeature(EntityCapsManager.NAMESPACE);
di.addFeature("http://jabber.org/protocol/muc");
di.addFeature("http://jabber.org/protocol/disco#info");
// Failure 2: Duplicate features
di.addFeature("http://jabber.org/protocol/disco#info");
DataForm df = new DataForm("result");
FormField ff = new FormField("os");
ff.addValue("Mac");
df.addField(ff);
ff = new FormField("FORM_TYPE");
ff.setType("hidden");
ff.addValue("urn:xmpp:dataforms:softwareinfo");
df.addField(ff);
ff = new FormField("ip_version");
ff.addValue("ipv4");
ff.addValue("ipv6");
df.addField(ff);
ff = new FormField("os_version");
ff.addValue("10.5.1");
df.addField(ff);
ff = new FormField("software");
ff.addValue("Psi");
df.addField(ff);
ff = new FormField("software_version");
ff.addValue("0.11");
df.addField(ff);
di.addExtension(df);
// Failure 3: Another service discovery information form with the same
// FORM_TYPE
df = new DataForm("result");
ff = new FormField("FORM_TYPE");
ff.setType("hidden");
ff.addValue("urn:xmpp:dataforms:softwareinfo");
df.addField(ff);
ff = new FormField("software");
ff.addValue("smack");
df.addField(ff);
di.addExtension(df);
return di;
}
public static File createTempDirectory() throws IOException {
File tmp = File.createTempFile("entity", "caps");
tmp.delete();
tmp.mkdir();
return tmp;
}
}

View file

@ -0,0 +1,278 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.delay.provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.util.TimeZone;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.util.XmppDateTime;
import org.jivesoftware.smackx.InitExtensions;
import org.jivesoftware.smackx.delay.packet.DelayInfo;
import org.jivesoftware.smackx.delay.packet.DelayInformation;
import org.jivesoftware.smackx.delay.provider.DelayInfoProvider;
import org.jivesoftware.smackx.delay.provider.DelayInformationProvider;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import com.jamesmurty.utils.XMLBuilder;
public class DelayInformationTest extends InitExtensions {
private static Properties outputProperties = new Properties();
static {
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void delayInformationTest() throws Exception {
DelayInformationProvider p = new DelayInformationProvider();
DelayInformation delayInfo;
XmlPullParser parser;
String control;
GregorianCalendar calendar = new GregorianCalendar(2002, 9 - 1, 10, 23, 8, 25);
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = calendar.getTime();
control = XMLBuilder.create("x")
.a("xmlns", "jabber:x:delay")
.a("from", "capulet.com")
.a("stamp", "2002-09-10T23:08:25Z")
.t("Offline Storage")
.asString(outputProperties);
parser = TestUtils.getParser(control, "x");
delayInfo = (DelayInformation) p.parseExtension(parser);
assertEquals("capulet.com", delayInfo.getFrom());
assertEquals(date, delayInfo.getStamp());
assertEquals("Offline Storage", delayInfo.getReason());
assertEquals(XmlPullParser.END_TAG, parser.getEventType());
assertEquals("x", parser.getName());
control = XMLBuilder.create("x")
.a("xmlns", "jabber:x:delay")
.a("from", "capulet.com")
.a("stamp", "2002-09-10T23:08:25Z")
.asString(outputProperties);
parser = TestUtils.getParser(control, "x");
delayInfo = (DelayInformation) p.parseExtension(parser);
assertEquals("capulet.com", delayInfo.getFrom());
assertEquals(date, delayInfo.getStamp());
assertNull(delayInfo.getReason());
assertEquals(XmlPullParser.END_TAG, parser.getEventType());
assertEquals("x", parser.getName());
}
@Test
public void delayInfoTest() throws Exception {
DelayInformationProvider p = new DelayInfoProvider();
DelayInfo delayInfo;
XmlPullParser parser;
String control;
GregorianCalendar calendar = new GregorianCalendar(2002, 9 - 1, 10, 23, 8, 25);
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = calendar.getTime();
control = XMLBuilder.create("delay")
.a("xmlns", "urn:xmpp:delay")
.a("from", "capulet.com")
.a("stamp", "2002-09-10T23:08:25Z")
.t("Offline Storage")
.asString(outputProperties);
parser = TestUtils.getParser(control, "delay");
delayInfo = (DelayInfo) p.parseExtension(parser);
assertEquals("capulet.com", delayInfo.getFrom());
assertEquals(date, delayInfo.getStamp());
assertEquals("Offline Storage", delayInfo.getReason());
assertEquals(XmlPullParser.END_TAG, parser.getEventType());
assertEquals("delay", parser.getName());
control = XMLBuilder.create("delay")
.a("xmlns", "urn:xmpp:delay")
.a("from", "capulet.com")
.a("stamp", "2002-09-10T23:08:25Z")
.asString(outputProperties);
parser = TestUtils.getParser(control, "delay");
delayInfo = (DelayInfo) p.parseExtension(parser);
assertEquals("capulet.com", delayInfo.getFrom());
assertEquals(date, delayInfo.getStamp());
assertNull(delayInfo.getReason());
assertEquals(XmlPullParser.END_TAG, parser.getEventType());
assertEquals("delay", parser.getName());
}
@Test
public void dateFormatsTest() throws Exception {
DelayInformationProvider p = new DelayInfoProvider();
DelayInfo delayInfo;
String control;
GregorianCalendar calendar = new GregorianCalendar(2002, 9 - 1, 10, 23, 8, 25);
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
// XEP-0082 date format
control = XMLBuilder.create("delay")
.a("xmlns", "urn:xmpp:delay")
.a("from", "capulet.com")
.a("stamp", "2002-09-10T23:08:25.12Z")
.asString(outputProperties);
delayInfo = (DelayInfo) p.parseExtension(TestUtils.getParser(control, "delay"));
GregorianCalendar cal = (GregorianCalendar) calendar.clone();
cal.add(Calendar.MILLISECOND, 12);
assertEquals(cal.getTime(), delayInfo.getStamp());
// XEP-0082 date format without milliseconds
control = XMLBuilder.create("delay")
.a("xmlns", "urn:xmpp:delay")
.a("from", "capulet.com")
.a("stamp", "2002-09-10T23:08:25Z")
.asString(outputProperties);
delayInfo = (DelayInfo) p.parseExtension(TestUtils.getParser(control, "delay"));
assertEquals(calendar.getTime(), delayInfo.getStamp());
// XEP-0082 date format without milliseconds and leading 0 in month
control = XMLBuilder.create("delay")
.a("xmlns", "urn:xmpp:delay")
.a("from", "capulet.com")
.a("stamp", "2002-9-10T23:08:25Z")
.asString(outputProperties);
delayInfo = (DelayInfo) p.parseExtension(TestUtils.getParser(control, "delay"));
assertEquals(calendar.getTime(), delayInfo.getStamp());
// XEP-0091 date format
control = XMLBuilder.create("delay")
.a("xmlns", "urn:xmpp:delay")
.a("from", "capulet.com")
.a("stamp", "20020910T23:08:25")
.asString(outputProperties);
delayInfo = (DelayInfo) p.parseExtension(TestUtils.getParser(control, "delay"));
assertEquals(calendar.getTime(), delayInfo.getStamp());
// XEP-0091 date format without leading 0 in month
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMd'T'HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
GregorianCalendar dateInPast = new GregorianCalendar();
if (dateInPast.get(Calendar.MONTH) >= 10) {
dateInPast.set(Calendar.MONTH, dateInPast.get(Calendar.MONTH) - 3);
}
dateInPast.add(Calendar.DAY_OF_MONTH, -3);
dateInPast.set(Calendar.MILLISECOND, 0);
control = XMLBuilder.create("delay")
.a("xmlns", "urn:xmpp:delay")
.a("from", "capulet.com")
.a("stamp", dateFormat.format(dateInPast.getTime()))
.asString(outputProperties);
delayInfo = (DelayInfo) p.parseExtension(TestUtils.getParser(control, "delay"));
assertEquals(dateInPast.getTime(), delayInfo.getStamp());
// XEP-0091 date format from SMACK-243
control = XMLBuilder.create("delay")
.a("xmlns", "urn:xmpp:delay")
.a("from", "capulet.com")
.a("stamp", "200868T09:16:20")
.asString(outputProperties);
delayInfo = (DelayInfo) p.parseExtension(TestUtils.getParser(control, "delay"));
Date controlDate = XmppDateTime.parseDate("2008-06-08T09:16:20.0Z");
assertEquals(controlDate, delayInfo.getStamp());
// invalid date format
control = XMLBuilder.create("delay")
.a("xmlns", "urn:xmpp:delay")
.a("from", "capulet.com")
.a("stamp", "yesterday")
.asString(outputProperties);
delayInfo = (DelayInfo) p.parseExtension(TestUtils.getParser(control, "delay"));
assertNotNull(delayInfo.getStamp());
}
@Test
public void validatePresenceWithDelayedDelivery() throws Exception {
String stanza = "<presence from='mercutio@example.com' to='juliet@example.com'>"
+ "<delay xmlns='urn:xmpp:delay' stamp='2002-09-10T23:41:07Z'/></presence>";
Presence presence = PacketParserUtils.parsePresence(TestUtils.getPresenceParser(stanza));
DelayInformation delay = (DelayInformation) presence.getExtension("urn:xmpp:delay");
assertNotNull(delay);
Date date = XmppDateTime.parseDate("2002-09-10T23:41:07Z");
assertEquals(date, delay.getStamp());
}
@Test
public void validatePresenceWithLegacyDelayed() throws Exception {
String stanza = "<presence from='mercutio@example.com' to='juliet@example.com'>"
+ "<x xmlns='jabber:x:delay' stamp='20020910T23:41:07'/></presence>";
Presence presence = PacketParserUtils.parsePresence(TestUtils.getPresenceParser(stanza));
DelayInformation delay = (DelayInformation) presence.getExtension("jabber:x:delay");
assertNotNull(delay);
Date date = XmppDateTime.parseDate("20020910T23:41:07");
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("GMT"));
cal.setTime(date);
assertEquals(cal.getTime(), delay.getStamp());
}
@Test
public void parsePresenceWithInvalidLegacyDelayed() throws Exception {
String stanza = "<presence from='mercutio@example.com' to='juliet@example.com'>"
+ "<x xmlns='jabber:x:delay'/></presence>";
Presence presence = PacketParserUtils.parsePresence(TestUtils.getPresenceParser(stanza));
DelayInformation delay = (DelayInformation) presence.getExtension("urn:xmpp:delay");
assertNull((Object)delay);
}
}

View file

@ -0,0 +1,56 @@
/**
*
* Copyright 2011 Robin Collier
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.filetransfer;
import static org.junit.Assert.assertTrue;
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class FileTransferNegotiatorTest {
private DummyConnection connection;
@Before
public void setUp() throws Exception {
// Uncomment this to enable debug output
// XMPPConnection.DEBUG_ENABLED = true;
connection = new DummyConnection();
connection.connect();
connection.login("me", "secret");
ServiceDiscoveryManager.getInstanceFor(connection);
}
@After
public void tearDown() throws Exception {
if (connection != null)
connection.disconnect();
}
@Test
public void verifyForm() throws Exception {
FileTransferNegotiator fileNeg = FileTransferNegotiator.getInstanceFor(connection);
fileNeg.negotiateOutgoingTransfer("me", "streamid", "file", 1024, null, 10);
Packet packet = connection.getSentPacket();
String xml = packet.toXML().toString();
assertTrue(xml.indexOf("var='stream-method' type=\"list-single\"") != -1);
}
}

View file

@ -0,0 +1,75 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.forward;
import static org.junit.Assert.*;
import java.util.Properties;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smackx.forward.Forwarded;
import org.jivesoftware.smackx.forward.provider.ForwardedProvider;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import com.jamesmurty.utils.XMLBuilder;
public class ForwardedTest {
private static Properties outputProperties = new Properties();
static {
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void forwardedTest() throws Exception {
XmlPullParser parser;
String control;
Forwarded fwd;
control = XMLBuilder.create("forwarded")
.a("xmlns", "urn:xmpp:forwarded:0")
.e("message")
.a("from", "romeo@montague.com")
.asString(outputProperties);
parser = TestUtils.getParser(control, "forwarded");
fwd = (Forwarded) new ForwardedProvider().parseExtension(parser);
// no delay in packet
assertEquals(null, fwd.getDelayInfo());
// check message
assertEquals("romeo@montague.com", fwd.getForwardedPacket().getFrom());
// check end of tag
assertEquals(XmlPullParser.END_TAG, parser.getEventType());
assertEquals("forwarded", parser.getName());
}
@Test(expected=Exception.class)
public void forwardedEmptyTest() throws Exception {
XmlPullParser parser;
String control;
control = XMLBuilder.create("forwarded")
.a("xmlns", "urn:xmpp:forwarded:0")
.asString(outputProperties);
parser = TestUtils.getParser(control, "forwarded");
new ForwardedProvider().parseExtension(parser);
}
}

View file

@ -0,0 +1,56 @@
/**
*
* Copyright 2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.iqlast;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.InitExtensions;
import org.jivesoftware.smackx.iqlast.packet.LastActivity;
import org.junit.Test;
import com.jamesmurty.utils.XMLBuilder;
public class LastActivityTest extends InitExtensions {
@Test
public void checkProvider() throws Exception {
XMLBuilder xml = XMLBuilder.create("iq");
xml.a("from", "romeo@montague.net/orchard")
.a("id", "last2")
.a("to", "juliet@capulet.com/balcony")
.a("type", "get")
.e("query")
.namespace(LastActivity.NAMESPACE);
DummyConnection c = new DummyConnection();
IQ lastRequest = PacketParserUtils.parseIQ(TestUtils.getIQParser(xml.asString()), c);
assertTrue(lastRequest instanceof LastActivity);
c.processPacket(lastRequest);;
Packet reply = c.getSentPacket();
assertTrue(reply instanceof LastActivity);
LastActivity l = (LastActivity) reply;
assertEquals("last2", l.getPacketID());
assertEquals(IQ.Type.RESULT, l.getType());
}
}

View file

@ -0,0 +1,61 @@
/**
*
* Copyright 2014 Georg Lukas.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.iqversion;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.iqversion.packet.Version;
import org.junit.Test;
public class VersionTest {
@Test
public void checkProvider() throws Exception {
// @formatter:off
String control = "<iq from='capulet.lit' to='juliet@capulet.lit/balcony' id='s2c1' type='get'>"
+ "<query xmlns='jabber:iq:version'/>"
+ "</iq>";
// @formatter:on
DummyConnection con = new DummyConnection();
// Enable version replys for this connection
VersionManager.getInstanceFor(con).setVersion(new Version("Test", "0.23", "DummyOS"));
IQ versionRequest = PacketParserUtils.parseIQ(TestUtils.getIQParser(control), con);
assertTrue(versionRequest instanceof Version);
con.processPacket(versionRequest);
Packet replyPacket = con.getSentPacket();
assertTrue(replyPacket instanceof Version);
Version reply = (Version) replyPacket;
//getFrom check is pending for SMACK-547
//assertEquals("juliet@capulet.lit/balcony", reply.getFrom());
assertEquals("capulet.lit", reply.getTo());
assertEquals("s2c1", reply.getPacketID());
assertEquals(IQ.Type.RESULT, reply.getType());
assertEquals("Test", reply.getName());
assertEquals("0.23", reply.getVersion());
assertEquals("DummyOS", reply.getOs());
}
}

View file

@ -0,0 +1,66 @@
/**
*
* Copyright 2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jiveproperties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.InitExtensions;
import org.jivesoftware.smackx.jiveproperties.packet.JivePropertiesExtension;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class JivePropertiesExtensionTest extends InitExtensions {
@Before
public void setUp() {
JivePropertiesManager.setJavaObjectEnabled(true);
}
@After
public void tearDown() {
JivePropertiesManager.setJavaObjectEnabled(false);
}
@Test
public void checkProvider() throws Exception {
// @formatter:off
String properties = "<message from='romeo@example.net/orchard' to='juliet@example.com/balcony'>"
+ "<body>Neither, fair saint, if either thee dislike.</body>"
+ "<properties xmlns='http://www.jivesoftware.com/xmlns/xmpp/properties'>"
+ "<property>"
+ "<name>FooBar</name>"
+ "<value type='integer'>42</value>"
+ "</property>"
+ "</properties>"
+ "</message>";
// @formatter:on
Message message = PacketParserUtils.parseMessage(TestUtils.getMessageParser(properties));
JivePropertiesExtension jpe = (JivePropertiesExtension) message.getExtension(JivePropertiesExtension.NAMESPACE);
assertNotNull(jpe);
Integer integer = (Integer) jpe.getProperty("FooBar");
assertNotNull(integer);
int fourtytwo = integer;
assertEquals(42, fourtytwo);
}
}

View file

@ -0,0 +1,196 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.muc;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.jivesoftware.smack.packet.Packet;
import org.junit.Test;
public class ConnectionDetachedPacketCollectorTest
{
@Test
public void verifyRollover()
{
ConnectionDetachedPacketCollector collector = new ConnectionDetachedPacketCollector(5);
for (int i=0; i<6; i++)
{
Packet testPacket = new TestPacket(i);
collector.processPacket(testPacket);
}
// Assert that '0' has rolled off
assertEquals("1", collector.nextResult().getPacketID());
assertEquals("2", collector.nextResult().getPacketID());
assertEquals("3", collector.nextResult().getPacketID());
assertEquals("4", collector.nextResult().getPacketID());
assertEquals("5", collector.pollResult().getPacketID());
assertNull(collector.pollResult());
for (int i=10; i<15; i++)
{
Packet testPacket = new TestPacket(i);
collector.processPacket(testPacket);
}
assertEquals("10", collector.nextResult().getPacketID());
assertEquals("11", collector.nextResult().getPacketID());
assertEquals("12", collector.nextResult().getPacketID());
assertEquals("13", collector.nextResult().getPacketID());
assertEquals("14", collector.pollResult().getPacketID());
assertNull(collector.pollResult());
assertNull(collector.nextResult(1000));
}
/**
* Although this doesn't guarentee anything due to the nature of threading, it can
* potentially catch problems.
*/
@Test
public void verifyThreadSafety()
{
int insertCount = 500;
final ConnectionDetachedPacketCollector collector = new ConnectionDetachedPacketCollector(insertCount);
Thread consumer1 = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
while (true)
{
try
{
Thread.sleep(3);
}
catch (InterruptedException e)
{
}
@SuppressWarnings("unused")
Packet packet = collector.nextResult();
// System.out.println(Thread.currentThread().getName() + " packet: " + packet);
}
}
catch (RuntimeException re)
{
if (re.getCause() instanceof InterruptedException)
{
// System.out.println(Thread.currentThread().getName() + " has been interupted");
}
}
}
});
consumer1.setName("consumer 1");
Thread consumer2 = new Thread(new Runnable()
{
@Override
public void run()
{
Packet p = null;
do
{
try
{
Thread.sleep(3);
}
catch (InterruptedException e)
{
}
p = collector.nextResult(1);
// System.out.println(Thread.currentThread().getName() + " packet: " + p);
}
while (p != null);
}
});
consumer2.setName("consumer 2");
Thread consumer3 = new Thread(new Runnable()
{
@Override
public void run()
{
Packet p = null;
do
{
try
{
Thread.sleep(3);
}
catch (InterruptedException e)
{
}
p = collector.pollResult();
// System.out.println(Thread.currentThread().getName() + " packet: " + p);
}
while (p != null);
}
});
consumer3.setName("consumer 3");
consumer1.start();
consumer2.start();
consumer3.start();
for(int i=0; i<insertCount; i++)
{
collector.processPacket(new TestPacket(i));
}
try
{
Thread.sleep(5000);
consumer3.join();
consumer2.join();
consumer1.interrupt();
}
catch (InterruptedException e)
{
}
//We cannot guarantee that this is going to pass due to the possible issue of timing between consumer 1
// and main, but the probability is extremely remote.
assertNull(collector.pollResult());
}
class TestPacket extends Packet
{
public TestPacket(int i)
{
setPacketID(String.valueOf(i));
}
@Override
public String toString()
{
return toXML();
}
@Override
public String toXML()
{
return "<packetId>" + getPacketID() + "</packetId>";
}
}
}

View file

@ -0,0 +1,65 @@
/**
*
* Copyright 2011 Robin Collier
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.muc;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.muc.RoomInfo;
import org.jivesoftware.smackx.xdata.FormField;
import org.jivesoftware.smackx.xdata.packet.DataForm;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class RoomInfoTest {
@Test
public void validateRoomWithEmptyForm() {
DataForm dataForm = new DataForm("result");
DiscoverInfo discoInfo = new DiscoverInfo();
discoInfo.addExtension(dataForm);
RoomInfo roomInfo = new RoomInfo(discoInfo);
assertTrue(roomInfo.getDescription().isEmpty());
assertTrue(roomInfo.getSubject().isEmpty());
assertEquals(-1, roomInfo.getOccupantsCount());
}
@Test
public void validateRoomWithForm() {
DataForm dataForm = new DataForm("result");
FormField desc = new FormField("muc#roominfo_description");
desc.addValue("The place for all good witches!");
dataForm.addField(desc);
FormField subject = new FormField("muc#roominfo_subject");
subject.addValue("Spells");
dataForm.addField(subject);
FormField occupants = new FormField("muc#roominfo_occupants");
occupants.addValue("3");
dataForm.addField(occupants);
DiscoverInfo discoInfo = new DiscoverInfo();
discoInfo.addExtension(dataForm);
RoomInfo roomInfo = new RoomInfo(discoInfo);
assertEquals("The place for all good witches!", roomInfo.getDescription());
assertEquals("Spells", roomInfo.getSubject());
assertEquals(3, roomInfo.getOccupantsCount());
}
}

View file

@ -0,0 +1,173 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// TODO this should become PingManagerTest
//package org.jivesoftware.smackx.ping;
//
//import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
//import static org.junit.Assert.assertTrue;
//
//import java.util.Properties;
//import java.util.concurrent.CountDownLatch;
//import java.util.concurrent.TimeUnit;
//
//import org.jivesoftware.smack.XMPPConnection;
//import org.jivesoftware.smack.DummyConnection;
//import org.jivesoftware.smack.PacketInterceptor;
//import org.jivesoftware.smack.PacketListener;
//import org.jivesoftware.smack.SmackConfiguration;
//import org.jivesoftware.smack.ThreadedDummyConnection;
//import org.jivesoftware.smack.filter.IQTypeFilter;
//import org.jivesoftware.smack.filter.PacketTypeFilter;
//import org.jivesoftware.smack.packet.IQ;
//import org.jivesoftware.smack.packet.Packet;
//import org.jivesoftware.smack.pingx.packet.Ping;
//import org.jivesoftware.smackx.ping.PingFailedListener;
//import org.junit.After;
//import org.junit.Before;
//import org.junit.Test;
//
//public class KeepaliveTest {
// private static final long PING_MINIMUM = 1000;
// private static String TO = "juliet@capulet.lit/balcony";
// private static String ID = "s2c1";
//
// private static Properties outputProperties = new Properties();
// {
// outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
// }
//
// private int originalTimeout;
//
// @Before
// public void resetProperties()
// {
// SmackConfiguration.setKeepAliveInterval(-1);
// originalTimeout = SmackConfiguration.getPacketReplyTimeout();
// SmackConfiguration.setPacketReplyTimeout(1000);
// }
//
// @After
// public void restoreProperties()
// {
// SmackConfiguration.setPacketReplyTimeout(originalTimeout);
// }
// /*
// * Stanza copied from spec
// */
// @Test
// public void validatePingStanzaXML() throws Exception {
// // @formatter:off
// String control = "<iq to='juliet@capulet.lit/balcony' id='s2c1' type='get'>"
// + "<ping xmlns='urn:xmpp:ping'/></iq>";
// // @formatter:on
//
// Ping ping = new Ping(TO);
// ping.setPacketID(ID);
//
// assertXMLEqual(control, ping.toXML());
// }
//
// @Test
// public void serverPingFailSingleConnection() throws Exception {
// DummyConnection connection = getConnection();
// CountDownLatch latch = new CountDownLatch(2);
// addInterceptor(connection, latch);
// addPingFailedListener(connection, latch);
//
// // Time based testing kind of sucks, but this should be reliable on a DummyConnection since there
// // is no actual server involved. This will provide enough time to ping and wait for the lack of response.
// assertTrue(latch.await(getWaitTime(), TimeUnit.MILLISECONDS));
// }
//
// @Test
// public void serverPingSuccessfulSingleConnection() throws Exception {
// ThreadedDummyConnection connection = getThreadedConnection();
// final CountDownLatch latch = new CountDownLatch(1);
//
// connection.addPacketListener(new PacketListener() {
// @Override
// public void processPacket(Packet packet) {
// latch.countDown();
// }
// }, new IQTypeFilter(IQ.Type.RESULT));
//
// // Time based testing kind of sucks, but this should be reliable on a DummyConnection since there
// // is no actual server involved. This will provide enough time to ping and wait for the lack of response.
// assertTrue(latch.await(getWaitTime(), TimeUnit.MILLISECONDS));
// }
//
// @Test
// public void serverPingFailMultipleConnection() throws Exception {
// CountDownLatch latch = new CountDownLatch(6);
// SmackConfiguration.setPacketReplyTimeout(15000);
//
// DummyConnection con1 = getConnection();
// addInterceptor(con1, latch);
// addPingFailedListener(con1, latch);
//
// DummyConnection con2 = getConnection();
// addInterceptor(con2, latch);
// addPingFailedListener(con2, latch);
//
// DummyConnection con3 = getConnection();
// addInterceptor(con3, latch);
// addPingFailedListener(con2, latch);
//
// assertTrue(latch.await(getWaitTime(), TimeUnit.MILLISECONDS));
// }
//
// private void addPingFailedListener(DummyConnection con, final CountDownLatch latch) {
// KeepAliveManager manager = KeepAliveManager.getInstanceFor(con);
// manager.addPingFailedListener(new PingFailedListener() {
// @Override
// public void pingFailed() {
// latch.countDown();
// }
// });
// }
//
// private DummyConnection getConnection() {
// DummyConnection con = new DummyConnection();
// KeepAliveManager mgr = KeepAliveManager.getInstanceFor(con);
// mgr.setPingInterval(PING_MINIMUM);
//
// return con;
// }
//
// private ThreadedDummyConnection getThreadedConnection() {
// ThreadedDummyConnection con = new ThreadedDummyConnection();
// KeepAliveManager mgr = KeepAliveManager.getInstanceFor(con);
// mgr.setPingInterval(PING_MINIMUM);
//
// return con;
// }
//
// private void addInterceptor(final XMPPConnection con, final CountDownLatch latch) {
// con.addPacketInterceptor(new PacketInterceptor() {
// @Override
// public void interceptPacket(Packet packet) {
// con.removePacketInterceptor(this);
// latch.countDown();
// }
// }, new PacketTypeFilter(Ping.class));
// }
//
// private long getWaitTime() {
// return PING_MINIMUM + SmackConfiguration.getPacketReplyTimeout() + 3000;
// }
//}

View file

@ -0,0 +1,234 @@
/**
*
* Copyright 2012-2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.ping;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.ThreadedDummyConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.InitExtensions;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.ping.packet.Ping;
import org.junit.Before;
import org.junit.Test;
public class PingTest extends InitExtensions {
private DummyConnection dummyCon;
private ThreadedDummyConnection threadedCon;
@Before
public void setup() {
dummyCon = new DummyConnection();
threadedCon = new ThreadedDummyConnection();
}
@Test
public void checkProvider() throws Exception {
// @formatter:off
String control = "<iq from='capulet.lit' to='juliet@capulet.lit/balcony' id='s2c1' type='get'>"
+ "<ping xmlns='urn:xmpp:ping'/>"
+ "</iq>";
// @formatter:on
DummyConnection con = new DummyConnection();
// Enable ping for this connection
PingManager.getInstanceFor(con);
IQ pingRequest = PacketParserUtils.parseIQ(TestUtils.getIQParser(control), con);
assertTrue(pingRequest instanceof Ping);
con.processPacket(pingRequest);
Packet pongPacket = con.getSentPacket();
assertTrue(pongPacket instanceof IQ);
IQ pong = (IQ) pongPacket;
assertEquals("capulet.lit", pong.getTo());
assertEquals("s2c1", pong.getPacketID());
assertEquals(IQ.Type.RESULT, pong.getType());
}
@Test
public void checkSendingPing() throws InterruptedException {
dummyCon = new DummyConnection();
PingManager pinger = PingManager.getInstanceFor(dummyCon);
try {
pinger.ping("test@myserver.com");
}
catch (SmackException e) {
// Ignore the fact the server won't answer for this unit test.
}
Packet sentPacket = dummyCon.getSentPacket();
assertTrue(sentPacket instanceof Ping);
}
@Test
public void checkSuccessfulPing() throws Exception {
threadedCon = new ThreadedDummyConnection();
PingManager pinger = PingManager.getInstanceFor(threadedCon);
boolean pingSuccess = pinger.ping("test@myserver.com");
assertTrue(pingSuccess);
}
/**
* DummyConnection will not reply so it will timeout.
* @throws SmackException
*/
@Test
public void checkFailedPingOnTimeout() throws SmackException {
dummyCon = new DummyConnection();
PingManager pinger = PingManager.getInstanceFor(dummyCon);
try {
pinger.ping("test@myserver.com");
}
catch (NoResponseException e) {
return;
}
fail();
}
/**
* Server returns an exception for entity.
* @throws Exception
*/
@Test
public void checkFailedPingToEntityError() throws Exception {
threadedCon = new ThreadedDummyConnection();
//@formatter:off
String reply =
"<iq type='error' id='qrzSp-16' to='test@myserver.com'>" +
"<ping xmlns='urn:xmpp:ping'/>" +
"<error type='cancel'>" +
"<service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" +
"</error>" +
"</iq>";
//@formatter:on
IQ serviceUnavailable = PacketParserUtils.parseIQ(TestUtils.getIQParser(reply), threadedCon);
threadedCon.addIQReply(serviceUnavailable);
PingManager pinger = PingManager.getInstanceFor(threadedCon);
boolean pingSuccess = pinger.ping("test@myserver.com");
assertFalse(pingSuccess);
}
@Test
public void checkPingToServerSuccess() throws Exception {
ThreadedDummyConnection con = new ThreadedDummyConnection();
PingManager pinger = PingManager.getInstanceFor(con);
boolean pingSuccess = pinger.pingMyServer();
assertTrue(pingSuccess);
}
/**
* Server returns an exception.
* @throws Exception
*/
@Test
public void checkPingToServerError() throws Exception {
ThreadedDummyConnection con = new ThreadedDummyConnection();
//@formatter:off
String reply =
"<iq type='error' id='qrzSp-16' to='test@myserver.com' from='" + con.getServiceName() + "'>" +
"<ping xmlns='urn:xmpp:ping'/>" +
"<error type='cancel'>" +
"<service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" +
"</error>" +
"</iq>";
//@formatter:on
IQ serviceUnavailable = PacketParserUtils.parseIQ(TestUtils.getIQParser(reply), con);
con.addIQReply(serviceUnavailable);
PingManager pinger = PingManager.getInstanceFor(con);
boolean pingSuccess = pinger.pingMyServer();
assertTrue(pingSuccess);
}
@Test
public void checkPingToServerTimeout() throws NotConnectedException {
DummyConnection con = new DummyConnection();
PingManager pinger = PingManager.getInstanceFor(con);
boolean res = pinger.pingMyServer();
assertFalse(res);
}
@Test
public void checkSuccessfulDiscoRequest() throws Exception {
ThreadedDummyConnection con = new ThreadedDummyConnection();
DiscoverInfo info = new DiscoverInfo();
info.addFeature(PingManager.NAMESPACE);
//@formatter:off
String reply =
"<iq type='result' id='qrzSp-16' to='test@myserver.com'>" +
"<query xmlns='http://jabber.org/protocol/disco#info'><identity category='client' type='pc' name='Pidgin'/>" +
"<feature var='urn:xmpp:ping'/>" +
"</query></iq>";
//@formatter:on
IQ discoReply = PacketParserUtils.parseIQ(TestUtils.getIQParser(reply), con);
con.addIQReply(discoReply);
PingManager pinger = PingManager.getInstanceFor(con);
boolean pingSupported = pinger.isPingSupported("test@myserver.com");
assertTrue(pingSupported);
}
@Test
public void checkUnuccessfulDiscoRequest() throws Exception {
ThreadedDummyConnection con = new ThreadedDummyConnection();
DiscoverInfo info = new DiscoverInfo();
info.addFeature(PingManager.NAMESPACE);
//@formatter:off
String reply =
"<iq type='result' id='qrzSp-16' to='test@myserver.com'>" +
"<query xmlns='http://jabber.org/protocol/disco#info'><identity category='client' type='pc' name='Pidgin'/>" +
"<feature var='urn:xmpp:noping'/>" +
"</query></iq>";
//@formatter:on
IQ discoReply = PacketParserUtils.parseIQ(TestUtils.getIQParser(reply), con);
con.addIQReply(discoReply);
PingManager pinger = PingManager.getInstanceFor(con);
boolean pingSupported = pinger.isPingSupported("test@myserver.com");
assertFalse(pingSupported);
}
}

View file

@ -0,0 +1,69 @@
/**
*
* Copyright 2012 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.privacy.provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.InitExtensions;
import org.jivesoftware.smackx.privacy.packet.Privacy;
import org.jivesoftware.smackx.privacy.packet.PrivacyItem;
import org.junit.Test;
public class PrivacyProviderTest extends InitExtensions {
@Test
public void parsePrivacyList() throws Exception {
DummyConnection connection = new DummyConnection();
// @formatter:off
final String xmlPrivacyList =
"<iq type='result' id='getlist2' to='romeo@example.net/orchard'>"
+ "<query xmlns='jabber:iq:privacy'>"
+ "<list name='public'>"
+ "<item type='jid'"
+ "value='tybalt@example.com'"
+ "action='deny'"
+ "order='1'/>"
+ "<item action='allow' order='2'/>"
+ "</list>"
+ "</query>"
+ "</iq>";
// @formatter:on
IQ iqPrivacyList = PacketParserUtils.parseIQ(TestUtils.getIQParser(xmlPrivacyList), connection);
assertTrue(iqPrivacyList instanceof Privacy);
Privacy privacyList = (Privacy) iqPrivacyList;
List<PrivacyItem> pl = privacyList.getPrivacyList("public");
PrivacyItem first = pl.get(0);
assertEquals(PrivacyItem.Type.jid, first.getType());
assertEquals("tybalt@example.com", first.getValue());
assertEquals(false, first.isAllow());
assertEquals(1, first.getOrder());
PrivacyItem second = pl.get(1);
assertEquals(true, second.isAllow());
assertEquals(2, second.getOrder());
}
}

View file

@ -0,0 +1,93 @@
/**
*
* Copyright 2011 Robin Collier
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.pubsub;
import static org.junit.Assert.assertEquals;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.ThreadedDummyConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.packet.XMPPError.Condition;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Identity;
import org.jivesoftware.smackx.pubsub.packet.PubSub;
import org.junit.Assert;
import org.junit.Test;
/**
*
* @author Robin Collier
*
*/
public class ConfigureFormTest
{
@Test
public void checkChildrenAssocPolicy()
{
ConfigureForm form = new ConfigureForm(FormType.submit);
form.setChildrenAssociationPolicy(ChildrenAssociationPolicy.owners);
assertEquals(ChildrenAssociationPolicy.owners, form.getChildrenAssociationPolicy());
}
@Test
public void getConfigFormWithInsufficientPriviliges() throws XMPPException, SmackException
{
ThreadedDummyConnection con = new ThreadedDummyConnection();
PubSubManager mgr = new PubSubManager(con);
DiscoverInfo info = new DiscoverInfo();
Identity ident = new Identity("pubsub", null, "leaf");
info.addIdentity(ident);
con.addIQReply(info);
Node node = mgr.getNode("princely_musings");
PubSub errorIq = new PubSub();
XMPPError error = new XMPPError(Condition.forbidden);
errorIq.setError(error);
con.addIQReply(errorIq);
try
{
node.getNodeConfiguration();
}
catch (XMPPErrorException e)
{
Assert.assertEquals(XMPPError.Type.AUTH, e.getXMPPError().getType());
}
}
@Test (expected=SmackException.class)
public void getConfigFormWithTimeout() throws XMPPException, SmackException
{
ThreadedDummyConnection con = new ThreadedDummyConnection();
PubSubManager mgr = new PubSubManager(con);
DiscoverInfo info = new DiscoverInfo();
Identity ident = new Identity("pubsub", null, "leaf");
info.addIdentity(ident);
con.addIQReply(info);
Node node = mgr.getNode("princely_musings");
SmackConfiguration.setDefaultPacketReplyTimeout(100);
con.setTimeout();
node.getNodeConfiguration();
}
}

View file

@ -0,0 +1,237 @@
/**
*
* Copyright 2011 Robin Collier
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.pubsub;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.jivesoftware.smack.ThreadedDummyConnection;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.InitExtensions;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
/**
*
* @author Robin Collier
*
*/
public class ItemValidationTest extends InitExtensions {
private ThreadedDummyConnection connection;
@Before
public void setUp() throws Exception
{
// Uncomment this to enable debug output
// XMPPConnection.DEBUG_ENABLED = true;
connection = new ThreadedDummyConnection();
connection.connect();
connection.login("me", "secret");
}
@After
public void tearDown() throws Exception
{
if (connection != null)
connection.disconnect();
}
@Test
public void verifyBasicItem() throws Exception
{
Item simpleItem = new Item();
String simpleCtrl = "<item />";
assertXMLEqual(simpleCtrl, simpleItem.toXML());
Item idItem = new Item("uniqueid");
String idCtrl = "<item id='uniqueid'/>";
assertXMLEqual(idCtrl, idItem.toXML());
Item itemWithNodeId = new Item("testId", "testNode");
String nodeIdCtrl = "<item id='testId' node='testNode' />";
assertXMLEqual(nodeIdCtrl, itemWithNodeId.toXML());
}
@Test
public void verifyPayloadItem() throws Exception
{
SimplePayload payload = new SimplePayload(null, null, "<data>This is the payload</data>");
PayloadItem<SimplePayload> simpleItem = new PayloadItem<SimplePayload>(payload);
String simpleCtrl = "<item>" + payload.toXML() + "</item>";
assertXMLEqual(simpleCtrl, simpleItem.toXML());
PayloadItem<SimplePayload> idItem = new PayloadItem<SimplePayload>("uniqueid", payload);
String idCtrl = "<item id='uniqueid'>" + payload.toXML() + "</item>";
assertXMLEqual(idCtrl, idItem.toXML());
PayloadItem<SimplePayload> itemWithNodeId = new PayloadItem<SimplePayload>("testId", "testNode", payload);
String nodeIdCtrl = "<item id='testId' node='testNode'>" + payload.toXML() + "</item>";
assertXMLEqual(nodeIdCtrl, itemWithNodeId.toXML());
}
@Test
public void parseBasicItem() throws Exception
{
XmlPullParser parser = TestUtils.getMessageParser(
"<message from='pubsub.myserver.com' to='francisco@denmark.lit' id='foo'>" +
"<event xmlns='http://jabber.org/protocol/pubsub#event'>" +
"<items node='testNode'>" +
"<item id='testid1' />" +
"</items>" +
"</event>" +
"</message>");
Packet message = PacketParserUtils.parseMessage(parser);
PacketExtension eventExt = message.getExtension(PubSubNamespace.EVENT.getXmlns());
assertTrue(eventExt instanceof EventElement);
EventElement event = (EventElement) eventExt;
assertEquals(EventElementType.items, event.getEventType());
assertEquals(1, event.getExtensions().size());
assertTrue(event.getExtensions().get(0) instanceof ItemsExtension);
assertEquals(1, ((ItemsExtension)event.getExtensions().get(0)).items.size());
PacketExtension itemExt = ((ItemsExtension)event.getExtensions().get(0)).items.get(0);
assertTrue(itemExt instanceof Item);
assertEquals("testid1", ((Item)itemExt).getId());
}
@Test
public void parseSimplePayloadItem() throws Exception
{
String itemContent = "<foo xmlns='smack:test'>Some text</foo>";
XmlPullParser parser = TestUtils.getMessageParser(
"<message from='pubsub.myserver.com' to='francisco@denmark.lit' id='foo'>" +
"<event xmlns='http://jabber.org/protocol/pubsub#event'>" +
"<items node='testNode'>" +
"<item id='testid1' >" +
itemContent +
"</item>" +
"</items>" +
"</event>" +
"</message>");
Packet message = PacketParserUtils.parseMessage(parser);
PacketExtension eventExt = message.getExtension(PubSubNamespace.EVENT.getXmlns());
EventElement event = (EventElement) eventExt;
PacketExtension itemExt = ((ItemsExtension)event.getExtensions().get(0)).items.get(0);
assertTrue(itemExt instanceof PayloadItem<?>);
PayloadItem<?> item = (PayloadItem<?>)itemExt;
assertEquals("testid1", item.getId());
assertTrue(item.getPayload() instanceof SimplePayload);
SimplePayload payload = (SimplePayload) item.getPayload();
assertEquals("foo", payload.getElementName());
assertEquals("smack:test", payload.getNamespace());
assertXMLEqual(itemContent, payload.toXML());
}
@Test
public void parseComplexItem() throws Exception
{
String itemContent =
"<entry xmlns='http://www.w3.org/2005/Atom'>" +
"<title>Soliloquy</title>" +
"<summary>" +
"To be, or not to be: that is the question:" +
"Whether 'tis nobler in the mind to suffer" +
"The slings and arrows of outrageous fortune," +
"Or to take arms against a sea of troubles," +
"And by opposing end them?" +
"</summary>" +
"<link rel='alternate' type='text/html' href='http://denmark.lit/2003/12/13/atom03'/>" +
"<id>tag:denmark.lit,2003:entry-32397</id>" +
"<published>2003-12-13T18:30:02Z</published>" +
"<updated>2003-12-13T18:30:02Z</updated>" +
"</entry>";
XmlPullParser parser = TestUtils.getMessageParser(
"<message from='pubsub.myserver.com' to='francisco@denmark.lit' id='foo'>" +
"<event xmlns='http://jabber.org/protocol/pubsub#event'>" +
"<items node='testNode'>" +
"<item id='testid1' >" +
itemContent +
"</item>" +
"</items>" +
"</event>" +
"</message>");
Packet message = PacketParserUtils.parseMessage(parser);
PacketExtension eventExt = message.getExtension(PubSubNamespace.EVENT.getXmlns());
EventElement event = (EventElement) eventExt;
PacketExtension itemExt = ((ItemsExtension)event.getExtensions().get(0)).items.get(0);
assertTrue(itemExt instanceof PayloadItem<?>);
PayloadItem<?> item = (PayloadItem<?>)itemExt;
assertEquals("testid1", item.getId());
assertTrue(item.getPayload() instanceof SimplePayload);
SimplePayload payload = (SimplePayload) item.getPayload();
assertEquals("entry", payload.getElementName());
assertEquals("http://www.w3.org/2005/Atom", payload.getNamespace());
assertXMLEqual(itemContent, payload.toXML());
}
@Test
public void parseEmptyTag() throws Exception
{
String itemContent = "<foo xmlns='smack:test'><bar/></foo>";
XmlPullParser parser = TestUtils.getMessageParser(
"<message from='pubsub.myserver.com' to='francisco@denmark.lit' id='foo'>" +
"<event xmlns='http://jabber.org/protocol/pubsub#event'>" +
"<items node='testNode'>" +
"<item id='testid1' >" +
itemContent +
"</item>" +
"</items>" +
"</event>" +
"</message>");
Packet message = PacketParserUtils.parseMessage(parser);
PacketExtension eventExt = message.getExtension(PubSubNamespace.EVENT.getXmlns());
assertTrue(eventExt instanceof EventElement);
EventElement event = (EventElement) eventExt;
assertEquals(EventElementType.items, event.getEventType());
assertEquals(1, event.getExtensions().size());
assertTrue(event.getExtensions().get(0) instanceof ItemsExtension);
assertEquals(1, ((ItemsExtension)event.getExtensions().get(0)).items.size());
PacketExtension itemExt = ((ItemsExtension)event.getExtensions().get(0)).items.get(0);
assertTrue(itemExt instanceof PayloadItem<?>);
PayloadItem<?> item = (PayloadItem<?>)itemExt;
assertEquals("testid1", item.getId());
assertTrue(item.getPayload() instanceof SimplePayload);
assertXMLEqual(itemContent, ((SimplePayload)item.getPayload()).toXML());
}
}

View file

@ -0,0 +1,128 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.receipts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Properties;
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.InitExtensions;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import com.jamesmurty.utils.XMLBuilder;
public class DeliveryReceiptTest extends InitExtensions {
private static Properties outputProperties = new Properties();
static {
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void receiptTest() throws Exception {
XmlPullParser parser;
String control;
control = XMLBuilder.create("message")
.a("from", "romeo@montague.com")
.e("request")
.a("xmlns", "urn:xmpp:receipts")
.asString(outputProperties);
parser = TestUtils.getMessageParser(control);
Packet p = PacketParserUtils.parseMessage(parser);
DeliveryReceiptRequest drr = (DeliveryReceiptRequest)p.getExtension(
DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE);
assertNotNull(drr);
assertTrue(DeliveryReceiptManager.hasDeliveryReceiptRequest(p));
Message m = new Message("romeo@montague.com", Message.Type.normal);
assertFalse(DeliveryReceiptManager.hasDeliveryReceiptRequest(m));
DeliveryReceiptManager.addDeliveryReceiptRequest(m);
assertTrue(DeliveryReceiptManager.hasDeliveryReceiptRequest(m));
}
@Test
public void receiptManagerListenerTest() throws Exception {
DummyConnection c = new DummyConnection();
// Ensure SDM is created for this connection
ServiceDiscoveryManager.getInstanceFor(c);
DeliveryReceiptManager drm = DeliveryReceiptManager.getInstanceFor(c);
TestReceiptReceivedListener rrl = new TestReceiptReceivedListener();
drm.addReceiptReceivedListener(rrl);
Message m = new Message("romeo@montague.com", Message.Type.normal);
m.setFrom("julia@capulet.com");
m.setPacketID("reply-id");
m.addExtension(new DeliveryReceipt("original-test-id"));
drm.processPacket(m);
// ensure the listener got called
assertEquals("original-test-id", rrl.receiptId);
}
private static class TestReceiptReceivedListener implements ReceiptReceivedListener {
public String receiptId = null;
@Override
public void onReceiptReceived(String fromJid, String toJid, String receiptId) {
assertEquals("julia@capulet.com", fromJid);
assertEquals("romeo@montague.com", toJid);
assertEquals("original-test-id", receiptId);
this.receiptId = receiptId;
}
}
@Test
public void receiptManagerAutoReplyTest() throws Exception {
DummyConnection c = new DummyConnection();
// Ensure SDM is created for this connection
ServiceDiscoveryManager.getInstanceFor(c);
DeliveryReceiptManager drm = DeliveryReceiptManager.getInstanceFor(c);
drm.enableAutoReceipts();
assertTrue(drm.getAutoReceiptsEnabled());
// test auto-receipts
Message m = new Message("julia@capulet.com", Message.Type.normal);
m.setFrom("romeo@montague.com");
m.setPacketID("test-receipt-request");
DeliveryReceiptManager.addDeliveryReceiptRequest(m);
// the DRM will send a reply-packet
assertEquals(0, c.getNumberOfSentPackets());
drm.processPacket(m);
assertEquals(1, c.getNumberOfSentPackets());
Packet reply = c.getSentPacket();
DeliveryReceipt r = (DeliveryReceipt)reply.getExtension("received", "urn:xmpp:receipts");
assertEquals("romeo@montague.com", reply.getTo());
assertEquals("test-receipt-request", r.getId());
}
}

View file

@ -0,0 +1,98 @@
/**
*
* Copyright 2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.time.packet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.InitExtensions;
import org.junit.Test;
public class TimeTest extends InitExtensions {
@Test
public void parseCurrentTimeTest() {
Calendar calendar = Calendar.getInstance();
Time time = new Time(calendar);
Date date = time.getTime();
Date calendarDate = calendar.getTime();
assertEquals(calendarDate, date);
}
@Test
public void negativeTimezoneTest() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("GMT-830"));
Time time = new Time(calendar);
assertEquals("-8:30", time.getTzo());
}
@Test
public void positiveTimezoneTest() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("GMT+830"));
Time time = new Time(calendar);
assertEquals("+8:30", time.getTzo());
}
@Test
public void parseTimeWithIntrospectionTest() throws Exception {
DummyConnection connection = new DummyConnection();
// @formatter:off
final String request =
"<iq type='get'"
+ "from='romeo@montague.net/orchard'"
+ "to='juliet@capulet.com/balcony'"
+ "id='time_1'>"
+ "<time xmlns='urn:xmpp:time'/>"
+ "</iq>";
// @formatter:on
IQ iqRequest = PacketParserUtils.parseIQ(TestUtils.getIQParser(request), connection);
assertTrue(iqRequest instanceof Time);
// @formatter:off
final String response =
"<iq type='result'"
+ "from='juliet@capulet.com/balcony'"
+ "to='romeo@montague.net/orchard'"
+ "id='time_1'>"
+ "<time xmlns='urn:xmpp:time'>"
+ "<tzo>-06:00</tzo>"
+ "<utc>2006-12-19T17:58:35Z</utc>"
+ "</time>"
+ "</iq>";
// @formatter:on
IQ iqResponse = PacketParserUtils.parseIQ(TestUtils.getIQParser(response), connection);
assertTrue(iqResponse instanceof Time);
Time time = (Time) iqResponse;
assertEquals("-06:00", time.getTzo());
assertEquals("2006-12-19T17:58:35Z", time.getUtc());
}
}

View file

@ -0,0 +1,59 @@
/**
*
* Copyright 2014 Vyacheslav Blinov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.xhtmlim.provider;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class XHTMLExtensionProviderTest {
public static final String XHTML_EXTENSION_SAMPLE_RESOURCE_NAME = "xhtml.xml";
@Test
public void parsesWell() throws IOException, XmlPullParserException {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(getClass().getResourceAsStream(XHTML_EXTENSION_SAMPLE_RESOURCE_NAME), "UTF-8");
parser.next();
XHTMLExtensionProvider provider = new XHTMLExtensionProvider();
PacketExtension extension = provider.parseExtension(parser);
assertThat(extension, is(instanceOf(XHTMLExtension.class)));
XHTMLExtension attachmentsInfo = (XHTMLExtension) extension;
assertEquals(sampleXhtml(), attachmentsInfo.getBodies().get(0));
}
private String sampleXhtml() {
return "<body xmlns='http://www.w3.org/1999/xhtml'>" +
"<span style='color: rgb(0, 0, 0); font-family: sans-serif, &apos;trebuchet ms&apos;" +
", &apos;lucida grande&apos;, &apos;lucida sans unicode&apos;, arial, helvetica, " +
"sans-serif; font-weight: 600; line-height: 18px;'>Generic family<br/>AnotherLine</span></body>";
}
}

View file

@ -0,0 +1,123 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.util;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/**
* A collection of utility methods to create mocked XMPP connections.
*
* @author Henning Staib
*/
public class ConnectionUtils {
/**
* Creates a mocked XMPP connection that stores every packet that is send over this
* connection in the given protocol instance and returns the predefined answer packets
* form the protocol instance.
* <p>
* This mocked connection can used to collect packets that require a reply using a
* PacketCollector.
*
* <pre>
* <code>
* PacketCollector collector = connection.createPacketCollector(new PacketFilter());
* connection.sendPacket(packet);
* Packet reply = collector.nextResult();
* </code>
* </pre>
*
* @param protocol protocol helper containing answer packets
* @param initiatorJID the user associated to the XMPP connection
* @param xmppServer the XMPP server associated to the XMPP connection
* @return a mocked XMPP connection
* @throws SmackException
* @throws XMPPErrorException
*/
public static XMPPConnection createMockedConnection(final Protocol protocol,
String initiatorJID, String xmppServer) throws SmackException, XMPPErrorException {
// mock XMPP connection
XMPPConnection connection = mock(XMPPConnection.class);
when(connection.getUser()).thenReturn(initiatorJID);
when(connection.getServiceName()).thenReturn(xmppServer);
// mock packet collector
final PacketCollector collector = mock(PacketCollector.class);
when(connection.createPacketCollector(isA(PacketFilter.class))).thenReturn(
collector);
Answer<PacketCollector> collectorAndSend = new Answer<PacketCollector>() {
@Override
public PacketCollector answer(InvocationOnMock invocation) throws Throwable {
Packet packet = (Packet) invocation.getArguments()[0];
protocol.getRequests().add(packet);
return collector;
}
};
when(connection.createPacketCollectorAndSend(isA(IQ.class))).thenAnswer(collectorAndSend);
// mock send method
Answer<Object> addIncoming = new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
protocol.getRequests().add((Packet) invocation.getArguments()[0]);
return null;
}
};
doAnswer(addIncoming).when(connection).sendPacket(isA(Packet.class));
// mock receive methods
Answer<Packet> answer = new Answer<Packet>() {
public Packet answer(InvocationOnMock invocation) throws Throwable {
return protocol.getResponses().poll();
}
};
when(collector.nextResult(anyInt())).thenAnswer(answer);
when(collector.nextResult()).thenAnswer(answer);
Answer<Packet> answerOrThrow = new Answer<Packet>() {
@Override
public Packet answer(InvocationOnMock invocation) throws Throwable {
Packet packet = protocol.getResponses().poll();
if (packet == null) return packet;
XMPPError xmppError = packet.getError();
if (xmppError != null) throw new XMPPErrorException(xmppError);
return packet;
}
};
when(collector.nextResultOrThrow()).thenAnswer(answerOrThrow);
when(collector.nextResultOrThrow(anyLong())).thenAnswer(answerOrThrow);
// initialize service discovery manager for this connection
ServiceDiscoveryManager.getInstanceFor(connection);
return connection;
}
}

View file

@ -0,0 +1,198 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.util;
import static org.junit.Assert.*;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.jivesoftware.smack.packet.Packet;
/**
* This class can be used in conjunction with a mocked XMPP connection (
* {@link ConnectionUtils#createMockedConnection(Protocol, String, String)}) to
* verify a XMPP protocol. This can be accomplished in the following was:
* <ul>
* <li>add responses to packets sent over the mocked XMPP connection by the
* method to test in the order the tested method awaits them</li>
* <li>call the method to test</li>
* <li>call {@link #verifyAll()} to run assertions on the request/response pairs
* </li>
* </ul>
* Example:
*
* <pre>
* <code>
* public void methodToTest() {
* Packet packet = new Packet(); // create an XMPP packet
* PacketCollector collector = connection.createPacketCollector(new PacketIDFilter());
* connection.sendPacket(packet);
* Packet reply = collector.nextResult();
* }
*
* public void testMethod() {
* // create protocol
* Protocol protocol = new Protocol();
* // create mocked connection
* XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, "user@xmpp-server", "xmpp-server");
*
* // add reply packet to protocol
* Packet reply = new Packet();
* protocol.add(reply);
*
* // call method to test
* methodToTest();
*
* // verify protocol
* protocol.verifyAll();
* }
* </code>
* </pre>
*
* Additionally to adding the response to the protocol instance you can pass
* verifications that will be executed when {@link #verifyAll()} is invoked.
* (See {@link Verification} for more details.)
* <p>
* If the {@link #printProtocol} flag is set to true {@link #verifyAll()} will
* also print out the XML messages in the order they are sent to the console.
* This may be useful to inspect the whole protocol "by hand".
*
* @author Henning Staib
*/
public class Protocol {
/**
* Set to <code>true</code> to print XML messages to the console while
* verifying the protocol.
*/
public boolean printProtocol = false;
// responses to requests are taken form this queue
Queue<Packet> responses = new LinkedList<Packet>();
// list of verifications
List<Verification<?, ?>[]> verificationList = new ArrayList<Verification<?, ?>[]>();
// list of requests
List<Packet> requests = new ArrayList<Packet>();
// list of all responses
List<Packet> responsesList = new ArrayList<Packet>();
/**
* Adds a responses and all verifications for the request/response pair to
* the protocol.
*
* @param response the response for a request
* @param verifications verifications for request/response pair
*/
public void addResponse(Packet response, Verification<?, ?>... verifications) {
responses.offer(response);
verificationList.add(verifications);
responsesList.add(response);
}
/**
* Verifies the request/response pairs by checking if their numbers match
* and executes the verification for each pair.
*/
@SuppressWarnings("unchecked")
public void verifyAll() {
assertEquals(requests.size(), responsesList.size());
if (printProtocol)
System.out.println("=================== Start ===============\n");
for (int i = 0; i < requests.size(); i++) {
Packet request = requests.get(i);
Packet response = responsesList.get(i);
if (printProtocol) {
System.out.println("------------------- Request -------------\n");
System.out.println(prettyFormat(request.toXML().toString()));
System.out.println("------------------- Response ------------\n");
if (response != null) {
System.out.println(prettyFormat(response.toXML().toString()));
}
else {
System.out.println("No response");
}
}
Verification<Packet, Packet>[] verifications = (Verification<Packet, Packet>[]) verificationList.get(i);
if (verifications != null) {
for (Verification<Packet, Packet> verification : verifications) {
verification.verify(request, response);
}
}
}
if (printProtocol)
System.out.println("=================== End =================\n");
}
/**
* Returns the responses queue.
*
* @return the responses queue
*/
protected Queue<Packet> getResponses() {
return responses;
}
/**
* Returns a list of all collected requests.
*
* @return list of requests
*/
public List<Packet> getRequests() {
return requests;
}
private String prettyFormat(String input, int indent) {
try {
Source xmlInput = new StreamSource(new StringReader(input));
StringWriter stringWriter = new StringWriter();
StreamResult xmlOutput = new StreamResult(stringWriter);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount",
String.valueOf(indent));
transformer.transform(xmlInput, xmlOutput);
return xmlOutput.getWriter().toString();
}
catch (Exception e) {
return "error while formatting the XML: " + e.getMessage();
}
}
private String prettyFormat(String input) {
return prettyFormat(input, 2);
}
}

View file

@ -0,0 +1,100 @@
/**
*
* Copyright the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.util;
import static org.junit.Assert.*;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
/**
* Implement this interface to verify a request/response pair.
* <p>
* For convenience there are some useful predefined implementations.
*
* @param <T> class of the request
* @param <S> class of the response
*
* @author Henning Staib
*/
public interface Verification<T extends Packet, S extends Packet> {
/**
* Verifies that the "To" field of the request corresponds with the "From" field of
* the response.
*/
public static Verification<Packet, Packet> correspondingSenderReceiver = new Verification<Packet, Packet>() {
public void verify(Packet request, Packet response) {
assertEquals(response.getFrom(), request.getTo());
}
};
/**
* Verifies that the type of the request is a GET.
*/
public static Verification<IQ, Packet> requestTypeGET = new Verification<IQ, Packet>() {
public void verify(IQ request, Packet response) {
assertEquals(IQ.Type.GET, request.getType());
}
};
/**
* Verifies that the type of the request is a SET.
*/
public static Verification<IQ, Packet> requestTypeSET = new Verification<IQ, Packet>() {
public void verify(IQ request, Packet response) {
assertEquals(IQ.Type.SET, request.getType());
}
};
/**
* Verifies that the type of the request is a RESULT.
*/
public static Verification<IQ, Packet> requestTypeRESULT = new Verification<IQ, Packet>() {
public void verify(IQ request, Packet response) {
assertEquals(IQ.Type.RESULT, request.getType());
}
};
/**
* Verifies that the type of the request is an ERROR.
*/
public static Verification<IQ, Packet> requestTypeERROR = new Verification<IQ, Packet>() {
public void verify(IQ request, Packet response) {
assertEquals(IQ.Type.ERROR, request.getType());
}
};
/**
* Implement this method to make assertions of the request/response pairs.
*
* @param request the request collected by the mocked XMPP connection
* @param response the response added to the protocol instance
*/
public void verify(T request, S response);
}

View file

@ -0,0 +1 @@
<amp xmlns="http://jabber.org/protocol/amp"><rule action="alert" condition="deliver" value="direct"/><rule action="drop" condition="deliver" value="forward"/><rule action="error" condition="deliver" value="gateway"/><rule action="notify" condition="deliver" value="none"/><rule action="notify" condition="deliver" value="stored"/><rule action="notify" condition="expire-at" value="2004-09-10T08:33:14Z"/><rule action="notify" condition="match-resource" value="any"/><rule action="notify" condition="match-resource" value="exact"/><rule action="notify" condition="match-resource" value="other"/></amp>

View file

@ -0,0 +1,13 @@
<amp xmlns='http://jabber.org/protocol/amp'
status='alert'
from='bernardo@hamlet.lit/elsinore'
to='francisco@hamlet.lit'>
<rule action='test' condition='deliver' value='direct'/>
<rule action='drop' condition='deliver' value='forwarded'/>
<rule action='error' condition='delivered' value='gateway'/>
<rule action='notify' value='none'/>
<rule action='notify' condition='deliver'/>
<rule condition='expire-at' value='2004-09-10T08:33:14Z'/>
<rule condition='expire-at' />
<rule action='notify' condition='match-resource' value='anys'/>
</amp>

View file

@ -0,0 +1 @@
<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'><span style='color: rgb(0, 0, 0); font-family: sans-serif, &apos;trebuchet ms&apos;, &apos;lucida grande&apos;, &apos;lucida sans unicode&apos;, arial, helvetica, sans-serif; font-weight: 600; line-height: 18px;'>Generic family<br/>AnotherLine</span></body></html>