1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2025-09-09 17:19:39 +02:00

SmackReactor/NIO, Java8/Android19, Pretty print XML, FSM connections

This commit adds
- SmackReactor / NIO
- a framework for finite state machine connections
- support for Java 8
- pretty printed XML debug output

It also
- reworks the integration test framework
- raises the minimum Android API level to 19
- introduces XmppNioTcpConnection

Furthermore fixes SMACK-801 (at least partly). Java 8 language
features are available, but not all runtime library methods. For that
we would need to raise the Android API level to 24 or higher.
This commit is contained in:
Florian Schmaus 2019-02-04 08:59:39 +01:00
parent dba12919d0
commit e98d42790a
144 changed files with 8692 additions and 1455 deletions

View file

@ -0,0 +1,266 @@
/**
*
* Copyright 2018-2019 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;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.StanzaExtensionFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.util.Async;
import org.jivesoftware.smack.util.MultiMap;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.jiveproperties.JivePropertiesManager;
import org.jivesoftware.smackx.jiveproperties.packet.JivePropertiesExtension;
import org.igniterealtime.smack.XmppConnectionStressTest.StressTestFailedException.ErrorsWhileSendingOrReceivingException;
import org.igniterealtime.smack.XmppConnectionStressTest.StressTestFailedException.NotAllMessagesReceivedException;
import org.jxmpp.jid.EntityFullJid;
public class XmppConnectionStressTest {
private static final String MESSAGE_NUMBER_PROPERTY = "message-number";
public static class Configuration {
public final long seed;
public final int messagesPerConnection;
public final int maxPayloadChunkSize;
public final int maxPayloadChunks;
public final boolean intermixMessages;
public Configuration(long seed, int messagesPerConnection, int maxPayloadChunkSize, int maxPayloadChunks,
boolean intermixMessages) {
this.seed = seed;
this.messagesPerConnection = messagesPerConnection;
this.maxPayloadChunkSize = maxPayloadChunkSize;
this.maxPayloadChunks = maxPayloadChunks;
this.intermixMessages = intermixMessages;
}
}
private final Configuration configuration;
public XmppConnectionStressTest(Configuration configuration) {
this.configuration = configuration;
}
private volatile long waitStart;
public void run(List<? extends XMPPConnection> connections, final long replyTimeoutMillis)
throws InterruptedException, NotAllMessagesReceivedException, ErrorsWhileSendingOrReceivingException {
final MultiMap<XMPPConnection, Message> messages = new MultiMap<>();
final Random random = new Random(configuration.seed);
final Map<XMPPConnection, Exception> sendExceptions = new ConcurrentHashMap<>();
final Map<XMPPConnection, Exception> receiveExceptions = new ConcurrentHashMap<>();
waitStart = -1;
for (XMPPConnection fromConnection : connections) {
MultiMap<XMPPConnection, Message> toConnectionMessages = new MultiMap<>();
for (XMPPConnection toConnection : connections) {
for (int i = 0; i < configuration.messagesPerConnection; i++) {
Message message = new Message();
message.setTo(toConnection.getUser());
int payloadChunkCount = random.nextInt(configuration.maxPayloadChunks) + 1;
for (int c = 0; c < payloadChunkCount; c++) {
int payloadChunkSize = random.nextInt(configuration.maxPayloadChunkSize) + 1;
String payloadCunk = StringUtils.randomString(payloadChunkSize, random);
JivePropertiesManager.addProperty(message, "payload-chunk-" + c, payloadCunk);
}
JivePropertiesManager.addProperty(message, MESSAGE_NUMBER_PROPERTY, i);
toConnectionMessages.put(toConnection, message);
}
}
if (configuration.intermixMessages) {
while (!toConnectionMessages.isEmpty()) {
int next = random.nextInt(connections.size());
Message message = null;
while (message == null) {
XMPPConnection toConnection = connections.get(next);
message = toConnectionMessages.getFirst(toConnection);
next = (next + 1) % connections.size();
}
messages.put(fromConnection, message);
}
} else {
for (XMPPConnection toConnection : connections) {
for (Message message : toConnectionMessages.getAll(toConnection)) {
messages.put(fromConnection, message);
}
}
}
}
Semaphore receivedSemaphore = new Semaphore(-connections.size() + 1);
Map<XMPPConnection, Map<EntityFullJid, boolean[]>> receiveMarkers = new ConcurrentHashMap<>(connections.size());
for (XMPPConnection connection : connections) {
connection.addSyncStanzaListener(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) {
waitStart = System.currentTimeMillis();
EntityFullJid from = stanza.getFrom().asEntityFullJidOrThrow();
Message message = (Message) stanza;
JivePropertiesExtension extension = JivePropertiesExtension.from(message);
Integer messageNumber = (Integer) extension.getProperty(MESSAGE_NUMBER_PROPERTY);
Map<EntityFullJid, boolean[]> myReceiveMarkers = receiveMarkers.get(connection);
if (myReceiveMarkers == null) {
myReceiveMarkers = new HashMap<>(connections.size());
receiveMarkers.put(connection, myReceiveMarkers);
}
boolean[] fromMarkers = myReceiveMarkers.get(from);
if (fromMarkers == null) {
fromMarkers = new boolean[configuration.messagesPerConnection];
myReceiveMarkers.put(from, fromMarkers);
}
// Sanity check: All markers before must be true, all markers including the messageNumber marker must be false.
for (int i = 0; i < fromMarkers.length; i++) {
if ((i < messageNumber && !fromMarkers[i])
|| (i >= messageNumber && fromMarkers[i])) {
// TODO: Better exception.
Exception exception = new Exception("out of order");
receiveExceptions.put(connection, exception);
// TODO: Current Smack design does not guarantee that the listener won't be invoked again.
// This is because the decission to invoke a sync listeners is done at a different place
// then invoking the listener.
connection.removeSyncStanzaListener(this);
receivedSemaphore.release();
return;
}
}
fromMarkers[messageNumber] = true;
if (myReceiveMarkers.size() != connections.size()) {
return;
}
for (boolean[] markers : myReceiveMarkers.values()) {
for (boolean b : markers) {
if (!b) {
return;
}
}
}
// All markers set to true, this means we received all messages.
receivedSemaphore.release();
}
}, new AndFilter(MessageTypeFilter.NORMAL,
new StanzaExtensionFilter(JivePropertiesExtension.ELEMENT, JivePropertiesExtension.NAMESPACE)));
}
Semaphore sendSemaphore = new Semaphore(-connections.size() + 1);
for (XMPPConnection connection : connections) {
Async.go(() -> {
List<Message> messagesToSend;
synchronized (messages) {
messagesToSend = messages.getAll(connection);
}
try {
for (Message messageToSend : messagesToSend) {
connection.sendStanza(messageToSend);
}
} catch (NotConnectedException | InterruptedException e) {
sendExceptions.put(connection, e);
} finally {
sendSemaphore.release();
}
});
}
sendSemaphore.acquire();
if (waitStart < 0) {
waitStart = System.currentTimeMillis();
}
boolean acquired;
do {
long acquireWait = waitStart + replyTimeoutMillis - System.currentTimeMillis();
acquired = receivedSemaphore.tryAcquire(acquireWait, TimeUnit.MILLISECONDS);
} while (!acquired && System.currentTimeMillis() < waitStart + replyTimeoutMillis);
if (!acquired && receiveExceptions.isEmpty() && sendExceptions.isEmpty()) {
throw new StressTestFailedException.NotAllMessagesReceivedException(receiveMarkers);
}
if (!receiveExceptions.isEmpty() || !sendExceptions.isEmpty()) {
throw new StressTestFailedException.ErrorsWhileSendingOrReceivingException(sendExceptions,
receiveExceptions);
}
// Test successful.
}
public abstract static class StressTestFailedException extends Exception {
private static final long serialVersionUID = 1L;
protected StressTestFailedException(String message) {
super(message);
}
public static final class NotAllMessagesReceivedException extends StressTestFailedException {
private static final long serialVersionUID = 1L;
public final Map<XMPPConnection, Map<EntityFullJid, boolean[]>> receiveMarkers;
private NotAllMessagesReceivedException(Map<XMPPConnection, Map<EntityFullJid, boolean[]>> receiveMarkers) {
super("Did not receive all messages");
this.receiveMarkers = receiveMarkers;
}
}
public static final class ErrorsWhileSendingOrReceivingException extends StressTestFailedException {
private static final long serialVersionUID = 1L;
public final Map<XMPPConnection, Exception> sendExceptions;
public final Map<XMPPConnection, Exception> receiveExceptions;
private ErrorsWhileSendingOrReceivingException(Map<XMPPConnection, Exception> sendExceptions,
Map<XMPPConnection, Exception> receiveExceptions) {
super("Exceptions while sending and/or receiving");
this.sendExceptions = sendExceptions;
this.receiveExceptions = receiveExceptions;
}
}
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2016 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -45,10 +45,10 @@ public abstract class AbstractSmackIntTest {
protected final Configuration sinttestConfiguration;
protected AbstractSmackIntTest(String testRunId, Configuration configuration) {
this.testRunId = testRunId;
this.sinttestConfiguration = configuration;
this.timeout = configuration.replyTimeout;
protected AbstractSmackIntTest(SmackIntegrationTestEnvironment<?> environment) {
this.testRunId = environment.testRunId;
this.sinttestConfiguration = environment.configuration;
this.timeout = environment.configuration.replyTimeout;
}
protected void performActionAndWaitUntilStanzaReceived(Runnable action, XMPPConnection connection, StanzaFilter filter)

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2018 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,10 @@
*/
package org.igniterealtime.smack.inttest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jivesoftware.smack.XMPPConnection;
public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest {
@ -40,10 +44,18 @@ public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest
*/
protected final XMPPConnection connection;
public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment environment) {
super(environment.testRunId, environment.configuration);
protected final List<XMPPConnection> connections;
public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
this.connection = this.conOne = environment.conOne;
this.conTwo = environment.conTwo;
this.conThree = environment.conThree;
final List<XMPPConnection> connectionsLocal = new ArrayList<>(3);
connectionsLocal.add(conOne);
connectionsLocal.add(conTwo);
connectionsLocal.add(conThree);
this.connections = Collections.unmodifiableList(connectionsLocal);
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2017 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,17 +16,22 @@
*/
package org.igniterealtime.smack.inttest;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smack.AbstractXMPPConnection;
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.jxmpp.jid.DomainBareJid;
public abstract class AbstractSmackLowLevelIntegrationTest extends AbstractSmackIntTest {
private final SmackIntegrationTestEnvironment environment;
private final SmackIntegrationTestEnvironment<?> environment;
/**
* The configuration
@ -35,33 +40,36 @@ public abstract class AbstractSmackLowLevelIntegrationTest extends AbstractSmack
protected final DomainBareJid service;
public AbstractSmackLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment) {
super(environment.testRunId, environment.configuration);
protected AbstractSmackLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
this.environment = environment;
this.configuration = environment.configuration;
this.service = configuration.service;
}
public final XMPPTCPConnectionConfiguration.Builder getConnectionConfiguration() throws KeyManagementException, NoSuchAlgorithmException {
XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();
if (configuration.tlsContext != null) {
builder.setCustomSSLContext(configuration.tlsContext);
}
builder.setSecurityMode(configuration.securityMode);
builder.setXmppDomain(service);
return builder;
protected AbstractXMPPConnection getConnectedConnection() throws InterruptedException, XMPPException, SmackException, IOException {
AbstractXMPPConnection connection = getUnconnectedConnection();
connection.connect().login();
return connection;
}
protected void performCheck(ConnectionCallback callback) throws Exception {
XMPPTCPConnection connection = SmackIntegrationTestFramework.getConnectedConnection(environment, -1);
try {
callback.connectionCallback(connection);
} finally {
IntTestUtil.disconnectAndMaybeDelete(connection, configuration);
}
protected AbstractXMPPConnection getUnconnectedConnection()
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
return environment.connectionManager.constructConnection();
}
public interface ConnectionCallback {
void connectionCallback(XMPPTCPConnection connection) throws Exception;
protected List<AbstractXMPPConnection> getUnconnectedConnections(int count)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
List<AbstractXMPPConnection> connections = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
AbstractXMPPConnection connection = getUnconnectedConnection();
connections.add(connection);
}
return connections;
}
protected void recycle(AbstractXMPPConnection connection) {
environment.connectionManager.recycle(connection);
}
}

View file

@ -0,0 +1,63 @@
/**
*
* Copyright 2018-2019 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.ArrayList;
import java.util.List;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
public abstract class AbstractSmackSpecificLowLevelIntegrationTest<C extends AbstractXMPPConnection>
extends AbstractSmackLowLevelIntegrationTest {
private final SmackIntegrationTestEnvironment<?> environment;
protected final Class<C> connectionClass;
private final XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor;
public AbstractSmackSpecificLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment,
Class<C> connectionClass) {
super(environment);
this.environment = environment;
this.connectionClass = connectionClass;
connectionDescriptor = environment.connectionManager.getConnectionDescriptorFor(connectionClass);
}
public Class<C> getConnectionClass() {
return connectionClass;
}
protected C getSpecificUnconnectedConnection() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
return environment.connectionManager.constructConnection(connectionDescriptor);
}
protected List<C> getSpecificUnconnectedConnections(int count)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
List<C> connections = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
C connection = getSpecificUnconnectedConnection();
connections.add(connection);
}
return connections;
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2017 Florian Schmaus
* Copyright 2015-2018 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -32,14 +32,18 @@ import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.debugger.ConsoleDebugger;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.debugger.EnhancedDebugger;
import eu.geekplace.javapinning.java7.Java7Pinning;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
// TODO: Rename to SinttestConfiguration.
public final class Configuration {
private static final Logger LOGGER = Logger.getLogger(Configuration.class.getName());
@ -92,6 +96,8 @@ public final class Configuration {
public final Set<String> testPackages;
public final ConnectionConfigurationBuilderApplier configurationApplier;
private Configuration(DomainBareJid service, String serviceTlsPin, SecurityMode securityMode, int replyTimeout,
Debugger debugger, String accountOneUsername, String accountOnePassword, String accountTwoUsername,
String accountTwoPassword, String accountThreeUsername, String accountThreePassword, Set<String> enabledTests, Set<String> disabledTests,
@ -126,6 +132,13 @@ public final class Configuration {
this.adminAccountUsername = adminAccountUsername;
this.adminAccountPassword = adminAccountPassword;
boolean accountOnePasswordSet = StringUtils.isNotEmpty(accountOnePassword);
if (accountOnePasswordSet != StringUtils.isNotEmpty(accountTwoPassword) ||
accountOnePasswordSet != StringUtils.isNotEmpty(accountThreePassword)) {
// Ensure the invariant that either all main accounts have a password set, or none.
throw new IllegalArgumentException();
}
this.accountOneUsername = accountOneUsername;
this.accountOnePassword = accountOnePassword;
this.accountTwoUsername = accountTwoUsername;
@ -135,6 +148,26 @@ public final class Configuration {
this.enabledTests = enabledTests;
this.disabledTests = disabledTests;
this.testPackages = testPackages;
this.configurationApplier = (builder) -> {
if (tlsContext != null) {
builder.setCustomSSLContext(tlsContext);
}
builder.setSecurityMode(securityMode);
builder.setXmppDomain(service);
switch (debugger) {
case enhanced:
builder.setDebuggerFactory(EnhancedDebugger.Factory.INSTANCE);
break;
case console:
builder.setDebuggerFactory(ConsoleDebugger.Factory.INSTANCE);
break;
case none:
// Nothing to do :).
break;
}
};
}
public boolean isAccountRegistrationPossible() {

View file

@ -0,0 +1,23 @@
/**
*
* Copyright 2018 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.ConnectionConfiguration;
public interface ConnectionConfigurationBuilderApplier {
void applyConfigurationTo(ConnectionConfiguration.Builder<?, ?> connectionConfigurationBuilder);
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,15 +16,14 @@
*/
package org.igniterealtime.smack.inttest;
import java.lang.reflect.Method;
import java.util.List;
public class FailedTest extends TestResult {
public final Throwable failureReason;
public FailedTest(Method testMethod, long startTime, long endTime, List<String> logMessages, Throwable failureReason) {
super(testMethod, startTime, endTime, logMessages);
public FailedTest(SmackIntegrationTestFramework.ConcreteTest concreteTest, long startTime, long endTime, List<String> logMessages, Throwable failureReason) {
super(concreteTest, startTime, endTime, logMessages);
this.failureReason = failureReason;
}
}

View file

@ -1,241 +0,0 @@
/**
*
* Copyright 2015-2017 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.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.admin.ServiceAdministrationManager;
import org.jivesoftware.smackx.iqregister.AccountManager;
import org.igniterealtime.smack.inttest.Configuration.AccountRegistration;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Localpart;
import org.jxmpp.stringprep.XmppStringprepException;
public class IntTestUtil {
private static final Logger LOGGER = Logger.getLogger(IntTestUtil.class.getName());
public static UsernameAndPassword registerAccount(XMPPTCPConnection connection, SmackIntegrationTestEnvironment environment, int connectionId) throws InterruptedException, XMPPException, SmackException, IOException {
String username = "sinttest-" + environment.testRunId + "-" + connectionId;
return registerAccount(connection, username, StringUtils.insecureRandomString(12), environment.configuration);
}
public static UsernameAndPassword registerAccount(XMPPTCPConnection connection, String accountUsername, String accountPassword,
Configuration config) throws InterruptedException, XMPPException, SmackException, IOException {
switch (config.accountRegistration) {
case inBandRegistration:
return registerAccountViaIbr(connection, accountUsername, accountPassword);
case serviceAdministration:
return registerAccountViaAdmin(connection, accountUsername, accountPassword, config.adminAccountUsername, config.adminAccountPassword);
default:
throw new AssertionError();
}
}
// public static UsernameAndPassword registerAccountViaAdmin(XMPPTCPConnection connection) throws XmppStringprepException, NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
// return registerAccountViaAdmin(connection, StringUtils.insecureRandomString(12),
// StringUtils.insecureRandomString(12));
// }
public static UsernameAndPassword registerAccountViaAdmin(XMPPTCPConnection connection, String username,
String password, String adminAccountUsername, String adminAccountPassword) throws InterruptedException, XMPPException, SmackException, IOException {
connection.login(adminAccountUsername, adminAccountPassword);
ServiceAdministrationManager adminManager = ServiceAdministrationManager.getInstanceFor(connection);
EntityBareJid userJid = JidCreate.entityBareFrom(Localpart.from(username), connection.getXMPPServiceDomain());
adminManager.addUser(userJid, password);
connection.disconnect();
connection.connect();
return new UsernameAndPassword(username, password);
}
public static UsernameAndPassword registerAccountViaIbr(XMPPConnection connection)
throws NoResponseException, XMPPErrorException, NotConnectedException,
InterruptedException {
return registerAccountViaIbr(connection, StringUtils.insecureRandomString(12),
StringUtils.insecureRandomString(12));
}
public static UsernameAndPassword registerAccountViaIbr(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");
Localpart usernameLocalpart;
try {
usernameLocalpart = Localpart.from(username);
}
catch (XmppStringprepException e) {
throw new IllegalArgumentException("Invalid username: " + username, e);
}
accountManager.createAccount(usernameLocalpart, password, additionalAttributes);
return new UsernameAndPassword(username, password);
}
public static final class UsernameAndPassword {
public final String username;
public final String password;
private UsernameAndPassword(String username, String password) {
this.username = username;
this.password = password;
}
}
public static void disconnectAndMaybeDelete(XMPPTCPConnection connection, Configuration config) throws InterruptedException {
try {
if (!config.isAccountRegistrationPossible()) {
return;
}
Configuration.AccountRegistration accountDeletionMethod = config.accountRegistration;
AccountManager accountManager = AccountManager.getInstance(connection);
try {
if (accountManager.isSupported()) {
accountDeletionMethod = AccountRegistration.inBandRegistration;
}
}
catch (NoResponseException | XMPPErrorException | NotConnectedException e) {
LOGGER.log(Level.WARNING, "Could not test if XEP-0077 account deletion is possible", e);
}
switch (accountDeletionMethod) {
case inBandRegistration:
deleteViaIbr(connection);
break;
case serviceAdministration:
deleteViaServiceAdministration(connection, config);
break;
default:
throw new AssertionError();
}
}
finally {
connection.disconnect();
}
}
public static void deleteViaServiceAdministration(XMPPTCPConnection connection, Configuration config) {
EntityBareJid accountToDelete = connection.getUser().asEntityBareJid();
final int maxAttempts = 3;
int attempts;
for (attempts = 0; attempts < maxAttempts; attempts++) {
connection.disconnect();
try {
connection.connect().login(config.adminAccountUsername, config.adminAccountPassword);
}
catch (XMPPException | SmackException | IOException | InterruptedException e) {
LOGGER.log(Level.WARNING, "Exception deleting account for " + connection, e);
continue;
}
ServiceAdministrationManager adminManager = ServiceAdministrationManager.getInstanceFor(connection);
try {
adminManager.deleteUser(accountToDelete);
break;
}
catch (NoResponseException | XMPPErrorException | NotConnectedException | InterruptedException e) {
LOGGER.log(Level.WARNING, "Exception deleting account for " + connection, e);
continue;
}
}
if (attempts > maxAttempts) {
LOGGER.log(Level.SEVERE, "Could not delete account for connection: " + connection);
}
}
public static void deleteViaIbr(XMPPTCPConnection connection)
throws InterruptedException {
// If the connection is disconnected, then re-reconnect and login. This could happen when
// (low-level) integration tests disconnect the connection, e.g. to test disconnection
// mechanisms
if (!connection.isConnected()) {
try {
connection.connect().login();
}
catch (XMPPException | SmackException | IOException e) {
LOGGER.log(Level.WARNING, "Exception reconnection account for deletion", e);
}
}
final int maxAttempts = 3;
AccountManager am = AccountManager.getInstance(connection);
int attempts;
for (attempts = 0; attempts < maxAttempts; attempts++) {
try {
am.deleteAccount();
}
catch (XMPPErrorException | NoResponseException e) {
LOGGER.log(Level.WARNING, "Exception deleting account for " + connection, e);
continue;
}
catch (NotConnectedException e) {
LOGGER.log(Level.WARNING, "Exception deleting account for " + connection, e);
try {
connection.connect().login();
}
catch (XMPPException | SmackException | IOException e2) {
LOGGER.log(Level.WARNING, "Exception while trying to re-connect " + connection, e);
}
continue;
}
LOGGER.info("Successfully deleted account of " + connection);
break;
}
if (attempts > maxAttempts) {
LOGGER.log(Level.SEVERE, "Could not delete account for connection: " + connection);
}
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +16,19 @@
*/
package org.igniterealtime.smack.inttest;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SmackIntegrationTest {
boolean onlyDefaultConnectionType() default false;
int connectionCount() default -1;
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,26 +16,25 @@
*/
package org.igniterealtime.smack.inttest;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.AbstractXMPPConnection;
public class SmackIntegrationTestEnvironment {
public class SmackIntegrationTestEnvironment<C extends AbstractXMPPConnection> {
public final XMPPTCPConnection conOne;
public final XMPPTCPConnection conTwo;
public final XMPPTCPConnection conThree;
public final C conOne, conTwo, conThree;
public final String testRunId;
public final Configuration configuration;
SmackIntegrationTestEnvironment(XMPPTCPConnection conOne, XMPPTCPConnection conTwo, XMPPTCPConnection conThree, String testRunId,
Configuration configuration) {
public final XmppConnectionManager<C> connectionManager;
SmackIntegrationTestEnvironment(C conOne, C conTwo, C conThree, String testRunId,
Configuration configuration, XmppConnectionManager<C> connectionManager) {
this.conOne = conOne;
this.conTwo = conTwo;
this.conThree = conThree;
this.testRunId = testRunId;
this.configuration = configuration;
this.connectionManager = connectionManager;
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2017 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -27,8 +27,12 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -43,21 +47,20 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.AbstractXMPPConnection;
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.XMPPException;
import org.jivesoftware.smack.debugger.ConsoleDebugger;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.debugger.EnhancedDebugger;
import org.jivesoftware.smackx.debugger.EnhancedDebuggerWindow;
import org.jivesoftware.smackx.iqregister.AccountManager;
import org.igniterealtime.smack.inttest.IntTestUtil.UsernameAndPassword;
import org.igniterealtime.smack.inttest.Configuration.AccountRegistration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.reflections.Reflections;
@ -66,51 +69,60 @@ import org.reflections.scanners.MethodParameterScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
public class SmackIntegrationTestFramework {
public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
private static final Logger LOGGER = Logger.getLogger(SmackIntegrationTestFramework.class.getName());
private static final char CLASS_METHOD_SEP = '#';
public static boolean SINTTEST_UNIT_TEST = false;
private final Class<DC> defaultConnectionClass;
protected final Configuration config;
protected TestRunResult testRunResult;
private SmackIntegrationTestEnvironment environment;
private SmackIntegrationTestEnvironment<DC> environment;
protected XmppConnectionManager<DC> connectionManager;
public enum TestType {
Normal,
LowLevel,
SpecificLowLevel,
}
public static void main(String[] args) throws IOException, KeyManagementException,
NoSuchAlgorithmException, SmackException, XMPPException, InterruptedException {
NoSuchAlgorithmException, SmackException, XMPPException, InterruptedException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Configuration config = Configuration.newConfiguration(args);
SmackIntegrationTestFramework sinttest = new SmackIntegrationTestFramework(config);
SmackIntegrationTestFramework<XMPPTCPConnection> sinttest = new SmackIntegrationTestFramework<>(config, XMPPTCPConnection.class);
TestRunResult testRunResult = sinttest.run();
for (Entry<Class<? extends AbstractSmackIntTest>, String> entry : testRunResult.impossibleTestClasses.entrySet()) {
for (Entry<Class<? extends AbstractSmackIntTest>, Throwable> entry : testRunResult.impossibleTestClasses.entrySet()) {
LOGGER.info("Could not run " + entry.getKey().getName() + " because: "
+ entry.getValue());
+ entry.getValue().getLocalizedMessage());
}
for (TestNotPossible testNotPossible : testRunResult.impossibleTestMethods) {
LOGGER.info("Could not run " + testNotPossible.testMethod.getName() + " because: "
for (TestNotPossible testNotPossible : testRunResult.impossibleIntegrationTests) {
LOGGER.info("Could not run " + testNotPossible.concreteTest + " because: "
+ testNotPossible.testNotPossibleException.getMessage());
}
final int successfulTests = testRunResult.successfulTests.size();
for (SuccessfulTest successfulTest : testRunResult.successfulIntegrationTests) {
LOGGER.info(successfulTest.concreteTest + "");
}
final int successfulTests = testRunResult.successfulIntegrationTests.size();
final int failedTests = testRunResult.failedIntegrationTests.size();
final int totalIntegrationTests = successfulTests + failedTests;
final int availableTests = testRunResult.getNumberOfAvailableTests();
final int possibleTests = testRunResult.getNumberOfPossibleTests();
LOGGER.info("SmackIntegrationTestFramework[" + testRunResult.testRunId + ']' + ": Finished ["
+ successfulTests + '/' + possibleTests + "] (of " + availableTests + " available tests)");
+ successfulTests + '/' + totalIntegrationTests + "] (" + possibleTests + " test methods of " + availableTests + " where possible)");
int exitStatus;
if (!testRunResult.failedIntegrationTests.isEmpty()) {
final int failedTests = testRunResult.failedIntegrationTests.size();
LOGGER.warning("The following " + failedTests + " tests failed!");
final int exitStatus;
if (failedTests > 0) {
LOGGER.warning("💀 The following " + failedTests + " tests failed! 💀");
for (FailedTest failedTest : testRunResult.failedIntegrationTests) {
final Method method = failedTest.testMethod;
final String className = method.getDeclaringClass().getName();
final String methodName = method.getName();
final Throwable cause = failedTest.failureReason;
LOGGER.severe(className + CLASS_METHOD_SEP + methodName + " failed: " + cause);
LOGGER.log(Level.SEVERE, failedTest.concreteTest + " failed: " + cause, cause);
}
exitStatus = 2;
} else {
@ -129,13 +141,22 @@ public class SmackIntegrationTestFramework {
System.exit(exitStatus);
}
public SmackIntegrationTestFramework(Configuration configuration) {
public SmackIntegrationTestFramework(Configuration configuration, Class<DC> defaultConnectionClass)
throws KeyManagementException, InstantiationException, IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchAlgorithmException, SmackException, IOException, XMPPException,
InterruptedException {
this.config = configuration;
this.defaultConnectionClass = defaultConnectionClass;
}
public synchronized TestRunResult run() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
IOException, XMPPException, InterruptedException {
public synchronized TestRunResult run()
throws KeyManagementException, NoSuchAlgorithmException, SmackException, IOException, XMPPException,
InterruptedException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
testRunResult = new TestRunResult();
// Create a connection manager *after* we created the testRunId (in testRunResult).
this.connectionManager = new XmppConnectionManager<>(this, defaultConnectionClass);
LOGGER.info("SmackIntegrationTestFramework [" + testRunResult.testRunId + ']' + ": Starting");
if (config.debugger != Configuration.Debugger.none) {
// JUL Debugger will not print any information until configured to print log messages of
@ -147,7 +168,7 @@ public class SmackIntegrationTestFramework {
if (config.replyTimeout > 0) {
SmackConfiguration.setDefaultReplyTimeout(config.replyTimeout);
}
if (config.securityMode != SecurityMode.required) {
if (config.securityMode != SecurityMode.required && config.accountRegistration == AccountRegistration.inBandRegistration) {
AccountManager.sensitiveOperationOverInsecureConnectionDefault(true);
}
// TODO print effective configuration
@ -169,6 +190,18 @@ public class SmackIntegrationTestFramework {
classes.addAll(inttestClasses);
classes.addAll(lowLevelInttestClasses);
{
// Remove all abstract classes.
// TODO: This may be a good candidate for Java stream filtering once Smack is Android API 24 or higher.
Iterator<Class<? extends AbstractSmackIntTest>> it = classes.iterator();
while (it.hasNext()) {
Class<? extends AbstractSmackIntTest> clazz = it.next();
if (Modifier.isAbstract(clazz.getModifiers())) {
it.remove();
}
}
}
if (classes.isEmpty()) {
throw new IllegalStateException("No test classes found");
}
@ -182,9 +215,7 @@ public class SmackIntegrationTestFramework {
}
finally {
// Ensure that the accounts are deleted and disconnected before we continue
disconnectAndMaybeDelete(environment.conOne);
disconnectAndMaybeDelete(environment.conTwo);
disconnectAndMaybeDelete(environment.conThree);
connectionManager.disconnectAndCleanup();
}
return testRunResult;
@ -192,10 +223,42 @@ public class SmackIntegrationTestFramework {
@SuppressWarnings({"unchecked", "Finally"})
private void runTests(Set<Class<? extends AbstractSmackIntTest>> classes)
throws NoResponseException, InterruptedException {
throws InterruptedException, InstantiationException, IllegalAccessException,
IllegalArgumentException, SmackException, IOException, XMPPException {
for (Class<? extends AbstractSmackIntTest> testClass : classes) {
final String testClassName = testClass.getName();
// TODO: Move the whole "skipping section" below one layer up?
// Skip pseudo integration tests from src/test
// Although Smack's gradle build files do not state that the 'main' sources classpath also contains the
// 'test' classes. Some IDEs like Eclipse include them. As result, a real integration test run encounters
// pseudo integration tests like the DummySmackIntegrationTest which always throws from src/test.
// It is unclear why this apparently does not happen in the 4.3 branch, one likely cause is
// compile project(path: ":smack-omemo", configuration: "testRuntime")
// in
// smack-integration-test/build.gradle:17
// added after 4.3 was branched out with
// 1f731f6318785a84b9741280d586a61dc37ecb2e
// Now "gradle integrationTest" appear to be never affected by this, i.e., they are executed with the
// correct classpath. Plain Eclipse, i.e. Smack imported into Eclipse after "gradle eclipse", appear
// to include *all* classes. Which means those runs sooner or later try to execute
// DummySmackIntegrationTest. Eclipse with buildship, the gradle plugin for Eclipse, always excludes
// *all* src/test classes, which means they do not encounter DummySmackIntegrationTest, but this means
// that the "compile project(path: ":smack-omemo", configuration: "testRuntime")" is not respected,
// which leads to
// Exception in thread "main" java.lang.NoClassDefFoundError: org/jivesoftware/smack/test/util/FileTestUtil
// at org.jivesoftware.smackx.ox.OXSecretKeyBackupIntegrationTest.<clinit>(OXSecretKeyBackupIntegrationTest.java:66)
// See
// - https://github.com/eclipse/buildship/issues/354 (Remove test dependencies from runtime classpath)
// - https://bugs.eclipse.org/bugs/show_bug.cgi?id=482315 (Runtime classpath includes test dependencies)
// - https://discuss.gradle.org/t/main-vs-test-compile-vs-runtime-classpaths-in-eclipse-once-and-for-all-how/17403
// - https://bugs.eclipse.org/bugs/show_bug.cgi?id=376616 (Scope of dependencies has no effect on Eclipse compilation)
if (!SINTTEST_UNIT_TEST && testClassName.startsWith("org.igniterealtime.smack.inttest.unittest")) {
LOGGER.finer("Skipping integration test '" + testClassName + "' from src/test classpath");
continue;
}
if (config.enabledTests != null && !isInSet(testClass, config.enabledTests)) {
LOGGER.info("Skipping test class " + testClassName + " because it is not enabled");
continue;
@ -206,46 +269,84 @@ public class SmackIntegrationTestFramework {
continue;
}
TestType testType;
if (AbstractSmackLowLevelIntegrationTest.class.isAssignableFrom(testClass)) {
final Constructor<? extends AbstractSmackIntTest> cons;
try {
cons = testClass.getConstructor(SmackIntegrationTestEnvironment.class);
}
catch (NoSuchMethodException | SecurityException e) {
throw new IllegalArgumentException(
"Smack Integration Test class does not declare the correct constructor. Is a public Constructor(SmackIntegrationTestEnvironment) missing?",
e);
}
final List<Method> smackIntegrationTestMethods;
{
Method[] testClassMethods = testClass.getMethods();
smackIntegrationTestMethods = new ArrayList<>(testClassMethods.length);
for (Method method : testClassMethods) {
if (!method.isAnnotationPresent(SmackIntegrationTest.class)) {
continue;
}
smackIntegrationTestMethods.add(method);
}
}
if (smackIntegrationTestMethods.isEmpty()) {
LOGGER.warning("No Smack integration test methods found in " + testClass);
continue;
}
testRunResult.numberOfAvailableTestMethods.addAndGet(smackIntegrationTestMethods.size());
final AbstractSmackIntTest test;
try {
test = cons.newInstance(environment);
}
catch (InvocationTargetException e) {
Throwable cause = e.getCause();
throwFatalException(cause);
testRunResult.impossibleTestClasses.put(testClass, cause);
continue;
}
Class<? extends AbstractXMPPConnection> specificLowLevelConnectionClass = null;
final TestType testType;
if (test instanceof AbstractSmackSpecificLowLevelIntegrationTest) {
AbstractSmackSpecificLowLevelIntegrationTest<?> specificLowLevelTest = (AbstractSmackSpecificLowLevelIntegrationTest<?>) test;
specificLowLevelConnectionClass = specificLowLevelTest.getConnectionClass();
testType = TestType.SpecificLowLevel;
} else if (test instanceof AbstractSmackLowLevelIntegrationTest) {
testType = TestType.LowLevel;
} else if (AbstractSmackIntegrationTest.class.isAssignableFrom(testClass)) {
} else if (test instanceof AbstractSmackIntegrationTest) {
testType = TestType.Normal;
} else {
throw new AssertionError();
}
List<Method> smackIntegrationTestMethods = new LinkedList<>();
for (Method method : testClass.getMethods()) {
if (!method.isAnnotationPresent(SmackIntegrationTest.class)) {
continue;
}
// Verify the method signatures, throw in case a signature is incorrect.
for (Method method : smackIntegrationTestMethods) {
Class<?> retClass = method.getReturnType();
if (!retClass.equals(Void.TYPE)) {
LOGGER.warning("SmackIntegrationTest annotation on method that does not return void");
continue;
throw new IllegalStateException(
"SmackIntegrationTest annotation on" + method + " that does not return void");
}
final Class<?>[] parameterTypes = method.getParameterTypes();
switch (testType) {
case Normal:
if (method.getParameterTypes().length > 0) {
LOGGER.warning("SmackIntegrationTest annotaton on method that takes arguments ");
continue;
final Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length > 0) {
throw new IllegalStateException(
"SmackIntegrationTest annotaton on " + method + " that takes arguments ");
}
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");
}
}
verifyLowLevelTestMethod(method, AbstractXMPPConnection.class);
break;
case SpecificLowLevel:
verifyLowLevelTestMethod(method, specificLowLevelConnectionClass);
break;
}
smackIntegrationTestMethods.add(method);
}
if (smackIntegrationTestMethods.isEmpty()) {
LOGGER.warning("No integration test methods found");
continue;
}
Iterator<Method> it = smackIntegrationTestMethods.iterator();
@ -271,75 +372,7 @@ public class SmackIntegrationTestFramework {
}
final int detectedTestMethodsCount = smackIntegrationTestMethods.size();
testRunResult.numberOfAvailableTests.addAndGet(detectedTestMethodsCount);
testRunResult.numberOfPossibleTests.addAndGet(detectedTestMethodsCount);
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();
throwFatalException(cause);
testRunResult.impossibleTestClasses.put(testClass, cause.getMessage());
testRunResult.numberOfPossibleTests.addAndGet(-detectedTestMethodsCount);
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(
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());
testRunResult.numberOfPossibleTests.addAndGet(-detectedTestMethodsCount);
}
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();
}
testRunResult.numberOfPossibleTestMethods.addAndGet(detectedTestMethodsCount);
try {
// Run the @BeforeClass methods (if any)
@ -373,48 +406,36 @@ public class SmackIntegrationTestFramework {
}
for (Method testMethod : smackIntegrationTestMethods) {
final String testPrefix = testClass.getSimpleName() + '.'
+ testMethod.getName() + " (" + testType + "): ";
// Invoke all test methods on the test instance
LOGGER.info(testPrefix + "Start");
long testStart = System.currentTimeMillis();
try {
List<ConcreteTest> concreteTests = null;
switch (testType) {
case Normal: {
ConcreteTest.Executor concreteTestExecutor = () -> testMethod.invoke(test);
ConcreteTest concreteTest = new ConcreteTest(testType, testMethod, concreteTestExecutor);
concreteTests = Collections.singletonList(concreteTest);
}
break;
case LowLevel:
case SpecificLowLevel:
LowLevelTestMethod lowLevelTestMethod = new LowLevelTestMethod(testMethod);
switch (testType) {
case Normal:
testMethod.invoke(test);
break;
case LowLevel:
invokeLowLevel(testMethod, test);
concreteTests = invokeLowLevel(lowLevelTestMethod, (AbstractSmackLowLevelIntegrationTest) test);
break;
case SpecificLowLevel: {
ConcreteTest.Executor concreteTestExecutor = () -> invokeSpecificLowLevel(
lowLevelTestMethod, (AbstractSmackSpecificLowLevelIntegrationTest<?>) test);
ConcreteTest concreteTest = new ConcreteTest(testType, testMethod, concreteTestExecutor);
concreteTests = Collections.singletonList(concreteTest);
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;
default:
throw new AssertionError();
}
Throwable nonFatalFailureReason;
// junit assert's throw an AssertionError if they fail, those should not be
// thrown up, as it would be done by throwFatalException()
if (cause instanceof AssertionError) {
nonFatalFailureReason = cause;
} else {
nonFatalFailureReason = throwFatalException(cause);
}
// An integration test failed
testRunResult.failedIntegrationTests.add(new FailedTest(testMethod, testStart, testEnd, null,
nonFatalFailureReason));
LOGGER.log(Level.SEVERE, testPrefix + "Failed", e);
break;
}
catch (IllegalArgumentException | IllegalAccessException e) {
throw new AssertionError(e);
for (ConcreteTest concreteTest : concreteTests) {
runConcreteTest(concreteTest);
}
}
}
@ -452,67 +473,86 @@ public class SmackIntegrationTestFramework {
}
}
private void invokeLowLevel(Method testMethod, AbstractSmackIntTest test) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InterruptedException {
// We have checked before that every parameter, if any, is of type XMPPTCPConnection
final int numberOfConnections = testMethod.getParameterTypes().length;
XMPPTCPConnection[] connections = null;
private void runConcreteTest(ConcreteTest concreteTest)
throws InterruptedException, XMPPException, IOException, SmackException {
LOGGER.info(concreteTest + " Start");
long testStart = System.currentTimeMillis();
try {
if (numberOfConnections > 0 && !config.isAccountRegistrationPossible()) {
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(environment, i);
}
concreteTest.executor.execute();
long testEnd = System.currentTimeMillis();
LOGGER.info(concreteTest + " Success");
testRunResult.successfulIntegrationTests.add(new SuccessfulTest(concreteTest, testStart, testEnd, null));
}
catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
catch (InvocationTargetException e) {
long testEnd = System.currentTimeMillis();
Throwable cause = e.getCause();
if (cause instanceof TestNotPossibleException) {
LOGGER.info(concreteTest + " is not possible");
testRunResult.impossibleIntegrationTests.add(new TestNotPossible(concreteTest, testStart, testEnd,
null, (TestNotPossibleException) cause));
return;
}
// Behave like this was an InvocationTargetException
throw new InvocationTargetException(e);
}
try {
testMethod.invoke(test, (Object[]) connections);
}
finally {
for (int i = 0; i < numberOfConnections; ++i) {
IntTestUtil.disconnectAndMaybeDelete(connections[i], config);
Throwable nonFatalFailureReason;
// junit assert's throw an AssertionError if they fail, those should not be
// thrown up, as it would be done by throwFatalException()
if (cause instanceof AssertionError) {
nonFatalFailureReason = cause;
} else {
nonFatalFailureReason = throwFatalException(cause);
}
// An integration test failed
testRunResult.failedIntegrationTests.add(new FailedTest(concreteTest, testStart, testEnd, null,
nonFatalFailureReason));
LOGGER.log(Level.SEVERE, concreteTest + " Failed", e);
}
catch (IllegalArgumentException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
protected void disconnectAndMaybeDelete(XMPPTCPConnection connection) throws InterruptedException {
IntTestUtil.disconnectAndMaybeDelete(connection, config);
private static void verifyLowLevelTestMethod(Method method,
Class<? extends AbstractXMPPConnection> connectionClass) {
if (!testMethodParametersIsListOfConnections(method, connectionClass)
&& !testMethodParametersVarargsConnections(method, connectionClass)) {
throw new IllegalArgumentException(method + " is not a valid low level test method");
}
}
protected SmackIntegrationTestEnvironment prepareEnvironment() throws SmackException,
private List<ConcreteTest> invokeLowLevel(LowLevelTestMethod lowLevelTestMethod, AbstractSmackLowLevelIntegrationTest test) {
Set<Class<? extends AbstractXMPPConnection>> connectionClasses;
if (lowLevelTestMethod.smackIntegrationTestAnnotation.onlyDefaultConnectionType()) {
Class<? extends AbstractXMPPConnection> defaultConnectionClass = connectionManager.getDefaultConnectionClass();
connectionClasses = Collections.singleton(defaultConnectionClass);
} else {
connectionClasses = connectionManager.getConnectionClasses();
}
List<ConcreteTest> resultingConcreteTests = new ArrayList<>(connectionClasses.size());
for (Class<? extends AbstractXMPPConnection> connectionClass : connectionClasses) {
ConcreteTest.Executor executor = () -> lowLevelTestMethod.invoke(test, connectionClass);
ConcreteTest concreteTest = new ConcreteTest(TestType.LowLevel, lowLevelTestMethod.testMethod, executor, connectionClass.getSimpleName());
resultingConcreteTests.add(concreteTest);
}
return resultingConcreteTests;
}
private <C extends AbstractXMPPConnection> void invokeSpecificLowLevel(LowLevelTestMethod testMethod,
AbstractSmackSpecificLowLevelIntegrationTest<C> test)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InterruptedException,
SmackException, IOException, XMPPException {
if (testMethod.smackIntegrationTestAnnotation.onlyDefaultConnectionType()) {
throw new IllegalArgumentException("SpecificLowLevelTests must not have set onlyDefaultConnectionType");
}
Class<C> connectionClass = test.getConnectionClass();
testMethod.invoke(test, connectionClass);
}
protected SmackIntegrationTestEnvironment<DC> prepareEnvironment() throws SmackException,
IOException, XMPPException, InterruptedException, KeyManagementException,
NoSuchAlgorithmException {
XMPPTCPConnection conOne = null;
XMPPTCPConnection conTwo = null;
XMPPTCPConnection conThree = null;
try {
conOne = getConnectedConnectionFor(AccountNum.One);
conTwo = getConnectedConnectionFor(AccountNum.Two);
conThree = getConnectedConnectionFor(AccountNum.Three);
}
catch (Exception e) {
// TODO Reverse the order, i.e. conThree should be disconnected first.
if (conOne != null) {
conOne.disconnect();
}
if (conTwo != null) {
conTwo.disconnect();
}
if (conThree != null) {
conThree.disconnect();
}
throw e;
}
return new SmackIntegrationTestEnvironment(conOne, conTwo, conThree, testRunResult.testRunId, config);
NoSuchAlgorithmException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
return connectionManager.prepareEnvironment();
}
enum AccountNum {
@ -521,99 +561,14 @@ public class SmackIntegrationTestFramework {
Three,
}
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;
case Three:
accountUsername = config.accountThreeUsername;
accountPassword = config.accountThreePassword;
middlefix = "three";
break;
default:
throw new IllegalStateException();
}
if (StringUtils.isNullOrEmpty(accountUsername)) {
accountUsername = USERNAME_PREFIX + '-' + middlefix + '-' + testRunResult.testRunId;
}
if (StringUtils.isNullOrEmpty(accountPassword)) {
accountPassword = StringUtils.insecureRandomString(16);
}
XMPPTCPConnectionConfiguration.Builder builder = getConnectionConfigurationBuilder(config);
builder.setUsernameAndPassword(accountUsername, accountPassword)
.setResource(middlefix + '-' + testRunResult.testRunId);
XMPPTCPConnection connection = new XMPPTCPConnection(builder.build());
connection.connect();
if (config.isAccountRegistrationPossible()) {
UsernameAndPassword uap = IntTestUtil.registerAccount(connection, accountUsername, accountPassword, config);
// 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(uap.username, uap.password);
} else {
connection.login();
}
return connection;
}
static XMPPTCPConnectionConfiguration.Builder getConnectionConfigurationBuilder(Configuration config) {
XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();
if (config.tlsContext != null) {
builder.setCustomSSLContext(config.tlsContext);
}
builder.setSecurityMode(config.securityMode);
builder.setXmppDomain(config.service);
switch (config.debugger) {
case enhanced:
builder.setDebuggerFactory(EnhancedDebugger.Factory.INSTANCE);
break;
case console:
builder.setDebuggerFactory(ConsoleDebugger.Factory.INSTANCE);
break;
case none:
// Nothing to do :).
break;
}
config.configurationApplier.applyConfigurationTo(builder);
return builder;
}
static XMPPTCPConnection getConnectedConnection(SmackIntegrationTestEnvironment environment, int connectionId)
throws KeyManagementException, NoSuchAlgorithmException, InterruptedException,
SmackException, IOException, XMPPException {
Configuration config = environment.configuration;
XMPPTCPConnectionConfiguration.Builder builder = getConnectionConfigurationBuilder(config);
XMPPTCPConnection connection = new XMPPTCPConnection(builder.build());
connection.connect();
UsernameAndPassword uap = IntTestUtil.registerAccount(connection, environment, connectionId);
connection.login(uap.username, uap.password);
return connection;
}
private static Exception throwFatalException(Throwable e) throws Error, NoResponseException,
InterruptedException {
if (e instanceof NoResponseException) {
@ -649,14 +604,14 @@ public class SmackIntegrationTestFramework {
*/
public final String testRunId = StringUtils.insecureRandomString(5).toLowerCase(Locale.US);
private final List<SuccessfulTest> successfulTests = Collections.synchronizedList(new LinkedList<SuccessfulTest>());
private final List<SuccessfulTest> successfulIntegrationTests = 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 numberOfAvailableTests = new AtomicInteger();
private final AtomicInteger numberOfPossibleTests = new AtomicInteger();
private final List<TestNotPossible> impossibleIntegrationTests = Collections.synchronizedList(new LinkedList<TestNotPossible>());
private final Map<Class<? extends AbstractSmackIntTest>, Throwable> impossibleTestClasses = new HashMap<>();
private final AtomicInteger numberOfAvailableTestMethods = new AtomicInteger();
private final AtomicInteger numberOfPossibleTestMethods = new AtomicInteger();
private TestRunResult() {
TestRunResult() {
}
public String getTestRunId() {
@ -664,15 +619,15 @@ public class SmackIntegrationTestFramework {
}
public int getNumberOfAvailableTests() {
return numberOfAvailableTests.get();
return numberOfAvailableTestMethods.get();
}
public int getNumberOfPossibleTests() {
return numberOfPossibleTests.get();
return numberOfPossibleTestMethods.get();
}
public List<SuccessfulTest> getSuccessfulTests() {
return Collections.unmodifiableList(successfulTests);
return Collections.unmodifiableList(successfulIntegrationTests);
}
public List<FailedTest> getFailedTests() {
@ -680,11 +635,154 @@ public class SmackIntegrationTestFramework {
}
public List<TestNotPossible> getNotPossibleTests() {
return Collections.unmodifiableList(impossibleTestMethods);
return Collections.unmodifiableList(impossibleIntegrationTests);
}
public Map<Class<? extends AbstractSmackIntTest>, String> getImpossibleTestClasses() {
public Map<Class<? extends AbstractSmackIntTest>, Throwable> getImpossibleTestClasses() {
return Collections.unmodifiableMap(impossibleTestClasses);
}
}
static final class ConcreteTest {
private final TestType testType;
private final Method method;
private final Executor executor;
private final String[] subdescriptons;
private ConcreteTest(TestType testType, Method method, Executor executor, String... subdescriptions) {
this.testType = testType;
this.method = method;
this.executor = executor;
this.subdescriptons = subdescriptions;
}
private transient String stringCache;
@Override
public String toString() {
if (stringCache != null) {
return stringCache;
}
StringBuilder sb = new StringBuilder();
sb.append(method.getDeclaringClass().getSimpleName())
.append('.')
.append(method.getName())
.append(" (")
.append(testType.name());
final String SUBDESCRIPTION_DELIMITER = ", ";
sb.append(SUBDESCRIPTION_DELIMITER);
for (String subdescripton : subdescriptons) {
sb.append(subdescripton).append(SUBDESCRIPTION_DELIMITER);
}
sb.setLength(sb.length() - SUBDESCRIPTION_DELIMITER.length());
sb.append(')');
stringCache = sb.toString();
return stringCache;
}
private interface Executor {
/**
* Execute the test.
*
* @throws IllegalAccessException
* @throws InterruptedException
* @throws InvocationTargetException if the reflective invoked test throws an exception.
* @throws XMPPException in case an XMPPException happens when <em>preparing</em> the test.
* @throws IOException in case an IOException happens when <em>preparing</em> the test.
* @throws SmackException in case an SmackException happens when <em>preparing</em> the test.
*/
void execute() throws IllegalAccessException, InterruptedException, InvocationTargetException,
XMPPException, IOException, SmackException;
}
}
private final class LowLevelTestMethod {
private final Method testMethod;
private final SmackIntegrationTest smackIntegrationTestAnnotation;
private final boolean parameterListOfConnections;
private LowLevelTestMethod(Method testMethod) {
this.testMethod = testMethod;
smackIntegrationTestAnnotation = testMethod.getAnnotation(SmackIntegrationTest.class);
assert (smackIntegrationTestAnnotation != null);
parameterListOfConnections = testMethodParametersIsListOfConnections(testMethod);
}
private void invoke(AbstractSmackLowLevelIntegrationTest test,
Class<? extends AbstractXMPPConnection> connectionClass)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException,
InterruptedException, SmackException, IOException, XMPPException {
final int connectionCount;
if (parameterListOfConnections) {
connectionCount = smackIntegrationTestAnnotation.connectionCount();
if (connectionCount < 1) {
throw new IllegalArgumentException(testMethod + " is annotated to use less than one connection ('"
+ connectionCount + ')');
}
} else {
connectionCount = testMethod.getParameterCount();
}
List<? extends AbstractXMPPConnection> connections = connectionManager.constructConnectedConnections(
connectionClass, connectionCount);
if (parameterListOfConnections) {
testMethod.invoke(test, connections);
} else {
Object[] connectionsArray = new Object[connectionCount];
for (int i = 0; i < connectionsArray.length; i++) {
connectionsArray[i] = connections.remove(0);
}
testMethod.invoke(test, connectionsArray);
}
}
}
private static boolean testMethodParametersIsListOfConnections(Method testMethod) {
return testMethodParametersIsListOfConnections(testMethod, AbstractXMPPConnection.class);
}
static boolean testMethodParametersIsListOfConnections(Method testMethod, Class<? extends AbstractXMPPConnection> connectionClass) {
Type[] parameterTypes = testMethod.getGenericParameterTypes();
if (parameterTypes.length != 1) {
return false;
}
Class<?> soleParameter = testMethod.getParameterTypes()[0];
if (!Collection.class.isAssignableFrom(soleParameter)) {
return false;
}
ParameterizedType soleParameterizedType = (ParameterizedType) parameterTypes[0];
Type[] actualTypeArguments = soleParameterizedType.getActualTypeArguments();
if (actualTypeArguments.length != 1) {
return false;
}
Type soleActualTypeArgument = actualTypeArguments[0];
if (!(soleActualTypeArgument instanceof Class<?>)) {
return false;
}
Class<?> soleActualTypeArgumentAsClass = (Class<?>) soleActualTypeArgument;
if (!connectionClass.isAssignableFrom(soleActualTypeArgumentAsClass)) {
return false;
}
return true;
}
static boolean testMethodParametersVarargsConnections(Method testMethod, Class<? extends AbstractXMPPConnection> connectionClass) {
Class<?>[] parameterTypes = testMethod.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
if (!parameterType.isAssignableFrom(connectionClass)) {
return false;
}
}
return true;
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +16,12 @@
*/
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);
public SuccessfulTest(SmackIntegrationTestFramework.ConcreteTest concreteTest, long startTime, long endTime, List<String> logMessages) {
super(concreteTest, startTime, endTime, logMessages);
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,16 +16,15 @@
*/
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,
public TestNotPossible(SmackIntegrationTestFramework.ConcreteTest concreteTest, long startTime, long endTime, List<String> logMessages,
TestNotPossibleException testNotPossibleException) {
super(testMethod, startTime, endTime, logMessages);
super(concreteTest, startTime, endTime, logMessages);
this.testNotPossibleException = testNotPossibleException;
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,19 +16,18 @@
*/
package org.igniterealtime.smack.inttest;
import java.lang.reflect.Method;
import java.util.List;
public abstract class TestResult {
public final Method testMethod;
public final SmackIntegrationTestFramework.ConcreteTest concreteTest;
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;
public TestResult(SmackIntegrationTestFramework.ConcreteTest concreteTest, long startTime, long endTime, List<String> logMessages) {
this.concreteTest = concreteTest;
assert (endTime >= startTime);
this.startTime = startTime;
this.endTime = endTime;

View file

@ -0,0 +1,104 @@
/**
*
* Copyright 2018-2019 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.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
public class XmppConnectionDescriptor<C extends AbstractXMPPConnection, CC extends ConnectionConfiguration, CCB extends ConnectionConfiguration.Builder<?, CC>> {
private final Class<C> connectionClass;
private final Class<CC> connectionConfigurationClass;
private final Constructor<C> connectionConstructor;
private final Method builderMethod;
public XmppConnectionDescriptor(Class<C> connectionClass, Class<CC> connectionConfigurationClass)
throws ClassNotFoundException, NoSuchMethodException, SecurityException {
this.connectionClass = connectionClass;
this.connectionConfigurationClass = connectionConfigurationClass;
this.connectionConstructor = getConstructor(connectionClass, connectionConfigurationClass);
this.builderMethod = getBuilderMethod(connectionConfigurationClass);
}
public C construct(Configuration sinttestConfiguration)
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
return construct(sinttestConfiguration, Collections.emptyList());
}
public C construct(Configuration sinttestConfiguration,
ConnectionConfigurationBuilderApplier... customConnectionConfigurationAppliers)
throws InstantiationException, IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
List<ConnectionConfigurationBuilderApplier> customConnectionConfigurationAppliersList = new ArrayList<ConnectionConfigurationBuilderApplier>(
Arrays.asList(customConnectionConfigurationAppliers));
return construct(sinttestConfiguration, customConnectionConfigurationAppliersList);
}
public C construct(Configuration sinttestConfiguration,
Collection<ConnectionConfigurationBuilderApplier> customConnectionConfigurationAppliers)
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
CCB connectionConfigurationBuilder = getNewBuilder();
for (ConnectionConfigurationBuilderApplier customConnectionConfigurationApplier : customConnectionConfigurationAppliers) {
customConnectionConfigurationApplier.applyConfigurationTo(connectionConfigurationBuilder);
}
sinttestConfiguration.configurationApplier.applyConfigurationTo(connectionConfigurationBuilder);
ConnectionConfiguration connectionConfiguration = connectionConfigurationBuilder.build();
CC concreteConnectionConfiguration = connectionConfigurationClass.cast(connectionConfiguration);
return connectionConstructor.newInstance(concreteConnectionConfiguration);
}
@SuppressWarnings("unchecked")
public CCB getNewBuilder() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
return (CCB) builderMethod.invoke(null);
}
public Class<C> getConnectionClass() {
return connectionClass;
}
private static <C extends XMPPConnection> Constructor<C> getConstructor(Class<C> connectionClass,
Class<? extends ConnectionConfiguration> connectionConfigurationClass)
throws NoSuchMethodException, SecurityException {
return connectionClass.getConstructor(connectionConfigurationClass);
}
private static <CC extends ConnectionConfiguration> Method getBuilderMethod(Class<CC> connectionConfigurationClass)
throws NoSuchMethodException, SecurityException {
Method builderMethod = connectionConfigurationClass.getMethod("builder");
if (!Modifier.isStatic(builderMethod.getModifiers())) {
throw new IllegalArgumentException();
}
Class<?> returnType = builderMethod.getReturnType();
if (!ConnectionConfiguration.Builder.class.isAssignableFrom(returnType)) {
throw new IllegalArgumentException();
}
return builderMethod;
}
}

View file

@ -0,0 +1,441 @@
/**
*
* Copyright 2018-2019 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.IOException;
import java.lang.reflect.InvocationTargetException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration;
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.XmppNioTcpConnection;
import org.jivesoftware.smack.util.MultiMap;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.admin.ServiceAdministrationManager;
import org.jivesoftware.smackx.iqregister.AccountManager;
import org.igniterealtime.smack.inttest.Configuration.AccountRegistration;
import org.igniterealtime.smack.inttest.SmackIntegrationTestFramework.AccountNum;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Localpart;
import org.jxmpp.stringprep.XmppStringprepException;
public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
private static final Logger LOGGER = Logger.getLogger(XmppConnectionManager.class.getName());
private static final Map<Class<? extends AbstractXMPPConnection>, XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> CONNECTION_DESCRIPTORS = new ConcurrentHashMap<>();
static {
try {
addConnectionDescriptor(XmppNioTcpConnection.class, XMPPTCPConnectionConfiguration.class);
addConnectionDescriptor(XMPPTCPConnection.class, XMPPTCPConnectionConfiguration.class);
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
throw new AssertionError(e);
}
}
public static void addConnectionDescriptor(Class<? extends AbstractXMPPConnection> connectionClass,
Class<? extends ConnectionConfiguration> connectionConfigurationClass) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor = new XmppConnectionDescriptor<>(
connectionClass, connectionConfigurationClass);
addConnectionDescriptor(connectionDescriptor);
}
public static void addConnectionDescriptor(
XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor) {
Class<? extends AbstractXMPPConnection> connectionClass = connectionDescriptor.getConnectionClass();
CONNECTION_DESCRIPTORS.put(connectionClass, connectionDescriptor);
}
public static void removeConnectionDescriptor(Class<? extends AbstractXMPPConnection> connectionClass) {
CONNECTION_DESCRIPTORS.remove(connectionClass);
}
private final XmppConnectionDescriptor<DC, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> defaultConnectionDescriptor;
private final Map<Class<? extends AbstractXMPPConnection>, XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> connectionDescriptors = new HashMap<>(
CONNECTION_DESCRIPTORS.size());
private final SmackIntegrationTestFramework<?> sinttestFramework;
private final Configuration sinttestConfiguration;
private final String testRunId;
private final DC accountRegistrationConnection;
private final ServiceAdministrationManager adminManager;
private final AccountManager accountManager;
/**
* One of the three main connections. The type of the main connections is the default connection type.
*/
DC conOne, conTwo, conThree;
/**
* A pool of authenticated and free to use connections.
*/
private final MultiMap<Class<? extends AbstractXMPPConnection>, AbstractXMPPConnection> connectionPool = new MultiMap<>();
/**
* A list of all ever created connections.
*/
private final List<AbstractXMPPConnection> connections = new ArrayList<>();
@SuppressWarnings("unchecked")
XmppConnectionManager(SmackIntegrationTestFramework<?> sinttestFramework,
Class<? extends DC> defaultConnectionClass)
throws SmackException, IOException, XMPPException, InterruptedException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
this.sinttestFramework = sinttestFramework;
this.sinttestConfiguration = sinttestFramework.config;
this.testRunId = sinttestFramework.testRunResult.testRunId;
connectionDescriptors.putAll(CONNECTION_DESCRIPTORS);
defaultConnectionDescriptor = (XmppConnectionDescriptor<DC, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors.get(
defaultConnectionClass);
if (defaultConnectionDescriptor == null) {
throw new IllegalArgumentException("Could not find a connection descriptor for " + defaultConnectionClass);
}
switch (sinttestConfiguration.accountRegistration) {
case serviceAdministration:
case inBandRegistration:
accountRegistrationConnection = defaultConnectionDescriptor.construct(sinttestConfiguration);
accountRegistrationConnection.connect();
accountRegistrationConnection.login(sinttestConfiguration.adminAccountUsername,
sinttestConfiguration.adminAccountPassword);
if (sinttestConfiguration.accountRegistration == AccountRegistration.inBandRegistration) {
adminManager = null;
accountManager = AccountManager.getInstance(accountRegistrationConnection);
} else {
adminManager = ServiceAdministrationManager.getInstanceFor(accountRegistrationConnection);
accountManager = null;
}
break;
case disabled:
accountRegistrationConnection = null;
adminManager = null;
accountManager = null;
break;
default:
throw new AssertionError();
}
}
SmackIntegrationTestEnvironment<DC> prepareEnvironment() throws KeyManagementException, NoSuchAlgorithmException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
SmackException, IOException, XMPPException, InterruptedException {
prepareMainConnections();
return new SmackIntegrationTestEnvironment<DC>(conOne, conTwo, conThree,
sinttestFramework.testRunResult.testRunId, sinttestConfiguration, this);
}
private void prepareMainConnections() throws KeyManagementException, NoSuchAlgorithmException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, SmackException, IOException,
XMPPException, InterruptedException {
final int mainAccountCount = AccountNum.values().length;
List<DC> connections = new ArrayList<>(mainAccountCount);
for (AccountNum mainAccountNum : AccountNum.values()) {
DC mainConnection = getConnectedMainConnectionFor(mainAccountNum);
connections.add(mainConnection);
}
conOne = connections.get(0);
conTwo = connections.get(1);
conThree = connections.get(2);
}
public Class<? extends AbstractXMPPConnection> getDefaultConnectionClass() {
return defaultConnectionDescriptor.getConnectionClass();
}
public Set<Class<? extends AbstractXMPPConnection>> getConnectionClasses() {
return Collections.unmodifiableSet(connectionDescriptors.keySet());
}
@SuppressWarnings("unchecked")
public <C extends AbstractXMPPConnection> XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> getConnectionDescriptorFor(
Class<C> connectionClass) {
return (XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors.get(
connectionClass);
}
void disconnectAndCleanup() throws InterruptedException {
int successfullyDeletedAccountsCount = 0;
for (AbstractXMPPConnection connection : connections) {
if (sinttestConfiguration.accountRegistration == AccountRegistration.inBandRegistration) {
// Note that we use the account manager from the to-be-deleted connection.
AccountManager accountManager = AccountManager.getInstance(connection);
try {
accountManager.deleteAccount();
successfullyDeletedAccountsCount++;
} catch (NoResponseException | XMPPErrorException | NotConnectedException e) {
LOGGER.log(Level.WARNING, "Could not delete dynamically registered account", e);
}
}
connection.disconnect();
if (sinttestConfiguration.accountRegistration == AccountRegistration.serviceAdministration) {
String username = connection.getConfiguration().getUsername().toString();
Localpart usernameAsLocalpart;
try {
usernameAsLocalpart = Localpart.from(username);
} catch (XmppStringprepException e) {
throw new AssertionError(e);
}
EntityBareJid connectionAddress = JidCreate.entityBareFrom(usernameAsLocalpart, sinttestConfiguration.service);
try {
adminManager.deleteUser(connectionAddress);
successfullyDeletedAccountsCount++;
} catch (NoResponseException | XMPPErrorException | NotConnectedException e) {
LOGGER.log(Level.WARNING, "Could not delete dynamically registered account", e);
}
}
}
if (sinttestConfiguration.isAccountRegistrationPossible()) {
int unsuccessfullyDeletedAccountsCount = connections.size() - successfullyDeletedAccountsCount;
if (unsuccessfullyDeletedAccountsCount == 0) {
LOGGER.info("Successsfully deleted all created accounts ✔");
} else {
LOGGER.warning("Could not delete all created accounts, " + unsuccessfullyDeletedAccountsCount + " remainaing");
}
}
connections.clear();
}
private static final String USERNAME_PREFIX = "smack-inttest";
private DC getConnectedMainConnectionFor(AccountNum accountNum) throws SmackException, IOException, XMPPException,
InterruptedException, KeyManagementException, NoSuchAlgorithmException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
String middlefix;
String accountUsername;
String accountPassword;
switch (accountNum) {
case One:
accountUsername = sinttestConfiguration.accountOneUsername;
accountPassword = sinttestConfiguration.accountOnePassword;
middlefix = "one";
break;
case Two:
accountUsername = sinttestConfiguration.accountTwoUsername;
accountPassword = sinttestConfiguration.accountTwoPassword;
middlefix = "two";
break;
case Three:
accountUsername = sinttestConfiguration.accountThreeUsername;
accountPassword = sinttestConfiguration.accountThreePassword;
middlefix = "three";
break;
default:
throw new IllegalStateException();
}
// Note that it is perfectly fine for account(Username|Password) to be 'null' at this point.
final String finalAccountUsername = StringUtils.isNullOrEmpty(accountUsername) ? USERNAME_PREFIX + '-' + middlefix + '-' + testRunId : accountUsername;
final String finalAccountPassword = StringUtils.isNullOrEmpty(accountPassword) ? StringUtils.insecureRandomString(16) : accountPassword;
if (sinttestConfiguration.isAccountRegistrationPossible()) {
registerAccount(finalAccountUsername, finalAccountPassword);
}
DC mainConnection = defaultConnectionDescriptor.construct(sinttestConfiguration, (builder) -> {
try {
builder.setUsernameAndPassword(finalAccountUsername, finalAccountPassword)
.setResource(middlefix + '-' + testRunId);
} catch (XmppStringprepException e) {
throw new IllegalArgumentException(e);
}
});
connections.add(mainConnection);
mainConnection.connect();
mainConnection.login();
return mainConnection;
}
private void registerAccount(String username, String password) throws NoResponseException, XMPPErrorException,
NotConnectedException, InterruptedException, XmppStringprepException {
if (accountRegistrationConnection == null) {
throw new IllegalStateException("Account registration not configured");
}
switch (sinttestConfiguration.accountRegistration) {
case serviceAdministration:
EntityBareJid userJid = JidCreate.entityBareFrom(Localpart.from(username),
accountRegistrationConnection.getXMPPServiceDomain());
adminManager.addUser(userJid, password);
break;
case inBandRegistration:
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");
Localpart usernameLocalpart = Localpart.from(username);
accountManager.createAccount(usernameLocalpart, password, additionalAttributes);
break;
case disabled:
throw new IllegalStateException("Account creation no possible");
}
}
<C extends AbstractXMPPConnection> List<C> constructConnectedConnections(Class<C> connectionClass, int count)
throws InterruptedException, SmackException, IOException, XMPPException {
List<C> connections = new ArrayList<>(count);
synchronized (connectionPool) {
@SuppressWarnings("unchecked")
List<C> pooledConnections = (List<C>) connectionPool.getAll(connectionClass);
while (count > 0 && !pooledConnections.isEmpty()) {
C connection = pooledConnections.remove(pooledConnections.size() - 1);
connections.add(connection);
count--;
}
}
@SuppressWarnings("unchecked")
XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor = (XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors
.get(connectionClass);
for (int i = 0; i < count; i++) {
C connection = constructConnectedConnection(connectionDescriptor);
connections.add(connection);
}
return connections;
}
private <C extends AbstractXMPPConnection> C constructConnectedConnection(
XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor)
throws InterruptedException, SmackException, IOException, XMPPException {
C connection = constructConnection(connectionDescriptor, null);
connection.connect();
connection.login();
return connection;
}
DC constructConnection()
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
return constructConnection(defaultConnectionDescriptor);
}
<C extends AbstractXMPPConnection> C constructConnection(
XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
return constructConnection(connectionDescriptor, null);
}
private <C extends AbstractXMPPConnection> C constructConnection(
XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor,
Collection<ConnectionConfigurationBuilderApplier> customConnectionConfigurationAppliers)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
String username = "sinttest-" + testRunId + '-' + (connections.size() + 1);
String password = StringUtils.randomString(24);
return constructConnection(username, password, connectionDescriptor, customConnectionConfigurationAppliers);
}
private <C extends AbstractXMPPConnection> C constructConnection(final String username, final String password,
XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor,
Collection<ConnectionConfigurationBuilderApplier> customConnectionConfigurationAppliers)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
try {
registerAccount(username, password);
} catch (XmppStringprepException e) {
throw new IllegalArgumentException(e);
}
ConnectionConfigurationBuilderApplier usernameAndPasswordApplier = (configurationBuilder) -> {
configurationBuilder.setUsernameAndPassword(username, password);
};
if (customConnectionConfigurationAppliers == null) {
customConnectionConfigurationAppliers = Collections.singleton(usernameAndPasswordApplier);
} else {
customConnectionConfigurationAppliers.add(usernameAndPasswordApplier);
}
C connection;
try {
connection = connectionDescriptor.construct(sinttestConfiguration, customConnectionConfigurationAppliers);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new IllegalStateException(e);
}
connections.add(connection);
return connection;
}
void recycle(Collection<? extends AbstractXMPPConnection> connections) {
for (AbstractXMPPConnection connection : connections) {
recycle(connection);
}
}
void recycle(AbstractXMPPConnection connection) {
Class<? extends AbstractXMPPConnection> connectionClass = connection.getClass();
if (!connectionDescriptors.containsKey(connectionClass)) {
throw new IllegalStateException("Attempt to recycle unknown connection of class '" + connectionClass + "'");
}
if (connection.isAuthenticated()) {
synchronized (connectionPool) {
connectionPool.put(connectionClass, connection);
}
}
// Note that we do not delete the account of the unauthenticated connection here, as it is done at the end of
// the test run together with all other dynamically created accounts.
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -48,7 +48,7 @@ public class ChatTest extends AbstractSmackIntegrationTest {
private boolean invoked;
@SuppressWarnings("deprecation")
public ChatTest(SmackIntegrationTestEnvironment environment) {
public ChatTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
chatManagerOne = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(conOne);
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -25,8 +25,6 @@ import java.security.NoSuchAlgorithmException;
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;
import org.igniterealtime.smack.inttest.AbstractSmackLowLevelIntegrationTest;
@ -35,7 +33,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
public class LoginIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
public LoginIntegrationTest(SmackIntegrationTestEnvironment environment) {
public LoginIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}
@ -54,14 +52,13 @@ public class LoginIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
public void testInvalidLogin() throws SmackException, IOException, XMPPException,
InterruptedException, KeyManagementException, NoSuchAlgorithmException {
final String nonExistentUserString = StringUtils.insecureRandomString(24);
XMPPTCPConnectionConfiguration conf = getConnectionConfiguration().setUsernameAndPassword(
nonExistentUserString, "invalidPassword").build();
final String invalidPassword = "invalidPassword";
XMPPTCPConnection connection = new XMPPTCPConnection(conf);
AbstractXMPPConnection connection = getUnconnectedConnection();
connection.connect();
try {
connection.login();
connection.login(nonExistentUserString, invalidPassword);
fail("Exception expected");
}
catch (SASLErrorException e) {

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -28,23 +28,20 @@ import org.jivesoftware.smack.filter.MessageWithBodiesFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.igniterealtime.smack.inttest.AbstractSmackLowLevelIntegrationTest;
import org.igniterealtime.smack.inttest.AbstractSmackSpecificLowLevelIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
import org.igniterealtime.smack.inttest.TestNotPossibleException;
public class StreamManagementTest extends AbstractSmackLowLevelIntegrationTest {
public class StreamManagementTest extends AbstractSmackSpecificLowLevelIntegrationTest<XMPPTCPConnection> {
public StreamManagementTest(SmackIntegrationTestEnvironment environment) throws Exception {
super(environment);
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");
}
}
});
public StreamManagementTest(SmackIntegrationTestEnvironment<?> environment) throws Exception {
super(environment, XMPPTCPConnection.class);
XMPPTCPConnection connection = getSpecificUnconnectedConnection();
connection.connect().login();
if (!connection.isSmAvailable()) {
throw new TestNotPossibleException("XEP-198: Stream Mangement not supported by service");
}
}
@SmackIntegrationTest

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2017 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,25 +20,23 @@ import static org.junit.Assert.assertTrue;
import java.lang.reflect.Field;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.igniterealtime.smack.inttest.AbstractSmackLowLevelIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
public class WaitForClosingStreamElementTest extends AbstractSmackLowLevelIntegrationTest {
public WaitForClosingStreamElementTest(SmackIntegrationTestEnvironment environment) {
public WaitForClosingStreamElementTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}
@SmackIntegrationTest
public void waitForClosingStreamElementTest(XMPPTCPConnection connection)
public void waitForClosingStreamElementTest(AbstractXMPPConnection connection)
throws NoSuchFieldException, SecurityException, IllegalArgumentException,
IllegalAccessException {
connection.disconnect();
Field closingStreamReceivedField = connection.getClass().getDeclaredField("closingStreamReceived");
Field closingStreamReceivedField = AbstractXMPPConnection.class.getDeclaredField("closingStreamReceived");
closingStreamReceivedField.setAccessible(true);
SynchronizationPoint<?> closingStreamReceived = (SynchronizationPoint<?>) closingStreamReceivedField.get(connection);
Exception failureException = closingStreamReceived.getFailureException();

View file

@ -0,0 +1,67 @@
/**
*
* Copyright 2018-2019 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.util.List;
import java.util.logging.Level;
import org.jivesoftware.smack.tcp.XmppNioTcpConnection;
import org.igniterealtime.smack.XmppConnectionStressTest;
import org.igniterealtime.smack.XmppConnectionStressTest.StressTestFailedException.ErrorsWhileSendingOrReceivingException;
import org.igniterealtime.smack.XmppConnectionStressTest.StressTestFailedException.NotAllMessagesReceivedException;
import org.igniterealtime.smack.inttest.AbstractSmackLowLevelIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
public class XmppConnectionIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
public XmppConnectionIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}
@SmackIntegrationTest(connectionCount = 4)
public void allToAllMessageSendTest(List<AbstractXMPPConnection> connections)
throws InterruptedException, NotAllMessagesReceivedException, ErrorsWhileSendingOrReceivingException {
final long seed = 42;
final int messagesPerConnection = 3; // 100
final int maxPayloadChunkSize = 16; // 512
final int maxPayloadChunks = 4; // 32
final boolean intermixMessages = false; // true
XmppConnectionStressTest.Configuration stressTestConfiguration = new XmppConnectionStressTest.Configuration(
seed, messagesPerConnection, maxPayloadChunkSize, maxPayloadChunks, intermixMessages);
XmppConnectionStressTest stressTest = new XmppConnectionStressTest(stressTestConfiguration);
stressTest.run(connections, timeout);
final Level connectionStatsLogLevel = Level.FINE;
if (LOGGER.isLoggable(connectionStatsLogLevel)) {
if (connections.get(0) instanceof XmppNioTcpConnection) {
for (XMPPConnection connection : connections) {
XmppNioTcpConnection xmppNioTcpConnection = (XmppNioTcpConnection) connection;
XmppNioTcpConnection.Stats stats = xmppNioTcpConnection.getStats();
LOGGER.log(connectionStatsLogLevel,
"Connections stats for " + xmppNioTcpConnection + ":\n{}",
stats);
}
}
}
}
}

View file

@ -25,7 +25,7 @@ public abstract class AbstractChatIntegrationTest extends AbstractSmackIntegrati
protected final ChatManager chatManagerTwo;
protected final ChatManager chatManagerThree;
protected AbstractChatIntegrationTest(SmackIntegrationTestEnvironment environment) {
protected AbstractChatIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
chatManagerOne = ChatManager.getInstanceFor(conOne);
chatManagerTwo = ChatManager.getInstanceFor(conTwo);

View file

@ -26,7 +26,7 @@ import org.jxmpp.jid.EntityBareJid;
public class IncomingMessageListenerIntegrationTest extends AbstractChatIntegrationTest {
public IncomingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment environment) {
public IncomingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}

View file

@ -26,7 +26,7 @@ import org.jxmpp.jid.EntityBareJid;
public class OutgoingMessageListenerIntegrationTest extends AbstractChatIntegrationTest {
public OutgoingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment environment) {
public OutgoingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2016-2018 Florian Schmaus
* Copyright 2016-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,8 +18,8 @@ package org.jivesoftware.smack.roster;
import java.util.concurrent.TimeoutException;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.igniterealtime.smack.inttest.AbstractSmackLowLevelIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
@ -30,12 +30,13 @@ import org.jxmpp.jid.FullJid;
public class LowLevelRosterIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
public LowLevelRosterIntegrationTest(SmackIntegrationTestEnvironment environment) {
public LowLevelRosterIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}
@SmackIntegrationTest
public void testPresenceEventListenersOffline(final XMPPTCPConnection conOne, final XMPPTCPConnection conTwo) throws TimeoutException, Exception {
public void testPresenceEventListenersOffline(final AbstractXMPPConnection conOne,
final AbstractXMPPConnection conTwo) throws TimeoutException, Exception {
IntegrationTestRosterUtil.ensureBothAccountsAreNotInEachOthersRoster(conOne, conTwo);
final Roster rosterOne = Roster.getInstanceFor(conOne);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2018 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -38,7 +38,7 @@ public class RosterIntegrationTest extends AbstractSmackIntegrationTest {
private final Roster rosterOne;
private final Roster rosterTwo;
public RosterIntegrationTest(SmackIntegrationTestEnvironment environment) {
public RosterIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
rosterOne = Roster.getInstanceFor(conOne);
rosterTwo = Roster.getInstanceFor(conTwo);

View file

@ -0,0 +1,46 @@
/**
*
* Copyright 2018-2019 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.tcp;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.igniterealtime.smack.inttest.AbstractSmackSpecificLowLevelIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
public class XmppNioTcpConnectionLowLevelIntegrationTest extends AbstractSmackSpecificLowLevelIntegrationTest<XmppNioTcpConnection> {
public XmppNioTcpConnectionLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment, XmppNioTcpConnection.class);
}
@SmackIntegrationTest
public void testDisconnectAfterConnect() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
IOException, XMPPException, InterruptedException {
XmppNioTcpConnection connection = getSpecificUnconnectedConnection();
connection.connect();
connection.disconnect();
}
}

View file

@ -0,0 +1,21 @@
/**
*
* 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.
*/
/**
* TCP-IP related classes for Smack.
*/
package org.jivesoftware.smack.tcp;

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2013-2018 Florian Schmaus
* Copyright 2013-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -57,7 +57,7 @@ public class EntityCapsTest extends AbstractSmackIntegrationTest {
private final ServiceDiscoveryManager sdmOne;
private final ServiceDiscoveryManager sdmTwo;
public EntityCapsTest(SmackIntegrationTestEnvironment environment) {
public EntityCapsTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
ecmTwo = EntityCapsManager.getInstanceFor(environment.conTwo);
sdmOne = ServiceDiscoveryManager.getInstanceFor(environment.conOne);

View file

@ -54,7 +54,7 @@ public class ChatStateIntegrationTest extends AbstractSmackIntegrationTest {
};
public ChatStateIntegrationTest(SmackIntegrationTestEnvironment environment) {
public ChatStateIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -39,7 +39,7 @@ public class FileTransferIntegrationTest extends AbstractSmackIntegrationTest {
private final FileTransferManager ftManagerOne;
private final FileTransferManager ftManagerTwo;
public FileTransferIntegrationTest(SmackIntegrationTestEnvironment environment) {
public FileTransferIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
ftManagerOne = FileTransferManager.getInstanceFor(conOne);
ftManagerTwo = FileTransferManager.getInstanceFor(conTwo);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2017 Florian Schmaus
* Copyright 2017-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -43,7 +43,7 @@ public class HttpFileUploadIntegrationTest extends AbstractSmackIntegrationTest
private final HttpFileUploadManager hfumOne;
public HttpFileUploadIntegrationTest(SmackIntegrationTestEnvironment environment) throws XMPPErrorException,
public HttpFileUploadIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws XMPPErrorException,
NotConnectedException, NoResponseException, InterruptedException, TestNotPossibleException {
super(environment);
hfumOne = HttpFileUploadManager.getInstanceFor(conOne);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2016-2018 Florian Schmaus
* Copyright 2016-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -43,7 +43,7 @@ public class IoTControlIntegrationTest extends AbstractSmackIntegrationTest {
private final IoTControlManager IoTControlManagerTwo;
public IoTControlIntegrationTest(SmackIntegrationTestEnvironment environment) {
public IoTControlIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
IoTControlManagerOne = IoTControlManager.getInstanceFor(conOne);
IoTControlManagerTwo = IoTControlManager.getInstanceFor(conTwo);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2016-2018 Florian Schmaus
* Copyright 2016-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -45,7 +45,7 @@ public class IoTDataIntegrationTest extends AbstractSmackIntegrationTest {
private final IoTDataManager iotDataManagerTwo;
public IoTDataIntegrationTest(SmackIntegrationTestEnvironment environment) {
public IoTDataIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
iotDataManagerOne = IoTDataManager.getInstanceFor(conOne);
iotDataManagerTwo = IoTDataManager.getInstanceFor(conTwo);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2016 Florian Schmaus
* Copyright 2016-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -41,7 +41,7 @@ public class IoTDiscoveryIntegrationTest extends AbstractSmackIntegrationTest {
private final IoTDiscoveryManager discoveryManagerOne;
private final IoTDiscoveryManager discoveryManagerTwo;
public IoTDiscoveryIntegrationTest(SmackIntegrationTestEnvironment environment) throws NoResponseException,
public IoTDiscoveryIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException {
super(environment);
discoveryManagerOne = IoTDiscoveryManager.getInstanceFor(conOne);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -31,7 +31,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
public class VersionIntegrationTest extends AbstractSmackIntegrationTest {
public VersionIntegrationTest(SmackIntegrationTestEnvironment environment) {
public VersionIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2016 Fernando Ramirez, 2018 Florian Schmaus
* Copyright 2016 Fernando Ramirez, 2018-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -47,7 +47,7 @@ public class MamIntegrationTest extends AbstractSmackIntegrationTest {
private final MamManager mamManagerConTwo;
public MamIntegrationTest(SmackIntegrationTestEnvironment environment) throws NoResponseException,
public MamIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException, NotLoggedInException {
super(environment);

View file

@ -35,7 +35,7 @@ public class MoodIntegrationTest extends AbstractSmackIntegrationTest {
private final MoodManager mm1;
private final MoodManager mm2;
public MoodIntegrationTest(SmackIntegrationTestEnvironment environment) {
public MoodIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
mm1 = MoodManager.getInstanceFor(conOne);
mm2 = MoodManager.getInstanceFor(conTwo);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2018 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -53,7 +53,7 @@ public class MultiUserChatIntegrationTest extends AbstractSmackIntegrationTest {
private final MultiUserChatManager mucManagerTwo;
private final DomainBareJid mucService;
public MultiUserChatIntegrationTest(SmackIntegrationTestEnvironment environment)
public MultiUserChatIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
throws NoResponseException, XMPPErrorException, NotConnectedException,
InterruptedException, TestNotPossibleException {
super(environment);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2018 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,9 +20,9 @@ import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.bookmarks.BookmarkManager;
@ -40,20 +40,20 @@ import org.jxmpp.jid.parts.Resourcepart;
public class MultiUserChatLowLevelIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
public MultiUserChatLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment) throws Exception {
public MultiUserChatLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws Exception {
super(environment);
performCheck(new ConnectionCallback() {
@Override
public void connectionCallback(XMPPTCPConnection connection) throws Exception {
if (MultiUserChatManager.getInstanceFor(connection).getMucServiceDomains().isEmpty()) {
throw new TestNotPossibleException("MUC component not offered by service");
}
AbstractXMPPConnection connection = getConnectedConnection();
try {
if (MultiUserChatManager.getInstanceFor(connection).getMucServiceDomains().isEmpty()) {
throw new TestNotPossibleException("MUC component not offered by service");
}
});
} finally {
recycle(connection);
}
}
@SmackIntegrationTest
public void testMucBookmarksAutojoin(XMPPTCPConnection connection) throws InterruptedException,
public void testMucBookmarksAutojoin(AbstractXMPPConnection connection) throws InterruptedException,
TestNotPossibleException, XMPPException, SmackException, IOException {
final BookmarkManager bookmarkManager = BookmarkManager.getBookmarkManager(connection);
if (!bookmarkManager.isSupported()) {

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2017 Florian Schmaus, Paul Schaub
* Copyright 2017-2018 Florian Schmaus, Paul Schaub
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -28,7 +28,7 @@ import org.igniterealtime.smack.inttest.TestNotPossibleException;
*/
public abstract class AbstractOmemoIntegrationTest extends AbstractSmackIntegrationTest {
public AbstractOmemoIntegrationTest(SmackIntegrationTestEnvironment environment) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, TestNotPossibleException {
public AbstractOmemoIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, TestNotPossibleException {
super(environment);
// Test for server support

View file

@ -39,7 +39,7 @@ public abstract class AbstractTwoUsersOmemoIntegrationTest extends AbstractOmemo
protected OmemoManager alice, bob;
public AbstractTwoUsersOmemoIntegrationTest(SmackIntegrationTestEnvironment environment)
public AbstractTwoUsersOmemoIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException, TestNotPossibleException {
super(environment);

View file

@ -34,7 +34,7 @@ import org.igniterealtime.smack.inttest.TestNotPossibleException;
*/
public class MessageEncryptionIntegrationTest extends AbstractTwoUsersOmemoIntegrationTest {
public MessageEncryptionIntegrationTest(SmackIntegrationTestEnvironment environment)
public MessageEncryptionIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException, TestNotPossibleException {
super(environment);

View file

@ -37,7 +37,7 @@ import org.igniterealtime.smack.inttest.TestNotPossibleException;
* Then Bob fetches his Mam archive and decrypts the result.
*/
public class OmemoMamDecryptionTest extends AbstractTwoUsersOmemoIntegrationTest {
public OmemoMamDecryptionTest(SmackIntegrationTestEnvironment environment)
public OmemoMamDecryptionTest(SmackIntegrationTestEnvironment<?> environment)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException, TestNotPossibleException {
super(environment);

View file

@ -32,7 +32,7 @@ import org.igniterealtime.smack.inttest.TestNotPossibleException;
public class ReadOnlyDeviceIntegrationTest extends AbstractTwoUsersOmemoIntegrationTest {
public ReadOnlyDeviceIntegrationTest(SmackIntegrationTestEnvironment environment) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, TestNotPossibleException {
public ReadOnlyDeviceIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, TestNotPossibleException {
super(environment);
}

View file

@ -25,7 +25,7 @@ import org.igniterealtime.smack.inttest.TestNotPossibleException;
public class SessionRenegotiationIntegrationTest extends AbstractTwoUsersOmemoIntegrationTest {
public SessionRenegotiationIntegrationTest(SmackIntegrationTestEnvironment environment)
public SessionRenegotiationIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException, TestNotPossibleException {
super(environment);

View file

@ -41,7 +41,7 @@ public abstract class AbstractOpenPgpIntegrationTest extends AbstractSmackIntegr
protected final PepManager bobPepManager;
protected final PepManager chloePepManager;
protected AbstractOpenPgpIntegrationTest(SmackIntegrationTestEnvironment environment)
protected AbstractOpenPgpIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
throws XMPPException.XMPPErrorException, TestNotPossibleException, SmackException.NotConnectedException,
InterruptedException, SmackException.NoResponseException {
super(environment);

View file

@ -97,7 +97,7 @@ public class OXSecretKeyBackupIntegrationTest extends AbstractOpenPgpIntegration
* @throws InterruptedException
* @throws SmackException.NoResponseException
*/
public OXSecretKeyBackupIntegrationTest(SmackIntegrationTestEnvironment environment)
public OXSecretKeyBackupIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
throws XMPPException.XMPPErrorException, TestNotPossibleException, SmackException.NotConnectedException,
InterruptedException, SmackException.NoResponseException {
super(environment);

View file

@ -87,7 +87,7 @@ public class OXInstantMessagingIntegrationTest extends AbstractOpenPgpIntegratio
* @throws TestNotPossibleException if the test is not possible due to lacking server support for PEP.
* @throws SmackException.NoResponseException
*/
public OXInstantMessagingIntegrationTest(SmackIntegrationTestEnvironment environment)
public OXInstantMessagingIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
throws XMPPException.XMPPErrorException, InterruptedException, SmackException.NotConnectedException,
TestNotPossibleException, SmackException.NoResponseException {
super(environment);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2017 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -39,7 +39,7 @@ import org.jxmpp.jid.Jid;
public class PingIntegrationTest extends AbstractSmackIntegrationTest {
public PingIntegrationTest(SmackIntegrationTestEnvironment environment) {
public PingIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2018 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -34,7 +34,7 @@ public class PubSubIntegrationTest extends AbstractSmackIntegrationTest {
private final PubSubManager pubSubManagerOne;
public PubSubIntegrationTest(SmackIntegrationTestEnvironment environment)
public PubSubIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
throws TestNotPossibleException, NoResponseException, XMPPErrorException,
NotConnectedException, InterruptedException {
super(environment);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2004 Jive Software, 2017 Florian Schmaus.
* Copyright 2004 Jive Software, 2017-2019 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -39,7 +39,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
*/
public class FormTest extends AbstractSmackIntegrationTest {
public FormTest(SmackIntegrationTestEnvironment environment) {
public FormTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,21 +16,39 @@
*/
package org.igniterealtime.smack.inttest;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
public class DummySmackIntegrationTestFramework extends SmackIntegrationTestFramework {
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.DummyConnection.DummyConnectionConfiguration;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
public DummySmackIntegrationTestFramework(Configuration configuration) {
super(configuration);
public class DummySmackIntegrationTestFramework extends SmackIntegrationTestFramework<DummyConnection> {
static {
try {
XmppConnectionManager.addConnectionDescriptor(DummyConnection.class, DummyConnectionConfiguration.class);
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
throw new AssertionError(e);
}
}
public DummySmackIntegrationTestFramework(Configuration configuration) throws KeyManagementException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
NoSuchAlgorithmException, SmackException, IOException, XMPPException, InterruptedException {
super(configuration, DummyConnection.class);
testRunResult = new TestRunResult();
}
@Override
protected SmackIntegrationTestEnvironment prepareEnvironment() {
return new SmackIntegrationTestEnvironment(null, null, null, testRunResult.getTestRunId(), config);
protected SmackIntegrationTestEnvironment<DummyConnection> prepareEnvironment() {
DummyConnection dummyConnection = new DummyConnection();
connectionManager.conOne = connectionManager.conTwo = connectionManager.conThree = dummyConnection;
return new SmackIntegrationTestEnvironment<DummyConnection>(dummyConnection, dummyConnection, dummyConnection,
testRunResult.getTestRunId(), config, null);
}
@Override
protected void disconnectAndMaybeDelete(XMPPTCPConnection connection) {
// This method is a no-op in DummySmackIntegrationTestFramework
}
}

View file

@ -0,0 +1,96 @@
/**
*
* Copyright 2019 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.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import java.util.List;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.junit.Test;
public class SmackIntegrationTestFrameWorkTest {
private static class ValidLowLevelList {
@SuppressWarnings("unused")
public void test(List<AbstractXMPPConnection> connections) {
}
}
private static class InvalidLowLevelList {
@SuppressWarnings("unused")
public void test(List<AbstractXMPPConnection> connections, boolean invalid) {
}
}
private static class ValidLowLevelVarargs {
@SuppressWarnings("unused")
public void test(AbstractXMPPConnection connectionOne, AbstractXMPPConnection connectionTwo,
AbstractXMPPConnection connectionThree) {
}
}
private static class InvalidLowLevelVarargs {
@SuppressWarnings("unused")
public void test(AbstractXMPPConnection connectionOne, Integer invalid, AbstractXMPPConnection connectionTwo,
AbstractXMPPConnection connectionThree) {
}
}
private static Method getTestMethod(Class<?> testClass) {
Method[] methods = testClass.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals("test")) {
return method;
}
}
throw new IllegalArgumentException("No test method found in " + testClass);
}
@Test
public void testValidLowLevelList() {
Method testMethod = getTestMethod(ValidLowLevelList.class);
assertTrue(SmackIntegrationTestFramework.testMethodParametersIsListOfConnections(testMethod,
AbstractXMPPConnection.class));
}
@Test
public void testInvalidLowLevelList() {
Method testMethod = getTestMethod(InvalidLowLevelList.class);
assertFalse(SmackIntegrationTestFramework.testMethodParametersIsListOfConnections(testMethod,
AbstractXMPPConnection.class));
}
@Test
public void testValidLowLevelVarargs() {
Method testMethod = getTestMethod(ValidLowLevelVarargs.class);
assertTrue(SmackIntegrationTestFramework.testMethodParametersVarargsConnections(testMethod,
AbstractXMPPConnection.class));
}
@Test
public void testInvalidLowLevelVargs() {
Method testMethod = getTestMethod(InvalidLowLevelVarargs.class);
assertFalse(SmackIntegrationTestFramework.testMethodParametersVarargsConnections(testMethod,
AbstractXMPPConnection.class));
}
}

View file

@ -16,9 +16,14 @@
*/
package org.igniterealtime.smack.inttest;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jxmpp.jid.JidTestUtil;
public class SmackIntegrationTestUnitTestUtil {
@ -32,7 +37,12 @@ public class SmackIntegrationTestUnitTestUtil {
.setUsernamesAndPassword("dummy1", "dummy1pass", "dummy2", "dummy2pass", "dummy3", "dummy3pass")
.addEnabledTest(unitTest).build();
// @formatter:on
return new DummySmackIntegrationTestFramework(configuration);
try {
return new DummySmackIntegrationTestFramework(configuration);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| SmackException | IOException | XMPPException | InterruptedException e) {
throw new IllegalStateException(e);
}
}
}

View file

@ -0,0 +1,45 @@
/**
*
* Copyright 2018-2019 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.junit.Assert.assertEquals;
import java.lang.reflect.InvocationTargetException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smack.tcp.XmppNioTcpConnection;
import org.junit.Test;
import org.jxmpp.stringprep.XmppStringprepException;
public class SmackIntegrationTestXmppConnectionManagerTest {
@Test
public void simpleXmppConnectionDescriptorTest() throws ClassNotFoundException, NoSuchMethodException,
SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
KeyManagementException, NoSuchAlgorithmException, XmppStringprepException, InstantiationException {
XmppConnectionDescriptor<XmppNioTcpConnection, XMPPTCPConnectionConfiguration, XMPPTCPConnectionConfiguration.Builder> descriptor
= new XmppConnectionDescriptor<>(XmppNioTcpConnection.class, XMPPTCPConnectionConfiguration.class);
Configuration sinttestConfiguration = Configuration.builder().setService("example.org").build();
XmppNioTcpConnection connection = descriptor.construct(sinttestConfiguration);
assertEquals("example.org", connection.getXMPPServiceDomain().toString());
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
@ -37,6 +38,7 @@ 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;
import org.igniterealtime.smack.inttest.SmackIntegrationTestFramework.TestRunResult;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@ -52,9 +54,19 @@ public class SmackIntegrationTestFrameworkUnitTest {
private static boolean beforeClassInvoked;
private static boolean afterClassInvoked;
@BeforeClass
public static void prepareSinttestUnitTest() {
SmackIntegrationTestFramework.SINTTEST_UNIT_TEST = true;
}
@AfterClass
public static void disallowSinntestUnitTest() {
SmackIntegrationTestFramework.SINTTEST_UNIT_TEST = false;
}
@Test
public void throwsRuntimeExceptionsTest() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
IOException, XMPPException, InterruptedException {
IOException, XMPPException, InterruptedException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
expectedException.expect(RuntimeException.class);
expectedException.expectMessage(ThrowsRuntimeExceptionDummyTest.RUNTIME_EXCEPTION_MESSAGE);
DummySmackIntegrationTestFramework sinttest = getFrameworkForUnitTest(ThrowsRuntimeExceptionDummyTest.class);
@ -63,7 +75,7 @@ public class SmackIntegrationTestFrameworkUnitTest {
public static class ThrowsRuntimeExceptionDummyTest extends AbstractSmackIntegrationTest {
public ThrowsRuntimeExceptionDummyTest(SmackIntegrationTestEnvironment environment) {
public ThrowsRuntimeExceptionDummyTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}
@ -77,7 +89,8 @@ public class SmackIntegrationTestFrameworkUnitTest {
@Test
public void logsNonFatalExceptionTest() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
IOException, XMPPException, InterruptedException {
IOException, XMPPException, InterruptedException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
DummySmackIntegrationTestFramework sinttest = getFrameworkForUnitTest(ThrowsNonFatalExceptionDummyTest.class);
TestRunResult testRunResult = sinttest.run();
List<FailedTest> failedTests = testRunResult.getFailedTests();
@ -93,7 +106,7 @@ public class SmackIntegrationTestFrameworkUnitTest {
public static final String DESCRIPTIVE_TEXT = "I'm not fatal";
public ThrowsNonFatalExceptionDummyTest(SmackIntegrationTestEnvironment environment) {
public ThrowsNonFatalExceptionDummyTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}
@ -107,7 +120,8 @@ public class SmackIntegrationTestFrameworkUnitTest {
@Test
public void testInvoking() throws KeyManagementException, NoSuchAlgorithmException, SmackException, IOException,
XMPPException, InterruptedException {
XMPPException, InterruptedException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
beforeClassInvoked = false;
afterClassInvoked = false;
@ -120,7 +134,7 @@ public class SmackIntegrationTestFrameworkUnitTest {
public static class BeforeAfterClassTest extends AbstractSmackIntegrationTest {
public BeforeAfterClassTest(SmackIntegrationTestEnvironment environment) {
public BeforeAfterClassTest(SmackIntegrationTestEnvironment<?> environment) {
super(environment);
}