Skip to content

Commit a99080a

Browse files
committedNov 22, 2023
Added multithreading and update tests
1 parent dae0746 commit a99080a

File tree

6 files changed

+104
-54
lines changed

6 files changed

+104
-54
lines changed
 

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
target/
22
.vscode/
33
depe
4+
.idea/
5+
*.iml

‎src/main/java/io/github/slimefun/e2etester/E2ETester.java

+13
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,26 @@
77

88
public class E2ETester extends JavaPlugin {
99

10+
private static E2ETester instance;
11+
1012
@Override
1113
public void onEnable() {
14+
instance = this;
15+
1216
final TestFramework framework = TestFramework.newTestRun();
1317

1418
// Wait a second for any startup stuff to be ran
1519
Bukkit.getScheduler().runTaskLater(this, () -> {
1620
framework.runTests("io.github.slimefun.e2etester.tests");
1721
}, 20);
1822
}
23+
24+
@Override
25+
public void onDisable() {
26+
instance = null;
27+
}
28+
29+
public static E2ETester getInstance() {
30+
return instance;
31+
}
1932
}

‎src/main/java/io/github/slimefun/e2etester/framework/TestFramework.java

+86-52
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
package io.github.slimefun.e2etester.framework;
22

3+
import java.lang.annotation.Annotation;
4+
import java.lang.reflect.InvocationTargetException;
35
import java.lang.reflect.Method;
46
import java.util.ArrayList;
57
import java.util.HashMap;
68
import java.util.LinkedHashMap;
79
import java.util.List;
810
import java.util.Map;
911
import java.util.Set;
12+
import java.util.concurrent.CountDownLatch;
13+
import java.util.concurrent.ExecutorService;
14+
import java.util.concurrent.Executors;
15+
import java.util.concurrent.atomic.AtomicBoolean;
1016
import java.util.function.Consumer;
1117
import java.util.stream.Collectors;
1218

1319
import javax.annotation.Nonnull;
1420

