[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`
### 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
--------------------------

View File

@ -89,4 +89,11 @@ public class CollectionUtil {
}
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");
* 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.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@ -33,6 +36,7 @@ import javax.net.ssl.SSLContext;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.debugger.ConsoleDebugger;
import org.jivesoftware.smack.util.CollectionUtil;
import org.jivesoftware.smack.util.Function;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.ParserUtils;
@ -101,8 +105,12 @@ public final class Configuration {
public final Set<String> enabledTests;
private final Map<String, Set<String>> enabledTestsMap;
public final Set<String> disabledTests;
private final Map<String, Set<String>> disabledTestsMap;
public final String defaultConnectionNickname;
public final Set<String> enabledConnections;
@ -169,8 +177,10 @@ public final class Configuration {
this.accountTwoPassword = builder.accountTwoPassword;
this.accountThreeUsername = builder.accountThreeUsername;
this.accountThreePassword = builder.accountThreePassword;
this.enabledTests = builder.enabledTests;
this.disabledTests = builder.disabledTests;
this.enabledTests = CollectionUtil.nullSafeUnmodifiableSet(builder.enabledTests);
this.enabledTestsMap = convertTestsToMap(enabledTests);
this.disabledTests = CollectionUtil.nullSafeUnmodifiableSet(builder.disabledTests);
this.disabledTestsMap = convertTestsToMap(disabledTests);
this.defaultConnectionNickname = builder.defaultConnectionNickname;
this.enabledConnections = builder.enabledConnections;
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;
}
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");
testRunResult.disabledTestClasses.add(disabledTestClass);
continue;
}
if (isInSet(testClass, config.disabledTests)) {
if (config.isClassDisabled(testClass)) {
DisabledTestClass disabledTestClass = new DisabledTestClass(testClass, "Skipping test class " + testClassName + " because it is disalbed");
testRunResult.disabledTestClasses.add(disabledTestClass);
continue;
@ -377,14 +377,13 @@ public class SmackIntegrationTestFramework {
while (it.hasNext()) {
final Method method = it.next();
final String methodName = method.getName();
if (config.enabledTests != null && !(config.enabledTests.contains(methodName)
|| isInSet(testClass, config.enabledTests))) {
if (!config.isMethodEnabled(method)) {
DisabledTest disabledTest = new DisabledTest(method, "Skipping test method " + methodName + " because it is not enabled");
testRunResult.disabledTests.add(disabledTest);
it.remove();
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");
testRunResult.disabledTests.add(disabledTest);
it.remove();
@ -607,15 +606,6 @@ public class SmackIntegrationTestFramework {
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 {
/**