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:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
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:
|
||||
runs-on: docker
|
||||
needs: test
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
|
|
|
@ -16,6 +16,10 @@ This is a standard Paper plugin using Gradle.
|
|||
|
||||
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
|
||||
|
||||
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 {
|
||||
def props = [version: version]
|
||||
def props = [
|
||||
version: version,
|
||||
launchClass: ("true".equals(project.test)) ? project.testClass : project.mainClass
|
||||
]
|
||||
inputs.properties props
|
||||
filteringCharset 'UTF-8'
|
||||
filesMatching('plugin.yml') {
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
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;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class BlazingGames extends JavaPlugin {
|
||||
public class BlazingGames extends JavaPlugin {
|
||||
public boolean API_AVAILABLE = false;
|
||||
|
||||
// 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
|
||||
version: '${version}'
|
||||
main: de.blazemcworld.blazinggames.BlazingGames
|
||||
main: '${launchClass}'
|
||||
api-version: '1.21'
|
||||
prefix: BlazingGames
|
||||
authors: [BlazeMCworld, sbot50, 'Ivy Collective (ivyc.)', XTerPL]
|
||||
|
|
Loading…
Reference in a new issue