21+
import io.github.slimefun.e2etester.E2ETester;
1522
import org.bukkit.Bukkit;
1623
import org.reflections.Reflections;
1724
import org.reflections.scanners.Scanners;
@@ -24,6 +31,7 @@
2431
public class TestFramework {
2532

2633
private final Map<String, ArrayList<Consumer<Void>>> eventListeners = new HashMap<>();
34+
private final ExecutorService service = Executors.newSingleThreadExecutor();
2735

2836
private int testsRan;
2937
private int testsPassed;
@@ -41,63 +49,89 @@ public void runTests(@Nonnull String packageName) {
4149
// TODO: Remove
4250
new Startup();
4351

44-
// Reflection go through all classes
45-
Reflections reflections = new Reflections(ConfigurationBuilder
46-
.build()
47-
.addScanners(Scanners.values())
48-
.forPackage(packageName, getClass().getClassLoader())
49-
);
50-
51-
logMessage("Running tests...");
52-
logMessage("");
53-
54-
final Set<Method> testMethods = reflections.get(Scanners.MethodsAnnotated.with(E2ETest.class).as(Method.class));
55-
final Map<Class<?>, List<Method>> tests = orderTests(testMethods);
56-
for (Map.Entry<Class<?>, List<Method>> entry : tests.entrySet()) {
57-
logMessage("%s:", entry.getKey().getName());
58-
59-
for (Method method : entry.getValue()) {
60-
String description = method.getAnnotation(E2ETest.class).description();
61-
62-
// Invoke
63-
try {
64-
testsRan++;
65-
66-
method.setAccessible(true);
67-
Object instance = method.getDeclaringClass().getDeclaredConstructor().newInstance();
68-
method.invoke(instance);
69-
70-
testsPassed++;
71-
logMessage(" ✔ %s", description);
72-
} catch(TestFailException e) {
73-
testsFailed++;
74-
logMessage(" x %s", description);
75-
e.printStackTrace();
76-
} catch(Exception e) {
77-
testsFailed++;
78-
logMessage(" x %s", description);
79-
e.printStackTrace();
52+
service.submit(() -> {
53+
// Reflection go through all classes
54+
Reflections reflections = new Reflections(ConfigurationBuilder
55+
.build()
56+
.addScanners(Scanners.values())
57+
.forPackage(packageName, getClass().getClassLoader())
58+
);
59+
60+
logMessage("Running tests...");
61+
logMessage("");
62+
63+
final Set<Method> testMethods = reflections.get(Scanners.MethodsAnnotated.with(E2ETest.class).as(Method.class));
64+
final Map<Class<?>, List<Method>> tests = orderTests(testMethods);
65+
for (Map.Entry<Class<?>, List<Method>> entry : tests.entrySet()) {
66+
logMessage("%s:", entry.getKey().getName());
67+
68+
for (Method method : entry.getValue()) {
69+
E2ETest annotation = method.getAnnotation(E2ETest.class);
70+
String description = annotation.description();
71+
boolean threadSafe = annotation.threadSafe();
72+
73+
CountDownLatch latch = new CountDownLatch(1);
74+
AtomicBoolean failed = new AtomicBoolean(false);
75+
76+
// Invoke
77+
try {
78+
testsRan++;
79+
method.setAccessible(true);
80+
Object instance = method.getDeclaringClass().getDeclaredConstructor().newInstance();
81+
if (threadSafe) {
82+
method.invoke(instance);
83+
} else {
84+
Bukkit.getScheduler().runTask(E2ETester.getInstance(), () -> {
85+
try {
86+
method.invoke(instance);
87+
latch.countDown();
88+
} catch (IllegalAccessException | InvocationTargetException e) {
89+
latch.countDown();
90+
if (e.getCause() instanceof TestFailException) {
91+
failed.set(true);
92+
e.printStackTrace();
93+
}
94+
}
95+
});
96+
latch.await();
97+
}
98+
if (failed.get()) {
99+
testsFailed++;
100+
logMessage(" x %s", description);
101+
} else {
102+
testsPassed++;
103+
logMessage(" ✔ %s", description);
104+
}
105+
} catch(TestFailException e) {
106+
testsFailed++;
107+
logMessage(" x %s", description);
108+
e.printStackTrace();
109+
} catch(Exception e) {
110+
testsFailed++;
111+
logMessage(" x %s", description);
112+
e.printStackTrace();
113+
}
80114
}
81115
}
82-
}
83-
84-
logMessage("");
85-
logMessage("Test results:");
86-
logMessage(" Tests ran: %d", this.testsRan);
87-
logMessage(" Tests passed: %d", this.testsPassed);
88-
logMessage(" Tests failed: %d", this.testsFailed);
89-
logMessage(" Tests skipped: %d", this.testsSkipped);
90116

91-
if (this.testsFailed > 0) {
92-
logMessage("Test failure, exiting with code 1");
93-
System.exit(1);
94-
} else {
95-
Bukkit.shutdown();
96-
}
117+
logMessage("");
118+
logMessage("Test results:");
119+
logMessage(" Tests ran: %d", this.testsRan);
120+
logMessage(" Tests passed: %d", this.testsPassed);
121+
logMessage(" Tests failed: %d", this.testsFailed);
122+
logMessage(" Tests skipped: %d", this.testsSkipped);
123+
124+
if (this.testsFailed > 0) {
125+
logMessage("Test failure, exiting with code 1");
126+
System.exit(1);
127+
} else {
128+
Bukkit.getScheduler().runTask(E2ETester.getInstance(), Bukkit::shutdown);
129+
}
130+
});
97131
}
98132

99133
public void on(@Nonnull String event, Consumer<Void> consumer) {
100-
eventListeners.putIfAbsent(event, new ArrayList<Consumer<Void>>());
134+
eventListeners.putIfAbsent(event, new ArrayList<>());
101135

102136
ArrayList<Consumer<Void>> value = eventListeners.get(event);
103137
if (value != null) {
@@ -146,7 +180,7 @@ private Map<Class<?>, List<Method>> orderTests(Set<Method> methods) {
146180
return tests.entrySet().stream()
147181
.sorted((entry1, entry2) -> entry1.getKey().getName().compareTo(entry2.getKey().getName()))
148182
.collect(Collectors.toMap(
149-
entry -> entry.getKey(),
183+
Map.Entry::getKey,
150184
value -> value.getValue().stream()
151185
.sorted((method1, method2) -> method1.getName().compareTo(method2.getName()))
152186
.toList()

‎src/main/java/io/github/slimefun/e2etester/framework/annotations/E2ETest.java

+1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010
public @interface E2ETest {
1111

1212
String description();
13+
boolean threadSafe() default false;
1314
}

‎src/main/java/io/github/slimefun/e2etester/tests/Startup.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ public void testPluginIsEnabled() {
1616
@E2ETest(description = "Test that `/sf versions` runs successfully")
1717
public void testVersionsCommandCanBeRun() {
1818
// Run /sf versions and make sure it doesn't error
19-
Assert.runConsoleCommand("sf versions", (output) -> output.contains("Slimefun 4.9-UNOFFICIAL"));
19+
Assert.runConsoleCommand("sf versions", (output) -> output.contains("Slimefun Preview Build"));
2020
}
2121
}

‎src/main/java/io/github/slimefun/e2etester/tests/VersionsTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public void testMcVersion() {
1414

1515
@E2ETest(description = "Test that `/sf versions` returns the right SF version")
1616
public void testSlimefunVersion() {
17-
Assert.runConsoleCommand("sf versions", (output) -> output.contains("Slimefun 4.9-UNOFFICIAL"));
17+
Assert.runConsoleCommand("sf versions", (output) -> output.contains("Slimefun Preview Build"));
1818
}
1919

2020
@E2ETest(description = "Test that `/sf versions` returns the right Java version")

0 commit comments

Comments
 (0)
Please sign in to comment.