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:
parent
b6fb1f3743
commit
91fd15ad86
758 changed files with 42 additions and 42 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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=";
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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 <item-not-found/> 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());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <item-not-found/> 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());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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>";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
// }
|
||||
//}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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, 'trebuchet ms'" +
|
||||
", 'lucida grande', 'lucida sans unicode', arial, helvetica, " +
|
||||
"sans-serif; font-weight: 600; line-height: 18px;'>Generic family<br/>AnotherLine</span></body>";
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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, 'trebuchet ms', 'lucida grande', 'lucida sans unicode', arial, helvetica, sans-serif; font-weight: 600; line-height: 18px;'>Generic family<br/>AnotherLine</span></body></html>
|
Loading…
Add table
Add a link
Reference in a new issue