[sinttest] Allow the selection of individual test *methods*

This commit is contained in:
Florian Schmaus 2021-12-13 21:08:45 +01:00
parent 69a55aaa84
commit 10a2687ff1
4 changed files with 153 additions and 17 deletions

View File

@ -86,6 +86,27 @@ debugger=console
The framework will first load the properties file from `~/.config/smack-integration-test/properties` The framework will first load the properties file from `~/.config/smack-integration-test/properties`
### Running selected tests only
Using `enabledTests` is is possible to run only selected tests. The
tests can be selected on a per class base or by specifying concrete
test methods. In the latter case, the methods must be qualified by a
(simple) class name.
For example:
```bash
$ gradle integrationTest -Dsinttest.enabledTests=SoftwareInfoIntegrationTest.test
```
will only run the `test()` method of `SoftwareInfoIntegrationTest`, whereas
```bash
$ gradle integrationTest -Dsinttest.enabledTests=SoftwareInfoIntegrationTest
```
would run all tests defined in the `SoftwareInfoIntegrationTest` class.
Overview of the components Overview of the components
-------------------------- --------------------------

View File

@ -89,4 +89,11 @@ public class CollectionUtil {
} }
return Collections.singletonList(element); return Collections.singletonList(element);
} }
public static <T> Set<T> nullSafeUnmodifiableSet(Set<T> set) {
if (set == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(set);
}
} }

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2015-2020 Florian Schmaus * Copyright 2015-2021 Florian Schmaus
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,8 +19,11 @@ package org.igniterealtime.smack.inttest;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.security.KeyManagementException; import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -33,6 +36,7 @@ import javax.net.ssl.SSLContext;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode; import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.debugger.ConsoleDebugger; import org.jivesoftware.smack.debugger.ConsoleDebugger;
import org.jivesoftware.smack.util.CollectionUtil;
import org.jivesoftware.smack.util.Function; import org.jivesoftware.smack.util.Function;
import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.ParserUtils; import org.jivesoftware.smack.util.ParserUtils;
@ -101,8 +105,12 @@ public final class Configuration {
public final Set<String> enabledTests; public final Set<String> enabledTests;
private final Map<String, Set<String>> enabledTestsMap;
public final Set<String> disabledTests; public final Set<String> disabledTests;
private final Map<String, Set<String>> disabledTestsMap;
public final String defaultConnectionNickname; public final String defaultConnectionNickname;
public final Set<String> enabledConnections; public final Set<String> enabledConnections;
@ -169,8 +177,10 @@ public final class Configuration {
this.accountTwoPassword = builder.accountTwoPassword; this.accountTwoPassword = builder.accountTwoPassword;
this.accountThreeUsername = builder.accountThreeUsername; this.accountThreeUsername = builder.accountThreeUsername;
this.accountThreePassword = builder.accountThreePassword; this.accountThreePassword = builder.accountThreePassword;
this.enabledTests = builder.enabledTests; this.enabledTests = CollectionUtil.nullSafeUnmodifiableSet(builder.enabledTests);
this.disabledTests = builder.disabledTests; this.enabledTestsMap = convertTestsToMap(enabledTests);
this.disabledTests = CollectionUtil.nullSafeUnmodifiableSet(builder.disabledTests);
this.disabledTestsMap = convertTestsToMap(disabledTests);
this.defaultConnectionNickname = builder.defaultConnectionNickname; this.defaultConnectionNickname = builder.defaultConnectionNickname;
this.enabledConnections = builder.enabledConnections; this.enabledConnections = builder.enabledConnections;
this.disabledConnections = builder.disabledConnections; this.disabledConnections = builder.disabledConnections;
@ -577,4 +587,112 @@ public final class Configuration {
}); });
} }
private static Map<String, Set<String>> convertTestsToMap(Set<String> tests) {
Map<String, Set<String>> res = new HashMap<>();
for (String test : tests) {
String[] testParts = test.split("\\.");
if (testParts.length == 1) {
// The whole test specification does not contain a dot, assume it is a test class specification.
res.put(test, Collections.emptySet());
continue;
}
String lastTestPart = testParts[testParts.length - 1];
if (lastTestPart.isEmpty()) {
throw new IllegalArgumentException("Invalid test specifier: " + test);
}
char firstCharOfLastTestPart = lastTestPart.charAt(0);
if (!Character.isLowerCase(firstCharOfLastTestPart)) {
// The first character of the last test part is not lowercase, assume this is a fully qualified test
// class specification, e.g. org.foo.bar.TestClass.
res.put(test, Collections.emptySet());
}
// The first character of the last test part is lowercase, assume this is a test class *and* method name
// specification.
String testMethodName = lastTestPart;
int classPartsCount = testParts.length - 1;
String[] classParts = new String[classPartsCount];
System.arraycopy(testParts, 0, classParts, 0, classPartsCount);
String testClass = String.join(".", classParts);
res.compute(testClass, (k, v) -> {
if (v == null) {
v = new HashSet<>();
}
v.add(testMethodName);
return v;
});
}
return res;
}
private static Set<String> getKey(Class<?> testClass, Map<String, Set<String>> testsMap) {
String className = testClass.getName();
if (testsMap.containsKey(className)) {
return testsMap.get(className);
}
String unqualifiedClassName = testClass.getSimpleName();
if (testsMap.containsKey(unqualifiedClassName)) {
return testsMap.get(unqualifiedClassName);
}
return null;
}
private static boolean contains(Class<? extends AbstractSmackIntTest> testClass, Map<String, Set<String>> testsMap) {
Set<String> enabledMethods = getKey(testClass, testsMap);
return enabledMethods != null;
}
public boolean isClassEnabled(Class<? extends AbstractSmackIntTest> testClass) {
if (enabledTestsMap.isEmpty()) {
return true;
}
return contains(testClass, enabledTestsMap);
}
public boolean isClassDisabled(Class<? extends AbstractSmackIntTest> testClass) {
if (disabledTestsMap.isEmpty()) {
return false;
}
return contains(testClass, disabledTestsMap);
}
private static boolean contains(Method method, Map<String, Set<String>> testsMap) {
Class<?> testClass = method.getDeclaringClass();
Set<String> methods = getKey(testClass, testsMap);
if (methods == null) {
return false;
}
if (methods.isEmpty()) {
return true;
}
String methodName = method.getName();
return methods.contains(methodName);
}
public boolean isMethodEnabled(Method method) {
if (enabledTestsMap.isEmpty()) {
return true;
}
return contains(method, enabledTestsMap);
}
public boolean isMethodDisabled(Method method) {
if (disabledTestsMap.isEmpty()) {
return false;
}
return contains(method, disabledTestsMap);
}
} }

