mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2025-09-09 18:29:45 +02:00
Add Integration Test Framework
and resurrect a few integration tests.
This commit is contained in:
parent
4e6fbe7293
commit
b8f046706b
34 changed files with 2333 additions and 100 deletions
21
smack-integration-test/build.gradle
Normal file
21
smack-integration-test/build.gradle
Normal file
|
@ -0,0 +1,21 @@
|
|||
apply plugin: 'application'
|
||||
|
||||
description = """\
|
||||
Smack integration tests."""
|
||||
|
||||
mainClassName = 'org.igniterealtime.smack.inttest.SmackIntegrationTestFramework'
|
||||
|
||||
dependencies {
|
||||
compile project(':smack-java7')
|
||||
compile project(':smack-tcp')
|
||||
compile project(':smack-extensions')
|
||||
compile 'org.reflections:reflections:0.9.9-RC1'
|
||||
compile 'eu.geekplace.javapinning:java-pinning-jar:1.0.1'
|
||||
compile "junit:junit:$junitVersion"
|
||||
testCompile "org.jxmpp:jxmpp-jid:$jxmppVersion:tests"
|
||||
}
|
||||
|
||||
run {
|
||||
// Pass all system properties down to the "application" run
|
||||
systemProperties System.getProperties()
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public abstract class AbstractSmackIntTest {
|
||||
|
||||
protected static final Logger LOGGER = Logger.getLogger(AbstractSmackIntTest.class.getName());
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
|
||||
public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest {
|
||||
|
||||
/**
|
||||
* The first connection.
|
||||
*/
|
||||
protected final XMPPConnection conOne;
|
||||
|
||||
/**
|
||||
* The second connection.
|
||||
*/
|
||||
protected final XMPPConnection conTwo;
|
||||
|
||||
/**
|
||||
* An alias for the first connection {@link #conOne}.
|
||||
*/
|
||||
protected final XMPPConnection connection;
|
||||
|
||||
protected final long defaultTimeout;
|
||||
|
||||
protected final String testRunId;
|
||||
|
||||
public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
this.connection = this.conOne = environment.conOne;
|
||||
this.conTwo = environment.conTwo;
|
||||
if (environment.configuration.replyTimeout > 0) {
|
||||
this.defaultTimeout = environment.configuration.replyTimeout;
|
||||
} else {
|
||||
this.defaultTimeout = 2 * 60 * 1000;
|
||||
}
|
||||
this.testRunId = environment.testRunId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||
import org.jxmpp.jid.DomainBareJid;
|
||||
|
||||
import eu.geekplace.javapinning.JavaPinning;
|
||||
|
||||
public abstract class AbstractSmackLowLevelIntegrationTest extends AbstractSmackIntTest {
|
||||
|
||||
/**
|
||||
* The configuration
|
||||
*/
|
||||
protected final Configuration configuration;
|
||||
|
||||
protected final String testRunId;
|
||||
|
||||
protected final DomainBareJid service;
|
||||
|
||||
public AbstractSmackLowLevelIntegrationTest(Configuration configuration, String testRunId) {
|
||||
this.configuration = configuration;
|
||||
this.testRunId = testRunId;
|
||||
this.service = configuration.service;
|
||||
}
|
||||
|
||||
public final XMPPTCPConnectionConfiguration.Builder getConnectionConfiguration() throws KeyManagementException, NoSuchAlgorithmException {
|
||||
XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();
|
||||
if (configuration.serviceTlsPin != null) {
|
||||
SSLContext sc = JavaPinning.forPin(configuration.serviceTlsPin);
|
||||
builder.setCustomSSLContext(sc);
|
||||
}
|
||||
builder.setSecurityMode(configuration.securityMode);
|
||||
builder.setServiceName(service);
|
||||
return builder;
|
||||
}
|
||||
|
||||
protected void performCheck(ConnectionCallback callback) throws Exception {
|
||||
XMPPTCPConnection connection = SmackIntegrationTestFramework.getConnectedConnection(configuration);
|
||||
try {
|
||||
callback.connectionCallback(connection);
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public interface ConnectionCallback {
|
||||
public void connectionCallback(XMPPTCPConnection connection) throws Exception;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,291 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jxmpp.jid.DomainBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
|
||||
public class Configuration {
|
||||
|
||||
public final DomainBareJid service;
|
||||
|
||||
public final String serviceTlsPin;
|
||||
|
||||
public final SecurityMode securityMode;
|
||||
|
||||
public final int replyTimeout;
|
||||
|
||||
public final boolean registerAccounts;
|
||||
|
||||
public final String accountOneUsername;
|
||||
|
||||
public final String accountOnePassword;
|
||||
|
||||
public final String accountTwoUsername;
|
||||
|
||||
public final String accountTwoPassword;
|
||||
|
||||
public final boolean debug;
|
||||
|
||||
public final Set<String> enabledTests;
|
||||
|
||||
public final Set<String> disabledTests;
|
||||
|
||||
public final Set<String> testPackages;
|
||||
|
||||
private Configuration(DomainBareJid service, String serviceTlsPin, SecurityMode securityMode, int replyTimeout,
|
||||
boolean debug, String accountOneUsername, String accountOnePassword, String accountTwoUsername,
|
||||
String accountTwoPassword, Set<String> enabledTests, Set<String> disabledTests,
|
||||
Set<String> testPackages) {
|
||||
this.service = service;
|
||||
this.serviceTlsPin = serviceTlsPin;
|
||||
this.securityMode = securityMode;
|
||||
this.replyTimeout = replyTimeout;
|
||||
this.debug = debug;
|
||||
if (StringUtils.isNullOrEmpty(accountOneUsername) || StringUtils.isNullOrEmpty(accountOnePassword)
|
||||
|| StringUtils.isNullOrEmpty(accountTwoUsername)
|
||||
|| StringUtils.isNullOrEmpty(accountTwoPassword)) {
|
||||
registerAccounts = true;
|
||||
}
|
||||
else {
|
||||
registerAccounts = false;
|
||||
}
|
||||
this.accountOneUsername = accountOneUsername;
|
||||
this.accountOnePassword = accountOnePassword;
|
||||
this.accountTwoUsername = accountTwoUsername;
|
||||
this.accountTwoPassword = accountTwoPassword;
|
||||
this.enabledTests = enabledTests;
|
||||
this.disabledTests = disabledTests;
|
||||
this.testPackages = testPackages;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private DomainBareJid service;
|
||||
|
||||
private String serviceTlsPin;
|
||||
|
||||
private SecurityMode securityMode;
|
||||
|
||||
private int replyTimeout;
|
||||
|
||||
private String accountOneUsername;
|
||||
|
||||
private String accountOnePassword;
|
||||
|
||||
private String accountTwoUsername;
|
||||
|
||||
private String accountTwoPassword;
|
||||
|
||||
private boolean debug;
|
||||
|
||||
private Set<String> enabledTests;
|
||||
|
||||
private Set<String> disabledTests;
|
||||
|
||||
private Set<String> testPackages;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
public Builder setService(String service) throws XmppStringprepException {
|
||||
return setService(JidCreate.domainBareFrom(service));
|
||||
}
|
||||
|
||||
public Builder setService(DomainBareJid service) {
|
||||
this.service = service;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addEnabledTest(Class<? extends AbstractSmackIntTest> enabledTest) {
|
||||
if (enabledTests == null) {
|
||||
enabledTests = new HashSet<>();
|
||||
}
|
||||
enabledTests.add(enabledTest.getName());
|
||||
// Also add the package of the test as test package
|
||||
return addTestPackage(enabledTest.getPackage().getName());
|
||||
}
|
||||
|
||||
public Builder addTestPackage(String testPackage) {
|
||||
if (testPackages == null) {
|
||||
testPackages = new HashSet<>();
|
||||
}
|
||||
testPackages.add(testPackage);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUsernamesAndPassword(String accountOneUsername, String accountOnePassword,
|
||||
String accountTwoUsername, String accountTwoPassword) {
|
||||
this.accountOneUsername = accountOneUsername;
|
||||
this.accountOnePassword = accountOnePassword;
|
||||
this.accountTwoUsername = accountTwoUsername;
|
||||
this.accountTwoPassword = accountTwoPassword;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setServiceTlsPin(String tlsPin) {
|
||||
this.serviceTlsPin = tlsPin;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSecurityMode(String securityModeString) {
|
||||
if (securityModeString != null) {
|
||||
securityMode = SecurityMode.valueOf(securityModeString);
|
||||
}
|
||||
else {
|
||||
securityMode = SecurityMode.required;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setReplyTimeout(String timeout) {
|
||||
if (timeout != null) {
|
||||
replyTimeout = Integer.valueOf(timeout);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDebug(String debugString) {
|
||||
if (debugString != null) {
|
||||
debug = Boolean.valueOf(debugString);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEnabledTests(String enabledTestsString) {
|
||||
enabledTests = getTestSetFrom(enabledTestsString);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDisabledTests(String disabledTestsString) {
|
||||
disabledTests = getTestSetFrom(disabledTestsString);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTestPackages(String testPackagesString) {
|
||||
if (testPackagesString != null) {
|
||||
String[] testPackagesArray = testPackagesString.split(",");
|
||||
testPackages = new HashSet<>(testPackagesArray.length);
|
||||
for (String s : testPackagesArray) {
|
||||
testPackages.add(s.trim());
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Configuration build() {
|
||||
return new Configuration(service, serviceTlsPin, securityMode, replyTimeout, debug, accountOneUsername,
|
||||
accountOnePassword, accountTwoUsername, accountTwoPassword, enabledTests, disabledTests,
|
||||
testPackages);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String SINTTEST = "sinttest.";
|
||||
|
||||
public static Configuration newConfiguration() throws IOException {
|
||||
File propertiesFile = findPropertiesFile();
|
||||
Properties properties = new Properties();
|
||||
|
||||
try (FileInputStream in = new FileInputStream(propertiesFile)) {
|
||||
properties.load(in);
|
||||
}
|
||||
|
||||
// Properties set via the system override the file properties
|
||||
Properties systemProperties = System.getProperties();
|
||||
for (Entry<Object, Object> entry : systemProperties.entrySet()) {
|
||||
String key = (String) entry.getKey();
|
||||
if (!key.startsWith(SINTTEST)) {
|
||||
continue;
|
||||
}
|
||||
key = key.substring(SINTTEST.length());
|
||||
String value = (String) entry.getValue();
|
||||
properties.put(key, value);
|
||||
}
|
||||
|
||||
Builder builder = builder();
|
||||
builder.setService(properties.getProperty("service"));
|
||||
builder.setServiceTlsPin(properties.getProperty("serviceTlsPin"));
|
||||
builder.setSecurityMode(properties.getProperty("securityMode"));
|
||||
builder.setReplyTimeout(properties.getProperty("replyTimeout", "60000"));
|
||||
|
||||
String accountOneUsername = properties.getProperty("accountOneUsername");
|
||||
String accountOnePassword = properties.getProperty("accountOnePassword");
|
||||
String accountTwoUsername = properties.getProperty("accountTwoUsername");
|
||||
String accountTwoPassword = properties.getProperty("accountTwoPassword");
|
||||
builder.setUsernamesAndPassword(accountOneUsername, accountOnePassword, accountTwoUsername, accountTwoPassword);
|
||||
|
||||
builder.setDebug(properties.getProperty("debug"));
|
||||
builder.setEnabledTests(properties.getProperty("enabledTests"));
|
||||
builder.setDisabledTests(properties.getProperty("disabledTests"));
|
||||
builder.setTestPackages(properties.getProperty("testPackages"));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static File findPropertiesFile() throws IOException {
|
||||
List<String> possibleLocations = new LinkedList<>();
|
||||
possibleLocations.add("properties");
|
||||
String userHome = System.getProperty("user.home");
|
||||
if (userHome != null) {
|
||||
possibleLocations.add(userHome + "/.config/smack-integration-test/properties");
|
||||
}
|
||||
|
||||
for (String possibleLocation : possibleLocations) {
|
||||
File res = new File(possibleLocation);
|
||||
if (res.isFile())
|
||||
return res;
|
||||
}
|
||||
throw new IOException("Could not find properties file");
|
||||
}
|
||||
|
||||
private static Set<String> getTestSetFrom(String string) {
|
||||
if (string == null) {
|
||||
return null;
|
||||
}
|
||||
String[] stringArray = string.split(",");
|
||||
Set<String> res = new HashSet<>(stringArray.length);
|
||||
for (String s : stringArray) {
|
||||
res.add(getFullTestStringFrom(s));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static String getFullTestStringFrom(String string) {
|
||||
string = string.trim();
|
||||
if (string.startsWith("smackx.") || string.startsWith("smack.")) {
|
||||
string = "org.jivesoftware." + string;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
public class FailedTest extends TestResult {
|
||||
|
||||
public final Exception failureReason;
|
||||
|
||||
public FailedTest(Method testMethod, long startTime, long endTime, List<String> logMessages, Exception failureReason) {
|
||||
super(testMethod, startTime, endTime, logMessages);
|
||||
this.failureReason = failureReason;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.iqregister.AccountManager;
|
||||
|
||||
public class IntTestUtil {
|
||||
|
||||
public static UsernameAndPassword registerAccount(XMPPConnection connection)
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException,
|
||||
InterruptedException {
|
||||
return registerAccount(connection, StringUtils.randomString(12),
|
||||
StringUtils.randomString(12));
|
||||
}
|
||||
|
||||
public static UsernameAndPassword registerAccount(XMPPConnection connection, String username,
|
||||
String password) throws NoResponseException, XMPPErrorException,
|
||||
NotConnectedException, InterruptedException {
|
||||
AccountManager accountManager = AccountManager.getInstance(connection);
|
||||
if (!accountManager.supportsAccountCreation()) {
|
||||
throw new UnsupportedOperationException("Account creation/registation is not supported");
|
||||
}
|
||||
Set<String> requiredAttributes = accountManager.getAccountAttributes();
|
||||
if (requiredAttributes.size() > 4) {
|
||||
throw new IllegalStateException("Unkown required attributes");
|
||||
}
|
||||
Map<String, String> additionalAttributes = new HashMap<>();
|
||||
additionalAttributes.put("name", "Smack Integration Test");
|
||||
additionalAttributes.put("email", "flow@igniterealtime.org");
|
||||
accountManager.createAccount(username, password, additionalAttributes);
|
||||
|
||||
return new UsernameAndPassword(username, password);
|
||||
}
|
||||
|
||||
public static class UsernameAndPassword {
|
||||
public final String username;
|
||||
public final String password;
|
||||
|
||||
private UsernameAndPassword(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface SmackIntegrationTest {
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
|
||||
public class SmackIntegrationTestEnvironment {
|
||||
|
||||
public final XMPPTCPConnection conOne;
|
||||
|
||||
public final XMPPTCPConnection conTwo;
|
||||
|
||||
public final String testRunId;
|
||||
|
||||
public final Configuration configuration;
|
||||
|
||||
SmackIntegrationTestEnvironment(XMPPTCPConnection conOne, XMPPTCPConnection conTwo, String testRunId,
|
||||
Configuration configuration) {
|
||||
this.conOne = conOne;
|
||||
this.conTwo = conTwo;
|
||||
this.testRunId = testRunId;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,633 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import static org.reflections.ReflectionUtils.getAllMethods;
|
||||
import static org.reflections.ReflectionUtils.withAnnotation;
|
||||
import static org.reflections.ReflectionUtils.withModifier;
|
||||
import static org.reflections.ReflectionUtils.withParametersCount;
|
||||
import static org.reflections.ReflectionUtils.withReturnType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.igniterealtime.smack.inttest.IntTestUtil.UsernameAndPassword;
|
||||
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
|
||||
import org.jivesoftware.smack.SmackConfiguration;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration.Builder;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.iqregister.AccountManager;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.scanners.MethodAnnotationsScanner;
|
||||
import org.reflections.scanners.MethodParameterScanner;
|
||||
import org.reflections.scanners.SubTypesScanner;
|
||||
import org.reflections.scanners.TypeAnnotationsScanner;
|
||||
|
||||
import eu.geekplace.javapinning.JavaPinning;
|
||||
|
||||
public class SmackIntegrationTestFramework {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(SmackIntegrationTestFramework.class.getName());
|
||||
private static final char CLASS_METHOD_SEP = '#';
|
||||
|
||||
protected final Configuration config;
|
||||
protected TestRunResult testRunResult;
|
||||
private SmackIntegrationTestEnvironment environment;
|
||||
|
||||
public enum TestType {
|
||||
Normal,
|
||||
LowLevel,
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException, KeyManagementException,
|
||||
NoSuchAlgorithmException, SmackException, XMPPException, InterruptedException {
|
||||
Configuration config = Configuration.newConfiguration();
|
||||
|
||||
SmackIntegrationTestFramework sinttest = new SmackIntegrationTestFramework(config);
|
||||
TestRunResult testRunResult = sinttest.run();
|
||||
|
||||
for (Entry<Class<? extends AbstractSmackIntTest>, String> entry : testRunResult.impossibleTestClasses.entrySet()) {
|
||||
LOGGER.info("Could not run " + entry.getKey().getName() + " because: "
|
||||
+ entry.getValue());
|
||||
}
|
||||
for (TestNotPossible testNotPossible : testRunResult.impossibleTestMethods) {
|
||||
LOGGER.info("Could not run " + testNotPossible.testMethod.getName() + " because: "
|
||||
+ testNotPossible.testNotPossibleException.getMessage());
|
||||
}
|
||||
LOGGER.info("SmackIntegrationTestFramework[" + testRunResult.testRunId + ']' + ": Finished ["
|
||||
+ testRunResult.successfulTests.size() + '/' + testRunResult.numberOfTests + ']');
|
||||
if (!testRunResult.failedIntegrationTests.isEmpty()) {
|
||||
for (FailedTest failedTest : testRunResult.failedIntegrationTests) {
|
||||
final Method method = failedTest.testMethod;
|
||||
final String className = method.getDeclaringClass().getName();
|
||||
final String methodName = method.getName();
|
||||
final Exception cause = failedTest.failureReason;
|
||||
LOGGER.severe(className + CLASS_METHOD_SEP + methodName + " failed: " + cause);
|
||||
}
|
||||
System.exit(2);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public SmackIntegrationTestFramework(Configuration configuration) {
|
||||
this.config = configuration;
|
||||
}
|
||||
|
||||
public synchronized TestRunResult run() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
|
||||
IOException, XMPPException, InterruptedException {
|
||||
testRunResult = new TestRunResult();
|
||||
LOGGER.info("SmackIntegrationTestFramework [" + testRunResult.testRunId + ']' + ": Starting");
|
||||
if (config.debug) {
|
||||
// JUL Debugger will not print any information until configured to print log messages of
|
||||
// level FINE
|
||||
// TODO configure JUL for log?
|
||||
SmackConfiguration.addDisabledSmackClass("org.jivesoftware.smack.debugger.JulDebugger");
|
||||
SmackConfiguration.DEBUG = true;
|
||||
}
|
||||
if (config.replyTimeout > 0) {
|
||||
SmackConfiguration.setDefaultPacketReplyTimeout(config.replyTimeout);
|
||||
}
|
||||
if (config.securityMode != SecurityMode.required) {
|
||||
AccountManager.sensitiveOperationOverInsecureConnectionDefault(true);
|
||||
}
|
||||
// TODO print effective configuration
|
||||
|
||||
String[] testPackages;
|
||||
if (config.testPackages == null) {
|
||||
testPackages = new String[] { "org.jivesoftware.smackx", "org.jivesoftware.smack" };
|
||||
}
|
||||
else {
|
||||
testPackages = config.testPackages.toArray(new String[config.testPackages.size()]);
|
||||
}
|
||||
Reflections reflections = new Reflections((Object[]) testPackages, new SubTypesScanner(),
|
||||
new TypeAnnotationsScanner(), new MethodAnnotationsScanner(), new MethodParameterScanner());
|
||||
Set<Class<? extends AbstractSmackIntegrationTest>> inttestClasses = reflections.getSubTypesOf(AbstractSmackIntegrationTest.class);
|
||||
Set<Class<? extends AbstractSmackLowLevelIntegrationTest>> lowLevelInttestClasses = reflections.getSubTypesOf(AbstractSmackLowLevelIntegrationTest.class);
|
||||
|
||||
Set<Class<? extends AbstractSmackIntTest>> classes = new HashSet<>(inttestClasses.size()
|
||||
+ lowLevelInttestClasses.size());
|
||||
classes.addAll(inttestClasses);
|
||||
classes.addAll(lowLevelInttestClasses);
|
||||
|
||||
if (classes.isEmpty()) {
|
||||
throw new IllegalStateException("No test classes found");
|
||||
}
|
||||
|
||||
LOGGER.info("SmackIntegrationTestFramework [" + testRunResult.testRunId
|
||||
+ "]: Finished scanning for tests, preparing environment");
|
||||
environment = prepareEnvironment();
|
||||
|
||||
try {
|
||||
runTests(classes);
|
||||
}
|
||||
finally {
|
||||
// Ensure that the accounts are deleted and disconnected before we continue
|
||||
disconnectAndMaybeDelete(environment.conOne);
|
||||
disconnectAndMaybeDelete(environment.conTwo);
|
||||
}
|
||||
|
||||
return testRunResult;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void runTests(Set<Class<? extends AbstractSmackIntTest>> classes)
|
||||
throws NoResponseException, NotConnectedException, InterruptedException {
|
||||
for (Class<? extends AbstractSmackIntTest> testClass : classes) {
|
||||
final String testClassName = testClass.getName();
|
||||
|
||||
if (config.enabledTests != null && !config.enabledTests.contains(testClassName)) {
|
||||
LOGGER.info("Skipping test class " + testClassName + " because it is not enabled");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config.disabledTests != null && config.disabledTests.contains(testClassName)) {
|
||||
LOGGER.info("Skipping test class " + testClassName + " because it is disalbed");
|
||||
continue;
|
||||
}
|
||||
|
||||
TestType testType;
|
||||
if (AbstractSmackLowLevelIntegrationTest.class.isAssignableFrom(testClass)) {
|
||||
testType = TestType.LowLevel;
|
||||
} else if (AbstractSmackIntegrationTest.class.isAssignableFrom(testClass)) {
|
||||
testType = TestType.Normal;
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
List<Method> smackIntegrationTestMethods = new LinkedList<>();
|
||||
for (Method method : testClass.getMethods()) {
|
||||
if (!method.isAnnotationPresent(SmackIntegrationTest.class)) {
|
||||
continue;
|
||||
}
|
||||
Class<?> retClass = method.getReturnType();
|
||||
if (!(retClass.equals(Void.TYPE))) {
|
||||
LOGGER.warning("SmackIntegrationTest annotation on method that does not return void");
|
||||
continue;
|
||||
}
|
||||
final Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
switch (testType) {
|
||||
case Normal:
|
||||
if (method.getParameterTypes().length > 0) {
|
||||
LOGGER.warning("SmackIntegrationTest annotaton on method that takes arguments ");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case LowLevel:
|
||||
for (Class<?> parameterType : parameterTypes) {
|
||||
if (!parameterType.isAssignableFrom(XMPPTCPConnection.class)) {
|
||||
LOGGER.warning("SmackIntegrationTest low-level test method declares parameter that is not of type XMPPTCPConnection");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
smackIntegrationTestMethods.add(method);
|
||||
}
|
||||
|
||||
if (smackIntegrationTestMethods.isEmpty()) {
|
||||
LOGGER.warning("No integration test methods found");
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator<Method> it = smackIntegrationTestMethods.iterator();
|
||||
while (it.hasNext()) {
|
||||
final Method method = it.next();
|
||||
final String methodName = method.getName();
|
||||
final String className = method.getDeclaringClass().getName();
|
||||
if (config.enabledTests != null && !config.enabledTests.contains(methodName)
|
||||
&& !config.enabledTests.contains(className)) {
|
||||
LOGGER.fine("Skipping test method " + methodName + " because it is not enabled");
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
if (config.disabledTests != null && config.disabledTests.contains(methodName)) {
|
||||
LOGGER.info("Skipping test method " + methodName + " because it is disabled");
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (smackIntegrationTestMethods.isEmpty()) {
|
||||
LOGGER.info("All tests in " + testClassName + " are disabled");
|
||||
continue;
|
||||
}
|
||||
|
||||
testRunResult.numberOfTests.addAndGet(smackIntegrationTestMethods.size());
|
||||
|
||||
AbstractSmackIntTest test;
|
||||
switch (testType) {
|
||||
case Normal: {
|
||||
Constructor<? extends AbstractSmackIntegrationTest> cons;
|
||||
try {
|
||||
cons = ((Class<? extends AbstractSmackIntegrationTest>) testClass).getConstructor(SmackIntegrationTestEnvironment.class);
|
||||
}
|
||||
catch (NoSuchMethodException | SecurityException e) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Smack Integration Test class could not get constructed (public Con)structor(SmackIntegrationTestEnvironment) missing?)",
|
||||
e);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
test = cons.newInstance(environment);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof TestNotPossibleException) {
|
||||
testRunResult.impossibleTestClasses.put(testClass, cause.getMessage());
|
||||
}
|
||||
else {
|
||||
throwFatalException(cause);
|
||||
LOGGER.log(Level.WARNING, "Could not construct test class", e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException | IllegalArgumentException e) {
|
||||
LOGGER.log(Level.WARNING, "todo", e);
|
||||
continue;
|
||||
}
|
||||
} break;
|
||||
case LowLevel: {
|
||||
Constructor<? extends AbstractSmackLowLevelIntegrationTest> cons;
|
||||
try {
|
||||
cons = ((Class<? extends AbstractSmackLowLevelIntegrationTest>) testClass).getConstructor(
|
||||
Configuration.class, String.class);
|
||||
}
|
||||
catch (NoSuchMethodException | SecurityException e) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Smack Integration Test class could not get constructed (public Con)structor(SmackIntegrationTestEnvironment) missing?)",
|
||||
e);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
test = cons.newInstance(config, testRunResult.testRunId);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof TestNotPossibleException) {
|
||||
testRunResult.impossibleTestClasses.put(testClass, cause.getMessage());
|
||||
}
|
||||
else {
|
||||
throwFatalException(cause);
|
||||
LOGGER.log(Level.WARNING, "Could not construct test class", e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException | IllegalArgumentException e) {
|
||||
LOGGER.log(Level.WARNING, "todo", e);
|
||||
continue;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
try {
|
||||
// Run the @BeforeClass methods (if any)
|
||||
Set<Method> beforeClassMethods = getAllMethods(testClass,
|
||||
withAnnotation(BeforeClass.class), withReturnType(Void.TYPE),
|
||||
withParametersCount(0), withModifier(Modifier.PUBLIC
|
||||
| Modifier.STATIC));
|
||||
|
||||
// See if there are any methods that have the @BeforeClassAnnotation but a wrong signature
|
||||
Set<Method> allBeforeClassMethods = getAllMethods(testClass, withAnnotation(BeforeClass.class));
|
||||
allBeforeClassMethods.removeAll(beforeClassMethods);
|
||||
if (!allBeforeClassMethods.isEmpty()) {
|
||||
LOGGER.warning("@BeforeClass methods with wrong signature found");
|
||||
}
|
||||
|
||||
if (beforeClassMethods.size() == 1) {
|
||||
Method beforeClassMethod = beforeClassMethods.iterator().next();
|
||||
try {
|
||||
beforeClassMethod.invoke(null);
|
||||
}
|
||||
catch (InvocationTargetException | IllegalAccessException e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception executing @AfterClass method", e);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
else if (beforeClassMethods.size() > 1) {
|
||||
throw new IllegalArgumentException("Only one @BeforeClass method allowed");
|
||||
}
|
||||
|
||||
for (Method testMethod : smackIntegrationTestMethods) {
|
||||
final String testPrefix = testClass.getSimpleName() + '.'
|
||||
+ testMethod.getName() + ": ";
|
||||
// Invoke all test methods on the test instance
|
||||
LOGGER.info(testPrefix + "Start");
|
||||
long testStart = System.currentTimeMillis();
|
||||
try {
|
||||
switch (testType) {
|
||||
case Normal:
|
||||
testMethod.invoke(test);
|
||||
break;
|
||||
case LowLevel:
|
||||
invokeLowLevel(testMethod, test);
|
||||
break;
|
||||
}
|
||||
LOGGER.info(testPrefix + "Success");
|
||||
long testEnd = System.currentTimeMillis();
|
||||
testRunResult.successfulTests.add(new SuccessfulTest(testMethod, testStart, testEnd, null));
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
long testEnd = System.currentTimeMillis();
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof TestNotPossibleException) {
|
||||
LOGGER.info(testPrefix + "Not possible");
|
||||
testRunResult.impossibleTestMethods.add(new TestNotPossible(testMethod, testStart, testEnd,
|
||||
null, (TestNotPossibleException) cause));
|
||||
continue;
|
||||
}
|
||||
Exception nonFatalException = throwFatalException(cause);
|
||||
// An integration test failed
|
||||
testRunResult.failedIntegrationTests.add(new FailedTest(testMethod, testStart, testEnd, null,
|
||||
nonFatalException));
|
||||
LOGGER.log(Level.SEVERE, testPrefix + "Failed", e);
|
||||
}
|
||||
catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Run the @AfterClass method (if any)
|
||||
Set<Method> afterClassMethods = getAllMethods(testClass,
|
||||
withAnnotation(AfterClass.class), withReturnType(Void.TYPE),
|
||||
withParametersCount(0), withModifier(Modifier.PUBLIC
|
||||
| Modifier.STATIC));
|
||||
|
||||
// See if there are any methods that have the @AfterClassAnnotation but a wrong signature
|
||||
Set<Method> allAfterClassMethods = getAllMethods(testClass, withAnnotation(BeforeClass.class));
|
||||
allAfterClassMethods.removeAll(afterClassMethods);
|
||||
if (!allAfterClassMethods.isEmpty()) {
|
||||
LOGGER.warning("@AfterClass methods with wrong signature found");
|
||||
}
|
||||
|
||||
if (afterClassMethods.size() == 1) {
|
||||
Method afterClassMethod = afterClassMethods.iterator().next();
|
||||
try {
|
||||
afterClassMethod.invoke(null);
|
||||
}
|
||||
catch (InvocationTargetException | IllegalAccessException e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception executing @AfterClass method", e);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
else if (afterClassMethods.size() > 1) {
|
||||
throw new IllegalArgumentException("Only one @AfterClass method allowed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeLowLevel(Method testMethod, AbstractSmackIntTest test) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
// We have checked before that every parameter, if any, is of type XMPPTCPConnection
|
||||
final int numberOfConnections = testMethod.getParameterTypes().length;
|
||||
XMPPTCPConnection[] connections = null;
|
||||
try {
|
||||
if (numberOfConnections > 0 && !config.registerAccounts) {
|
||||
throw new TestNotPossibleException(
|
||||
"Must create accounts for this test, but it's not enabled");
|
||||
}
|
||||
connections = new XMPPTCPConnection[numberOfConnections];
|
||||
for (int i = 0; i < numberOfConnections; ++i) {
|
||||
connections[i] = getConnectedConnection(config);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException) e;
|
||||
}
|
||||
// Behave like this was an InvocationTargetException
|
||||
throw new InvocationTargetException(e);
|
||||
}
|
||||
try {
|
||||
testMethod.invoke(test, (Object[]) connections);
|
||||
}
|
||||
finally {
|
||||
for (int i = 0; i < numberOfConnections; ++i) {
|
||||
try {
|
||||
AccountManager.getInstance(connections[i]).deleteAccount();
|
||||
LOGGER.info("Successfully deleted account for connection ("
|
||||
+ connections[i].getConnectionCounter() + ')');
|
||||
}
|
||||
catch (NoResponseException | XMPPErrorException | NotConnectedException
|
||||
| InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE, "Could not delete account", e);
|
||||
}
|
||||
connections[i].disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void disconnectAndMaybeDelete(XMPPTCPConnection connection)
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException,
|
||||
InterruptedException {
|
||||
if (config.registerAccounts) {
|
||||
AccountManager am = AccountManager.getInstance(connection);
|
||||
am.deleteAccount();
|
||||
}
|
||||
connection.disconnect();
|
||||
}
|
||||
|
||||
protected SmackIntegrationTestEnvironment prepareEnvironment() throws SmackException,
|
||||
IOException, XMPPException, InterruptedException, KeyManagementException,
|
||||
NoSuchAlgorithmException {
|
||||
XMPPTCPConnection conOne = null;
|
||||
XMPPTCPConnection conTwo = null;
|
||||
try {
|
||||
conOne = getConnectedConnectionFor(AccountNum.One);
|
||||
conTwo = getConnectedConnectionFor(AccountNum.Two);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (conOne != null) {
|
||||
conOne.disconnect();
|
||||
}
|
||||
if (conTwo != null) {
|
||||
conTwo.disconnect();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return new SmackIntegrationTestEnvironment(conOne, conTwo, testRunResult.testRunId, config);
|
||||
}
|
||||
|
||||
enum AccountNum {
|
||||
One,
|
||||
Two,
|
||||
}
|
||||
|
||||
private static final String USERNAME_PREFIX = "smack-inttest";
|
||||
|
||||
private XMPPTCPConnection getConnectedConnectionFor(AccountNum accountNum)
|
||||
throws SmackException, IOException, XMPPException, InterruptedException,
|
||||
KeyManagementException, NoSuchAlgorithmException {
|
||||
String middlefix;
|
||||
String accountUsername;
|
||||
String accountPassword;
|
||||
switch (accountNum) {
|
||||
case One:
|
||||
accountUsername = config.accountOneUsername;
|
||||
accountPassword = config.accountOnePassword;
|
||||
middlefix = "one";
|
||||
break;
|
||||
case Two:
|
||||
accountUsername = config.accountTwoUsername;
|
||||
accountPassword = config.accountTwoPassword;
|
||||
middlefix = "two";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (StringUtils.isNullOrEmpty(accountUsername)) {
|
||||
accountUsername = USERNAME_PREFIX + '-' + middlefix + '-' +testRunResult.testRunId;
|
||||
}
|
||||
if (StringUtils.isNullOrEmpty(accountPassword)) {
|
||||
accountPassword = StringUtils.randomString(16);
|
||||
}
|
||||
// @formatter:off
|
||||
Builder builder = XMPPTCPConnectionConfiguration.builder()
|
||||
.setServiceName(config.service)
|
||||
.setUsernameAndPassword(accountUsername, accountPassword)
|
||||
.setResource(middlefix + '-' + testRunResult.testRunId)
|
||||
.setSecurityMode(config.securityMode);
|
||||
// @formatter:on
|
||||
if (StringUtils.isNotEmpty(config.serviceTlsPin)) {
|
||||
SSLContext sc = JavaPinning.forPin(config.serviceTlsPin);
|
||||
builder.setCustomSSLContext(sc);
|
||||
}
|
||||
XMPPTCPConnection connection = new XMPPTCPConnection(builder.build());
|
||||
connection.connect();
|
||||
if (config.registerAccounts) {
|
||||
IntTestUtil.registerAccount(connection, accountUsername, accountPassword);
|
||||
|
||||
// TODO is this still required?
|
||||
// Some servers, e.g. Openfire, do not support a login right after the account was
|
||||
// created, so disconnect and re-connection the connection first.
|
||||
connection.disconnect();
|
||||
connection.connect();
|
||||
}
|
||||
|
||||
connection.login();
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
static XMPPTCPConnection getConnectedConnection(Configuration config)
|
||||
throws KeyManagementException, NoSuchAlgorithmException, InterruptedException,
|
||||
SmackException, IOException, XMPPException {
|
||||
XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();
|
||||
if (config.serviceTlsPin != null) {
|
||||
SSLContext sc = JavaPinning.forPin(config.serviceTlsPin);
|
||||
builder.setCustomSSLContext(sc);
|
||||
}
|
||||
builder.setSecurityMode(config.securityMode);
|
||||
builder.setServiceName(config.service);
|
||||
XMPPTCPConnection connection = new XMPPTCPConnection(builder.build());
|
||||
connection.connect();
|
||||
UsernameAndPassword uap = IntTestUtil.registerAccount(connection);
|
||||
connection.login(uap.username, uap.password);
|
||||
return connection;
|
||||
}
|
||||
|
||||
private static Exception throwFatalException(Throwable e) throws Error, NotConnectedException, NoResponseException,
|
||||
InterruptedException {
|
||||
if (e instanceof NotConnectedException) {
|
||||
throw (NotConnectedException) e;
|
||||
}
|
||||
if (e instanceof NoResponseException) {
|
||||
throw (NoResponseException) e;
|
||||
}
|
||||
if (e instanceof InterruptedException) {
|
||||
throw (InterruptedException) e;
|
||||
}
|
||||
if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException) e;
|
||||
}
|
||||
if (e instanceof Error) {
|
||||
throw (Error) e;
|
||||
}
|
||||
return (Exception) e;
|
||||
}
|
||||
|
||||
public static class TestRunResult {
|
||||
public final String testRunId = StringUtils.randomString(5);
|
||||
private final List<SuccessfulTest> successfulTests = Collections.synchronizedList(new LinkedList<SuccessfulTest>());
|
||||
private final List<FailedTest> failedIntegrationTests = Collections.synchronizedList(new LinkedList<FailedTest>());
|
||||
private final List<TestNotPossible> impossibleTestMethods = Collections.synchronizedList(new LinkedList<TestNotPossible>());
|
||||
private final Map<Class<? extends AbstractSmackIntTest>, String> impossibleTestClasses = new HashMap<>();
|
||||
private final AtomicInteger numberOfTests = new AtomicInteger();
|
||||
|
||||
private TestRunResult() {
|
||||
}
|
||||
|
||||
public String getTestRunId() {
|
||||
return testRunId;
|
||||
}
|
||||
|
||||
public int getNumberOfTests() {
|
||||
return numberOfTests.get();
|
||||
}
|
||||
|
||||
public List<SuccessfulTest> getSuccessfulTests() {
|
||||
return Collections.unmodifiableList(successfulTests);
|
||||
}
|
||||
|
||||
public List<FailedTest> getFailedTests() {
|
||||
return Collections.unmodifiableList(failedIntegrationTests);
|
||||
}
|
||||
|
||||
public List<TestNotPossible> getNotPossibleTests() {
|
||||
return Collections.unmodifiableList(impossibleTestMethods);
|
||||
}
|
||||
|
||||
public Map<Class<? extends AbstractSmackIntTest>, String> getImpossibleTestClasses() {
|
||||
return Collections.unmodifiableMap(impossibleTestClasses);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
public class SuccessfulTest extends TestResult {
|
||||
|
||||
public SuccessfulTest(Method testMethod, long startTime, long endTime, List<String> logMessages) {
|
||||
super(testMethod, startTime, endTime, logMessages);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
public class TestNotPossible extends TestResult {
|
||||
|
||||
public final TestNotPossibleException testNotPossibleException;
|
||||
|
||||
public TestNotPossible(Method testMethod, long startTime, long endTime, List<String> logMessages,
|
||||
TestNotPossibleException testNotPossibleException) {
|
||||
super(testMethod, startTime, endTime, logMessages);
|
||||
this.testNotPossibleException = testNotPossibleException;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
public class TestNotPossibleException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public TestNotPossibleException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class TestResult {
|
||||
|
||||
public final Method testMethod;
|
||||
public final long startTime;
|
||||
public final long endTime;
|
||||
public final long duration;
|
||||
public final List<String> logMessages;
|
||||
|
||||
public TestResult(Method testMethod, long startTime, long endTime, List<String> logMessages) {
|
||||
this.testMethod = testMethod;
|
||||
assert (endTime > startTime);
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.duration = endTime - startTime;
|
||||
this.logMessages = logMessages;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest.util;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
|
||||
public class ResultSyncPoint<R, E extends Exception> {
|
||||
|
||||
private R result;
|
||||
private E exception;
|
||||
|
||||
public R waitForResult(long timeout) throws E, InterruptedException, TimeoutException {
|
||||
synchronized(this) {
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
wait(timeout);
|
||||
}
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
throw new TimeoutException("Timeout expired");
|
||||
}
|
||||
|
||||
|
||||
public void signal(R result) {
|
||||
synchronized(this) {
|
||||
this.result = Objects.requireNonNull(result);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void signal(E exception) {
|
||||
synchronized(this) {
|
||||
this.exception = Objects.requireNonNull(exception);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.smack;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.igniterealtime.smack.inttest.AbstractSmackLowLevelIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.Configuration;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.jivesoftware.smack.sasl.SASLError;
|
||||
import org.jivesoftware.smack.sasl.SASLErrorException;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
|
||||
public class LoginIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||
|
||||
public LoginIntegrationTest(Configuration configuration, String testRunId) {
|
||||
super(configuration, testRunId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the server is returning the correct error when trying to login using an invalid
|
||||
* (i.e. non-existent) user.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* @throws XMPPException
|
||||
* @throws IOException
|
||||
* @throws SmackException
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws KeyManagementException
|
||||
*/
|
||||
@SmackIntegrationTest
|
||||
public void testInvalidLogin() throws SmackException, IOException, XMPPException,
|
||||
InterruptedException, KeyManagementException, NoSuchAlgorithmException {
|
||||
final String nonExistentUserString = StringUtils.randomString(24);
|
||||
XMPPTCPConnectionConfiguration conf = getConnectionConfiguration().setUsernameAndPassword(
|
||||
nonExistentUserString, "invalidPassword").build();
|
||||
|
||||
XMPPTCPConnection connection = new XMPPTCPConnection(conf);
|
||||
connection.connect();
|
||||
|
||||
try {
|
||||
connection.login();
|
||||
fail("Exception expected");
|
||||
}
|
||||
catch (SASLErrorException e) {
|
||||
assertEquals(SASLError.not_authorized, e.getSASLFailure().getSASLError());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.smack;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.igniterealtime.smack.inttest.AbstractSmackLowLevelIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.Configuration;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.TestNotPossibleException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
public class StreamManagementTest extends AbstractSmackLowLevelIntegrationTest {
|
||||
|
||||
public StreamManagementTest(Configuration configuration, String testRunId)
|
||||
throws Exception {
|
||||
super(configuration, testRunId);
|
||||
performCheck(new ConnectionCallback() {
|
||||
@Override
|
||||
public void connectionCallback(XMPPTCPConnection connection) throws Exception {
|
||||
if (!connection.isSmAvailable()) {
|
||||
throw new TestNotPossibleException("XEP-198: Stream Mangement not supported by service");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void before() {
|
||||
// TODO remove this once stream mangement is enabled per default
|
||||
XMPPTCPConnection.setUseStreamManagementDefault(true);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void after() {
|
||||
XMPPTCPConnection.setUseStreamManagementDefault(false);
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void testStreamManagement(XMPPTCPConnection conOne, XMPPTCPConnection conTwo) throws InterruptedException, KeyManagementException,
|
||||
NoSuchAlgorithmException, SmackException, IOException, XMPPException,
|
||||
TestNotPossibleException {
|
||||
send("Hi, what's up?", conOne, conTwo);
|
||||
|
||||
conOne.instantShutdown();
|
||||
|
||||
send("Hi, what's up? I've been just instantly shutdown", conOne, conTwo);
|
||||
|
||||
// Reconnect with xep198
|
||||
conOne.connect();
|
||||
|
||||
send("Hi, what's up? I've been just resumed", conOne, conTwo);
|
||||
// TODO check that all messages where received
|
||||
}
|
||||
|
||||
private static void send(String messageString, XMPPConnection from, XMPPConnection to)
|
||||
throws NotConnectedException, InterruptedException {
|
||||
Message message = new Message(to.getUser());
|
||||
message.setBody(messageString);
|
||||
from.sendStanza(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.filetransfer;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||
import org.igniterealtime.smack.inttest.util.ResultSyncPoint;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
|
||||
public class FileTransferIntegrationTest extends AbstractSmackIntegrationTest {
|
||||
|
||||
private static final int MAX_FT_DURATION = 360;
|
||||
|
||||
private final FileTransferManager ftManagerOne;
|
||||
private final FileTransferManager ftManagerTwo;
|
||||
|
||||
public FileTransferIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
super(environment);
|
||||
ftManagerOne = FileTransferManager.getInstanceFor(conOne);
|
||||
ftManagerTwo = FileTransferManager.getInstanceFor(conTwo);
|
||||
}
|
||||
|
||||
private static final byte[] dataToSend = StringUtils.randomString(1024 * 4 * 5).getBytes();
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void fileTransferTest() throws Exception {
|
||||
genericfileTransferTest();
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void ibbFileTransferTest() throws Exception {
|
||||
FileTransferNegotiator.IBB_ONLY = true;
|
||||
genericfileTransferTest();
|
||||
FileTransferNegotiator.IBB_ONLY = false;
|
||||
}
|
||||
|
||||
private void genericfileTransferTest() throws Exception {
|
||||
final ResultSyncPoint<String, Exception> resultSyncPoint = new ResultSyncPoint<>();
|
||||
final FileTransferListener receiveListener = new FileTransferListener() {
|
||||
@Override
|
||||
public void fileTransferRequest(FileTransferRequest request) {
|
||||
byte[] dataReceived = null;
|
||||
IncomingFileTransfer ift = request.accept();
|
||||
try {
|
||||
InputStream is = ift.recieveFile();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
int nRead;
|
||||
byte[] buf = new byte[1024];
|
||||
while ((nRead = is.read(buf, 0, buf.length)) != -1) {
|
||||
os.write(buf, 0, nRead);
|
||||
}
|
||||
os.flush();
|
||||
dataReceived = os.toByteArray();
|
||||
if (Arrays.equals(dataToSend, dataReceived)) {
|
||||
resultSyncPoint.signal("Received data matches send data. \\o/");
|
||||
}
|
||||
else {
|
||||
resultSyncPoint.signal(new Exception("Received data does not match"));
|
||||
}
|
||||
}
|
||||
catch (SmackException | IOException | XMPPErrorException | InterruptedException e) {
|
||||
resultSyncPoint.signal(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
ftManagerTwo.addFileTransferListener(receiveListener);
|
||||
|
||||
OutgoingFileTransfer oft = ftManagerOne.createOutgoingFileTransfer(conTwo.getUser());
|
||||
oft.sendStream(new ByteArrayInputStream(dataToSend), "hello.txt", dataToSend.length, "A greeting");
|
||||
int duration = 0;
|
||||
while (!oft.isDone()) {
|
||||
switch (oft.getStatus()) {
|
||||
case error:
|
||||
throw new Exception("Filetransfer error: " + oft.getError());
|
||||
default:
|
||||
LOGGER.info("Filetransfer status: " + oft.getStatus() + ". Progress: " + oft.getProgress());
|
||||
break;
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
if (++duration > MAX_FT_DURATION) {
|
||||
throw new Exception("Max duration reached");
|
||||
}
|
||||
}
|
||||
|
||||
resultSyncPoint.waitForResult(MAX_FT_DURATION * 1000);
|
||||
|
||||
ftManagerTwo.removeFileTransferListener(receiveListener);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.iqversion;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||
import org.igniterealtime.smack.inttest.TestNotPossibleException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smackx.iqversion.packet.Version;
|
||||
|
||||
public class VersionIntegrationTest extends AbstractSmackIntegrationTest {
|
||||
|
||||
public VersionIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void testVersion() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException {
|
||||
// TODO put into @BeforeClass method
|
||||
VersionManager.setAutoAppendSmackVersion(false);
|
||||
|
||||
VersionManager versionManagerOne = VersionManager.getInstanceFor(conOne);
|
||||
VersionManager versionManagerTwo = VersionManager.getInstanceFor(conTwo);
|
||||
final String versionName = "Smack Integration Test " + testRunId;
|
||||
versionManagerTwo.setVersion(versionName, "1.0");
|
||||
|
||||
assertTrue (versionManagerOne.isSupported(conTwo.getUser()));
|
||||
Version version = versionManagerOne.getVersion(conTwo.getUser());
|
||||
assertEquals(versionName, version.getName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.muc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||
import org.igniterealtime.smack.inttest.TestNotPossibleException;
|
||||
import org.igniterealtime.smack.inttest.util.ResultSyncPoint;
|
||||
import org.jivesoftware.smack.MessageListener;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.xdata.Form;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.DomainBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.jid.parts.Localpart;
|
||||
import org.jxmpp.jid.parts.Resourcepart;
|
||||
|
||||
public class MultiUserChatIntegrationTest extends AbstractSmackIntegrationTest {
|
||||
|
||||
private final String randomString = StringUtils.randomString(6);
|
||||
|
||||
private final MultiUserChatManager mucManagerOne;
|
||||
private final MultiUserChatManager mucManagerTwo;
|
||||
private final DomainBareJid mucService;
|
||||
|
||||
public MultiUserChatIntegrationTest(SmackIntegrationTestEnvironment environment)
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException,
|
||||
InterruptedException, TestNotPossibleException {
|
||||
super(environment);
|
||||
mucManagerOne = MultiUserChatManager.getInstanceFor(conOne);
|
||||
mucManagerTwo = MultiUserChatManager.getInstanceFor(conTwo);
|
||||
|
||||
List<DomainBareJid> services = mucManagerOne.getServiceNames();
|
||||
if (services.isEmpty()) {
|
||||
throw new TestNotPossibleException("No MUC (XEP-45) service found");
|
||||
}
|
||||
else {
|
||||
mucService = services.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void mucTest() throws TimeoutException, Exception {
|
||||
BareJid mucAddress = JidCreate.bareFrom(Localpart.from("smack-inttest-" + randomString), mucService.getDomain());
|
||||
|
||||
MultiUserChat mucAsSeenByOne = mucManagerOne.getMultiUserChat(mucAddress);
|
||||
MultiUserChat mucAsSeenByTwo = mucManagerTwo.getMultiUserChat(mucAddress);
|
||||
|
||||
final String mucMessage = "Smack Integration Test MUC Test Message " + randomString;
|
||||
final ResultSyncPoint<String, Exception> resultSyncPoint = new ResultSyncPoint<>();
|
||||
|
||||
mucAsSeenByTwo.addMessageListener(new MessageListener() {
|
||||
@Override
|
||||
public void processMessage(Message message) {
|
||||
String body = message.getBody();
|
||||
if (mucMessage.equals(body)) {
|
||||
resultSyncPoint.signal(body);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
boolean newlyCreated = mucAsSeenByOne.createOrJoin(Resourcepart.from("one-" + randomString));
|
||||
if (newlyCreated) {
|
||||
mucAsSeenByOne.sendConfigurationForm(new Form(DataForm.Type.submit));
|
||||
}
|
||||
mucAsSeenByTwo.join(Resourcepart.from("two-" + randomString));
|
||||
|
||||
mucAsSeenByOne.sendMessage(mucMessage);
|
||||
resultSyncPoint.waitForResult(defaultTimeout);
|
||||
|
||||
mucAsSeenByOne.leave();
|
||||
mucAsSeenByTwo.leave();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.assertTrue;
|
||||
|
||||
import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
|
||||
public class PingIntegrationTest extends AbstractSmackIntegrationTest {
|
||||
|
||||
public PingIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void pingServer() throws NotConnectedException, InterruptedException {
|
||||
PingManager pingManager = PingManager.getInstanceFor(connection);
|
||||
assertTrue(pingManager.pingMyServer());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
|
||||
public class DummySmackIntegrationTestFramework extends SmackIntegrationTestFramework {
|
||||
|
||||
public DummySmackIntegrationTestFramework(Configuration configuration) {
|
||||
super(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SmackIntegrationTestEnvironment prepareEnvironment() {
|
||||
return new SmackIntegrationTestEnvironment(null, null, testRunResult.getTestRunId(), config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disconnectAndMaybeDelete(XMPPTCPConnection connection) {
|
||||
// This method is a no-op in DummySmackIntegrationTestFramework
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest;
|
||||
|
||||
import org.jxmpp.jid.JidTestUtil;
|
||||
|
||||
public class SmackIntegrationTestUnitTestUtil {
|
||||
|
||||
public static DummySmackIntegrationTestFramework getFrameworkForUnitTest(Class<? extends AbstractSmackIntTest> unitTest) {
|
||||
// @formatter:off
|
||||
Configuration configuration = Configuration.builder()
|
||||
.setService(JidTestUtil.DOMAIN_BARE_JID_1)
|
||||
.setUsernamesAndPassword("dummy1", "dummy1pass", "dummy2", "dummy2pass")
|
||||
.addEnabledTest(unitTest).build();
|
||||
// @formatter:on
|
||||
return new DummySmackIntegrationTestFramework(configuration);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest.unittest;
|
||||
|
||||
import static org.igniterealtime.smack.inttest.SmackIntegrationTestUnitTestUtil.getFrameworkForUnitTest;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.DummySmackIntegrationTestFramework;
|
||||
import org.igniterealtime.smack.inttest.FailedTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestFramework.TestRunResult;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.packet.XMPPError;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
public class SmackIntegrationTestFrameworkUnitTest {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void throwsRuntimeExceptionsTest() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
|
||||
IOException, XMPPException, InterruptedException {
|
||||
expectedException.expect(RuntimeException.class);
|
||||
expectedException.expectMessage(ThrowsRuntimeExceptionDummyTest.RUNTIME_EXCEPTION_MESSAGE);
|
||||
DummySmackIntegrationTestFramework sinttest = getFrameworkForUnitTest(ThrowsRuntimeExceptionDummyTest.class);
|
||||
sinttest.run();
|
||||
}
|
||||
|
||||
public static class ThrowsRuntimeExceptionDummyTest extends AbstractSmackIntegrationTest {
|
||||
|
||||
public ThrowsRuntimeExceptionDummyTest(SmackIntegrationTestEnvironment environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
public static final String RUNTIME_EXCEPTION_MESSAGE = "Dummy RuntimeException";
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void throwRuntimeExceptionTest() {
|
||||
throw new RuntimeException(RUNTIME_EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logsNonFatalExceptionTest() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
|
||||
IOException, XMPPException, InterruptedException {
|
||||
DummySmackIntegrationTestFramework sinttest = getFrameworkForUnitTest(ThrowsNonFatalExceptionDummyTest.class);
|
||||
TestRunResult testRunResult = sinttest.run();
|
||||
List<FailedTest> failedTests = testRunResult.getFailedTests();
|
||||
assertEquals(1, failedTests.size());
|
||||
FailedTest failedTest = failedTests.get(0);
|
||||
assertTrue(failedTest.failureReason instanceof XMPPErrorException);
|
||||
XMPPErrorException ex = (XMPPErrorException) failedTest.failureReason;
|
||||
assertEquals(XMPPError.Condition.bad_request, ex.getXMPPError().getCondition());
|
||||
assertEquals(ThrowsNonFatalExceptionDummyTest.DESCRIPTIVE_TEXT, ex.getXMPPError().getDescriptiveText());
|
||||
}
|
||||
|
||||
public static class ThrowsNonFatalExceptionDummyTest extends AbstractSmackIntegrationTest {
|
||||
|
||||
public static final String DESCRIPTIVE_TEXT = "I'm not fatal";
|
||||
|
||||
public ThrowsNonFatalExceptionDummyTest(SmackIntegrationTestEnvironment environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void throwRuntimeExceptionTest() throws XMPPErrorException {
|
||||
throw new XMPPException.XMPPErrorException(
|
||||
XMPPError.from(XMPPError.Condition.bad_request, DESCRIPTIVE_TEXT));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 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.igniterealtime.smack.inttest.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jivesoftware.smack.util.Async;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ResultSyncPointTest {
|
||||
|
||||
@Test
|
||||
public void testResultSyncPoint() throws InterruptedException, TimeoutException, Exception {
|
||||
final String result = "Hip Hip Hurrary!!111!";
|
||||
final CyclicBarrier barrier = new CyclicBarrier(2);
|
||||
final ResultSyncPoint<String, Exception> rsp = new ResultSyncPoint<>();
|
||||
Async.go(new Async.ThrowingRunnable() {
|
||||
@Override
|
||||
public void runOrThrow() throws InterruptedException, BrokenBarrierException {
|
||||
barrier.await();
|
||||
rsp.signal(result);
|
||||
}
|
||||
});
|
||||
barrier.await();
|
||||
String receivedResult = rsp.waitForResult(60 * 1000);
|
||||
assertEquals(result, receivedResult);
|
||||
}
|
||||
|
||||
@Test(expected=TestException.class)
|
||||
public void exceptionTestResultSyncPoint() throws InterruptedException, TimeoutException, Exception {
|
||||
final CyclicBarrier barrier = new CyclicBarrier(2);
|
||||
final ResultSyncPoint<String, TestException> rsp = new ResultSyncPoint<>();
|
||||
Async.go(new Async.ThrowingRunnable() {
|
||||
@Override
|
||||
public void runOrThrow() throws InterruptedException, BrokenBarrierException {
|
||||
barrier.await();
|
||||
rsp.signal(new TestException());
|
||||
}
|
||||
});
|
||||
barrier.await();
|
||||
rsp.waitForResult(60 * 1000);
|
||||
}
|
||||
|
||||
private static class TestException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue