mirror of
https://github.com/BlazingGames/blazing-games-plugin.git
synced 2025-02-03 21:26:41 -05:00
add unit testing ""framework""
This commit is contained in:
parent
7a08b8ca82
commit
d98941ffe9
12 changed files with 384 additions and 6 deletions
|
@ -1,11 +1,47 @@
|
||||||
name: Build and Publish
|
name: Build, Test and Publish
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
jobs:
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: '21'
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: actions/gradle/setup-gradle@v4
|
||||||
|
with:
|
||||||
|
gradle-version: '8.11'
|
||||||
|
|
||||||
|
- name: Setup Paper
|
||||||
|
run: |
|
||||||
|
mkdir testsrv
|
||||||
|
curl -o testsrv/server.jar https://api.papermc.io/v2/projects/paper/versions/1.21/builds/130/downloads/paper-1.21-130.jar
|
||||||
|
echo "eula=true" > testsrv/eula.txt
|
||||||
|
|
||||||
|
- name: Build test jar with Gradle
|
||||||
|
run: gradle -Pversion=test-${{ github.run_number }} -Ptest=true build
|
||||||
|
|
||||||
|
- name: Install plugin
|
||||||
|
run: |
|
||||||
|
mkdir testsrv/plugins
|
||||||
|
cp build/libs/blazinggames-test-${{ github.run_number }}.jar testsrv/plugins/blazinggames.jar
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
timeout-minutes: 30
|
||||||
|
run: |
|
||||||
|
java -Xms2048M -Xmx2048M -jar testsrv/server.jar nogui --nogui
|
||||||
build-and-publish:
|
build-and-publish:
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
|
needs: test
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
|
@ -16,6 +16,10 @@ This is a standard Paper plugin using Gradle.
|
||||||
|
|
||||||
To build, use: `./gradlew build`
|
To build, use: `./gradlew build`
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
This plugins supports testing. To run tests, use: `./gradlew build -Ptest=true`, and load the plugin normally. Once tests are done running, the file `TESTS_RESULT` in the server files directory will contain `true` if tests passed or `false` if tests failed.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This plugin is licensed under the Apache License (version 2.0). For more information, please read the NOTICE and LICENSE files.
|
This plugin is licensed under the Apache License (version 2.0). For more information, please read the NOTICE and LICENSE files.
|
||||||
|
|
|
@ -70,7 +70,10 @@ tasks.withType(JavaCompile).configureEach {
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
def props = [version: version]
|
def props = [
|
||||||
|
version: version,
|
||||||
|
launchClass: ("true".equals(project.test)) ? project.testClass : project.mainClass
|
||||||
|
]
|
||||||
inputs.properties props
|
inputs.properties props
|
||||||
filteringCharset 'UTF-8'
|
filteringCharset 'UTF-8'
|
||||||
filesMatching('plugin.yml') {
|
filesMatching('plugin.yml') {
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
version = STAGING
|
version = STAGING
|
||||||
|
|
||||||
|
test = false
|
||||||
|
mainClass = de.blazemcworld.blazinggames.BlazingGames
|
||||||
|
testClass = de.blazemcworld.blazinggames.testing.TestBlazingGames
|
|
@ -54,8 +54,7 @@ import java.util.Objects;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
public class BlazingGames extends JavaPlugin {
|
||||||
public final class BlazingGames extends JavaPlugin {
|
|
||||||
public boolean API_AVAILABLE = false;
|
public boolean API_AVAILABLE = false;
|
||||||
|
|
||||||
// Gson
|
// Gson
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Blazing Games Maintainers
|
||||||
|
*
|
||||||
|
* 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 de.blazemcworld.blazinggames.testing;
|
||||||
|
|
||||||
|
public abstract class BlazingTest {
|
||||||
|
public abstract boolean runAsync();
|
||||||
|
public boolean run() {
|
||||||
|
try {
|
||||||
|
runTest();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void runTest() throws Exception;
|
||||||
|
|
||||||
|
// methods for test runner
|
||||||
|
protected void assertBoolean(String condition, boolean assertion) throws TestFailedException {
|
||||||
|
if (!assertion) {
|
||||||
|
throw new TestFailedException(getClass(), "assertBoolean failed: \"" + condition + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertEquals(Object expected, Object actual) throws TestFailedException {
|
||||||
|
if (expected == null && actual == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expected == null || actual == null || !expected.equals(actual)) {
|
||||||
|
throw new TestFailedException(getClass(), "assertEquals expected \"" + expected + "\" but got \"" + actual + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Blazing Games Maintainers
|
||||||
|
*
|
||||||
|
* 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 de.blazemcworld.blazinggames.testing;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import de.blazemcworld.blazinggames.BlazingGames;
|
||||||
|
|
||||||
|
public class TestBlazingGames extends BlazingGames {
|
||||||
|
public static final int TEST_RUNNERS = 5;
|
||||||
|
private static final ArrayList<TestList> tests = new ArrayList<>(List.of(TestList.values()));
|
||||||
|
private static final ArrayList<TestList> failedTests = new ArrayList<>();
|
||||||
|
private static boolean started = false;
|
||||||
|
private static int remainingRunners = TEST_RUNNERS;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
try {
|
||||||
|
super.onEnable();
|
||||||
|
|
||||||
|
if (!started) {
|
||||||
|
started = true;
|
||||||
|
|
||||||
|
if (tests.isEmpty()) {
|
||||||
|
getLogger().severe("No tests found!");
|
||||||
|
exit(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogger().info("Starting " + tests.size() + " tests with " + TEST_RUNNERS + " runners...");
|
||||||
|
|
||||||
|
int runners = TEST_RUNNERS > tests.size() ? tests.size() : TEST_RUNNERS;
|
||||||
|
if (runners != TEST_RUNNERS) {
|
||||||
|
getLogger().warning("Not enough tests to run with " + TEST_RUNNERS + " runners! Running with " + runners + " instead");
|
||||||
|
remainingRunners = tests.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < runners; i++) {
|
||||||
|
scheduleNextTest(null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogger().info("Tests starting soon...");
|
||||||
|
} else {
|
||||||
|
getLogger().severe("Plugin was loaded twice. Exiting.");
|
||||||
|
exit(false);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
getLogger().severe("An unhandled exception occurred in onEnable. Exiting.");
|
||||||
|
exit(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
try {
|
||||||
|
super.onDisable();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
getLogger().severe("An unhandled exception occurred in onDisable. Exiting.");
|
||||||
|
exit(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull FileConfiguration getConfig() {
|
||||||
|
var config = new YamlConfiguration();
|
||||||
|
|
||||||
|
// defaults (config.yml)
|
||||||
|
try (
|
||||||
|
InputStream stream = getClass().getResourceAsStream("/config.yml");
|
||||||
|
Reader reader = new InputStreamReader(stream);
|
||||||
|
) {
|
||||||
|
config.setDefaults(YamlConfiguration.loadConfiguration(reader));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overrides (config.testing.yml)
|
||||||
|
try (
|
||||||
|
InputStream stream = getClass().getResourceAsStream("/config.testing.yml");
|
||||||
|
Reader reader = new InputStreamReader(stream);
|
||||||
|
) {
|
||||||
|
config.load(reader);
|
||||||
|
} catch (IOException | InvalidConfigurationException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void exit(boolean success) {
|
||||||
|
File file = new File("TESTS_RESULT");
|
||||||
|
file.delete();
|
||||||
|
try (FileWriter writer = new FileWriter(file)) {
|
||||||
|
writer.write(success ? "true" : "false");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
Bukkit.getServer().shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void scheduleNextTest(final TestList currentTest, final boolean passed) {
|
||||||
|
TestList test = nextTest(currentTest, passed);
|
||||||
|
if (test != null) {
|
||||||
|
if (test.test.runAsync()) {
|
||||||
|
Bukkit.getScheduler().runTaskLaterAsynchronously(get(), new TestRunner(test, get().getLogger()), 5);
|
||||||
|
} else {
|
||||||
|
Bukkit.getScheduler().runTaskLater(get(), new TestRunner(test, get().getLogger()), 5);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remainingRunners--;
|
||||||
|
if (remainingRunners <= 0) {
|
||||||
|
final boolean isSuccess = failedTests.isEmpty();
|
||||||
|
get().getLogger().info("All tests are done.");
|
||||||
|
if (isSuccess) {
|
||||||
|
get().getLogger().info("All tests passed! Exiting cleanly.");
|
||||||
|
} else {
|
||||||
|
get().getLogger().severe("Some tests failed:");
|
||||||
|
for (TestList testList : failedTests) {
|
||||||
|
get().getLogger().severe("* " + testList.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bukkit.getScheduler().runTaskLater(get(), () -> exit(isSuccess), 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized TestList nextTest(final TestList currentTest, final boolean passed) {
|
||||||
|
if (currentTest != null) {
|
||||||
|
if (!passed) {
|
||||||
|
failedTests.add(currentTest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tests.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tests.remove(0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Blazing Games Maintainers
|
||||||
|
*
|
||||||
|
* 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 de.blazemcworld.blazinggames.testing;
|
||||||
|
|
||||||
|
public class TestFailedException extends Exception {
|
||||||
|
public TestFailedException(Class<?> clazz, String message) {
|
||||||
|
super("Test failed: " + clazz.getName() + ": " + message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Blazing Games Maintainers
|
||||||
|
*
|
||||||
|
* 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 de.blazemcworld.blazinggames.testing;
|
||||||
|
|
||||||
|
public enum TestList {
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
public final BlazingTest test;
|
||||||
|
TestList(BlazingTest test) {
|
||||||
|
this.test = test;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Blazing Games Maintainers
|
||||||
|
*
|
||||||
|
* 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 de.blazemcworld.blazinggames.testing;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class TestRunner implements Runnable {
|
||||||
|
private final TestList test;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
|
public TestRunner(TestList test, Logger logger) {
|
||||||
|
this.test = test;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
logger.info("Running test: " + test.name());
|
||||||
|
boolean passed = test.test.run();
|
||||||
|
if (!passed) {
|
||||||
|
logger.severe("Test failed: " + test.name());
|
||||||
|
} else {
|
||||||
|
logger.info("Test passed: " + test.name());
|
||||||
|
}
|
||||||
|
TestBlazingGames.scheduleNextTest(test, passed);
|
||||||
|
}
|
||||||
|
}
|
27
src/main/resources/config.testing.yml
Normal file
27
src/main/resources/config.testing.yml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# overrides of config.yml for when unit testing is enabled
|
||||||
|
|
||||||
|
jda:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
logging:
|
||||||
|
log-error: true
|
||||||
|
log-info: true
|
||||||
|
log-debug: true
|
||||||
|
notify-ops-on-error: false
|
||||||
|
|
||||||
|
computing:
|
||||||
|
local:
|
||||||
|
disable-computers: false
|
||||||
|
privileges:
|
||||||
|
chunkloading: true
|
||||||
|
net: true
|
||||||
|
microsoft:
|
||||||
|
spoof-ms-server: true
|
||||||
|
jwt:
|
||||||
|
secret-key: randomize-on-server-start
|
||||||
|
secret-key-is-password: false
|
||||||
|
services:
|
||||||
|
blazing-api:
|
||||||
|
enabled: true
|
||||||
|
blazing-wss:
|
||||||
|
enabled: true
|
|
@ -1,6 +1,6 @@
|
||||||
name: blazinggames
|
name: blazinggames
|
||||||
version: '${version}'
|
version: '${version}'
|
||||||
main: de.blazemcworld.blazinggames.BlazingGames
|
main: '${launchClass}'
|
||||||
api-version: '1.21'
|
api-version: '1.21'
|
||||||
prefix: BlazingGames
|
prefix: BlazingGames
|
||||||
authors: [BlazeMCworld, sbot50, 'Ivy Collective (ivyc.)', XTerPL]
|
authors: [BlazeMCworld, sbot50, 'Ivy Collective (ivyc.)', XTerPL]
|
||||||
|
|
Loading…
Reference in a new issue