View File

@ -282,13 +282,13 @@ public class SmackIntegrationTestFramework {
continue; continue;
} }
if (config.enabledTests != null && !isInSet(testClass, config.enabledTests)) { if (!config.isClassEnabled(testClass)) {
DisabledTestClass disabledTestClass = new DisabledTestClass(testClass, "Skipping test class " + testClassName + " because it is not enabled"); DisabledTestClass disabledTestClass = new DisabledTestClass(testClass, "Skipping test class " + testClassName + " because it is not enabled");
testRunResult.disabledTestClasses.add(disabledTestClass); testRunResult.disabledTestClasses.add(disabledTestClass);
continue; continue;
} }
if (isInSet(testClass, config.disabledTests)) { if (config.isClassDisabled(testClass)) {
DisabledTestClass disabledTestClass = new DisabledTestClass(testClass, "Skipping test class " + testClassName + " because it is disalbed"); DisabledTestClass disabledTestClass = new DisabledTestClass(testClass, "Skipping test class " + testClassName + " because it is disalbed");
testRunResult.disabledTestClasses.add(disabledTestClass); testRunResult.disabledTestClasses.add(disabledTestClass);
continue; continue;
@ -377,14 +377,13 @@ public class SmackIntegrationTestFramework {
while (it.hasNext()) { while (it.hasNext()) {
final Method method = it.next(); final Method method = it.next();
final String methodName = method.getName(); final String methodName = method.getName();
if (config.enabledTests != null && !(config.enabledTests.contains(methodName) if (!config.isMethodEnabled(method)) {
|| isInSet(testClass, config.enabledTests))) {
DisabledTest disabledTest = new DisabledTest(method, "Skipping test method " + methodName + " because it is not enabled"); DisabledTest disabledTest = new DisabledTest(method, "Skipping test method " + methodName + " because it is not enabled");
testRunResult.disabledTests.add(disabledTest); testRunResult.disabledTests.add(disabledTest);
it.remove(); it.remove();
continue; continue;
} }
if (config.disabledTests != null && config.disabledTests.contains(methodName)) { if (config.isMethodDisabled(method)) {
DisabledTest disabledTest = new DisabledTest(method, "Skipping test method " + methodName + " because it is disabled"); DisabledTest disabledTest = new DisabledTest(method, "Skipping test method " + methodName + " because it is disabled");
testRunResult.disabledTests.add(disabledTest); testRunResult.disabledTests.add(disabledTest);
it.remove(); it.remove();
@ -607,15 +606,6 @@ public class SmackIntegrationTestFramework {
return (Exception) e; return (Exception) e;
} }
private static boolean isInSet(Class<?> clz, Set<String> classes) {
if (classes == null) {
return false;
}
final String className = clz.getName();
final String unqualifiedClassName = clz.getSimpleName();
return classes.contains(className) || classes.contains(unqualifiedClassName);
}
public static final class TestRunResult { public static final class TestRunResult {
/** /**