mirror of
https://github.com/lucko/LuckPerms.git
synced 2025-08-22 14:12:48 +02:00
Integration tests against real server
This commit is contained in:
@@ -2,6 +2,10 @@ plugins {
|
||||
alias(libs.plugins.shadow)
|
||||
}
|
||||
|
||||
configurations {
|
||||
testJar
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://repo.papermc.io/repository/maven-public/' }
|
||||
}
|
||||
@@ -27,6 +31,18 @@ shadowJar {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('copyTestJar', Copy) {
|
||||
from tasks.shadowJar.archiveFile
|
||||
into layout.buildDirectory.dir('testJars')
|
||||
rename { String fileName ->
|
||||
return 'luckperms-bukkit.testjar'
|
||||
}
|
||||
}
|
||||
|
||||
artifacts.add('testJar', layout.buildDirectory.dir('testJars')) {
|
||||
builtBy('copyTestJar')
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives shadowJar
|
||||
}
|
||||
|
@@ -7,6 +7,10 @@ plugins {
|
||||
|
||||
archivesBaseName = 'luckperms'
|
||||
|
||||
configurations {
|
||||
testJar
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://maven.fabricmc.net/' }
|
||||
}
|
||||
@@ -81,6 +85,18 @@ task remappedShadowJar(type: RemapJarTask) {
|
||||
|
||||
tasks.assemble.dependsOn tasks.remappedShadowJar
|
||||
|
||||
tasks.register('copyTestJar', Copy) {
|
||||
from tasks.remappedShadowJar.archiveFile
|
||||
into layout.buildDirectory.dir('testJars')
|
||||
rename { String fileName ->
|
||||
return 'luckperms-fabric.testjar'
|
||||
}
|
||||
}
|
||||
|
||||
artifacts.add('testJar', layout.buildDirectory.dir('testJars')) {
|
||||
builtBy('copyTestJar')
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives remappedShadowJar
|
||||
shadow shadowJar
|
||||
|
@@ -7,6 +7,10 @@ plugins {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 17
|
||||
|
||||
configurations {
|
||||
testJar
|
||||
}
|
||||
|
||||
minecraft {
|
||||
mappings channel: 'official', version: minecraftVersion
|
||||
}
|
||||
@@ -60,6 +64,20 @@ shadowJar {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('copyTestJar', Copy) {
|
||||
from tasks.shadowJar.archiveFile
|
||||
into layout.buildDirectory.dir('testJars')
|
||||
dependsOn reobfShadowJar
|
||||
rename { String fileName ->
|
||||
return 'luckperms-forge.testjar'
|
||||
}
|
||||
}
|
||||
|
||||
artifacts.add('testJar', layout.buildDirectory.dir('testJars')) {
|
||||
builtBy('copyTestJar')
|
||||
}
|
||||
|
||||
|
||||
artifacts {
|
||||
archives shadowJar
|
||||
}
|
||||
|
34
integration-tests/build.gradle
Normal file
34
integration-tests/build.gradle
Normal file
@@ -0,0 +1,34 @@
|
||||
sourceCompatibility = 17
|
||||
targetCompatibility = 17
|
||||
|
||||
test {
|
||||
useJUnitPlatform {
|
||||
if (!project.hasProperty('dockerTests')) {
|
||||
excludeTags 'docker'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://repo.opencollab.dev/maven-releases/' }
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'org.apache.logging.log4j:log4j-core:2.20.0'
|
||||
testImplementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.20.0'
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.1'
|
||||
testImplementation "org.testcontainers:junit-jupiter:1.18.3"
|
||||
testImplementation 'org.mockito:mockito-core:4.11.0'
|
||||
testImplementation 'org.mockito:mockito-junit-jupiter:4.11.0'
|
||||
testImplementation 'org.awaitility:awaitility:4.2.0'
|
||||
|
||||
testImplementation project(path: ':bukkit:loader', configuration: 'testJar')
|
||||
testImplementation project(path: ':fabric', configuration: 'testJar')
|
||||
testImplementation project(path: ':forge:loader', configuration: 'testJar')
|
||||
|
||||
testImplementation 'com.github.steveice10:mcprotocollib:1.20-1'
|
||||
}
|
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.integration;
|
||||
|
||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket;
|
||||
import com.github.steveice10.packetlib.tcp.TcpClientSession;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.testcontainers.containers.BindMode;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.output.Slf4jLogConsumer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Testcontainers
|
||||
public class IntegrationTests {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(IntegrationTests.class);
|
||||
|
||||
@Nested
|
||||
class Bukkit extends Generic {
|
||||
|
||||
@Container
|
||||
private final GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("itzg/minecraft-server"))
|
||||
.withEnv("EULA", "TRUE")
|
||||
.withEnv("TYPE", "PAPER")
|
||||
.withEnv("ONLINE_MODE", "FALSE")
|
||||
.withEnv("LUCKPERMS_DEBUG_LOGINS", "true")
|
||||
.withExposedPorts(25565)
|
||||
.withClasspathResourceMapping("luckperms-bukkit.testjar", "/plugins/LuckPerms.jar", BindMode.READ_ONLY)
|
||||
.withLogConsumer(new Slf4jLogConsumer(LOGGER))
|
||||
.waitingFor(Wait.forLogMessage(".*Done.*", 1).withStartupTimeout(Duration.ofSeconds(120)));
|
||||
|
||||
@Override
|
||||
protected GenericContainer<?> container() {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBukkit() throws IOException, InterruptedException {
|
||||
// ensure the server has started
|
||||
assertTrue(this.container.isRunning());
|
||||
|
||||
// ensure the LuckPerms plugin enabled successfully
|
||||
assertLogsContain("[LuckPerms] Successfully enabled.");
|
||||
|
||||
// create a Minecraft client and login to the server
|
||||
loginWithClient();
|
||||
|
||||
// wait for the player to connect
|
||||
awaitLogsContain("lucko joined the game");
|
||||
|
||||
// ensure the player login was handled by LuckPerms
|
||||
assertLogsContain(
|
||||
"[LuckPerms] Processing pre-login for 9a06e4db-8487-39b2-8751-1d107561d787 - lucko",
|
||||
"[LuckPerms] Processing login for 9a06e4db-8487-39b2-8751-1d107561d787 - lucko"
|
||||
);
|
||||
|
||||
// give player some permissions & enable verbose mode
|
||||
executeServerCommand("lp user lucko permission set minecraft.command.ban");
|
||||
executeServerCommand("lp verbose on minecraft.command.ban");
|
||||
|
||||
// wait for verbose mode to be enabled
|
||||
awaitLogsContain("[LP] Verbose logging enabled");
|
||||
|
||||
// get the client to execute a command
|
||||
executeClientCommand("ban");
|
||||
|
||||
// wait for the verbose results to show up
|
||||
awaitLogsContain("[LP] VB > lucko - minecraft.command.ban - true");
|
||||
|
||||
// disable verbose mode and disconnect the client
|
||||
executeServerCommand("lp verbose off");
|
||||
disconnectClient();
|
||||
|
||||
// wait for verbose to be disabled and the client to leave
|
||||
awaitLogsContain(
|
||||
"[LP] Verbose logging disabled.",
|
||||
"lucko left the game"
|
||||
);
|
||||
|
||||
// stop the server
|
||||
executeServerCommand("stop");
|
||||
|
||||
// ensure the server process stops gracefully
|
||||
await().atMost(30, TimeUnit.SECONDS).until(() -> !this.container.isRunning());
|
||||
|
||||
// ensure the plugin disabled
|
||||
assertLogsContain("[LuckPerms] Goodbye!");
|
||||
|
||||
// check for LuckPerms stack traces in the log output
|
||||
assertFalse(logsContain("at me.lucko.luckperms"), "There seems to be stack traces from LuckPerms in the logs");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class Fabric extends Generic {
|
||||
|
||||
@Container
|
||||
private final GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("itzg/minecraft-server"))
|
||||
.withEnv("EULA", "TRUE")
|
||||
.withEnv("TYPE", "FABRIC")
|
||||
.withEnv("ONLINE_MODE", "FALSE")
|
||||
.withEnv("MODRINTH_PROJECTS", "fabric-api")
|
||||
.withEnv("LUCKPERMS_DEBUG_LOGINS", "true")
|
||||
.withExposedPorts(25565)
|
||||
.withClasspathResourceMapping("luckperms-fabric.testjar", "/mods/LuckPerms.jar", BindMode.READ_ONLY)
|
||||
.withLogConsumer(new Slf4jLogConsumer(LOGGER))
|
||||
.waitingFor(Wait.forLogMessage(".*Done.*", 1).withStartupTimeout(Duration.ofSeconds(120)));
|
||||
|
||||
@Override
|
||||
protected GenericContainer<?> container() {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFabric() throws IOException, InterruptedException {
|
||||
// ensure the server has started
|
||||
assertTrue(this.container.isRunning());
|
||||
|
||||
// ensure the LuckPerms plugin enabled successfully
|
||||
assertLogsContain("Successfully enabled.");// assertLogsContain("[LuckPerms] Successfully enabled.");
|
||||
|
||||
// create a Minecraft client and login to the server
|
||||
loginWithClient();
|
||||
|
||||
// wait for the player to connect
|
||||
//awaitLogsContain("lucko joined the game");
|
||||
|
||||
// ensure the player login was handled by LuckPerms
|
||||
awaitLogsContain(
|
||||
"Processing pre-login for 9a06e4db-8487-39b2-8751-1d107561d787 - lucko",
|
||||
"Processing login for 9a06e4db-8487-39b2-8751-1d107561d787 - lucko"
|
||||
);
|
||||
|
||||
// give player some permissions & enable verbose mode
|
||||
executeServerCommand("lp user lucko permission set minecraft.command.ban");
|
||||
executeServerCommand("lp verbose on minecraft.command.ban");
|
||||
|
||||
// wait for verbose mode to be enabled
|
||||
awaitLogsContain("[LP] Verbose logging enabled");
|
||||
|
||||
// get the client to execute a command
|
||||
executeClientCommand("ban");
|
||||
|
||||
// wait for the verbose results to show up
|
||||
awaitLogsContain("[LP] VB > lucko - minecraft.command.ban - true");
|
||||
|
||||
// disable verbose mode and disconnect the client
|
||||
executeServerCommand("lp verbose off");
|
||||
disconnectClient();
|
||||
|
||||
// wait for verbose to be disabled and the client to leave
|
||||
awaitLogsContain(
|
||||
"[LP] Verbose logging disabled.",
|
||||
"lucko left the game"
|
||||
);
|
||||
|
||||
// stop the server
|
||||
executeServerCommand("stop");
|
||||
|
||||
// ensure the server process stops gracefully
|
||||
await().atMost(30, TimeUnit.SECONDS).until(() -> !this.container.isRunning());
|
||||
|
||||
// ensure the plugin disabled
|
||||
assertLogsContain("[LuckPerms] Goodbye!");
|
||||
|
||||
// check for LuckPerms stack traces in the log output
|
||||
assertFalse(logsContain("at me.lucko.luckperms"), "There seems to be stack traces from LuckPerms in the logs");
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class Generic {
|
||||
private TcpClientSession client;
|
||||
|
||||
protected abstract GenericContainer<?> container();
|
||||
|
||||
protected boolean logsContain(String... strings) {
|
||||
String logs = container().getLogs();
|
||||
return Arrays.stream(strings).allMatch(logs::contains);
|
||||
}
|
||||
|
||||
protected void assertLogsContain(String... strings) {
|
||||
assertTrue(logsContain(strings), "container logs must contain: " + Arrays.stream(strings).collect(Collectors.joining(", ", "'", "'")));
|
||||
}
|
||||
|
||||
protected void awaitLogsContain(String... strings) {
|
||||
await().atMost(10, TimeUnit.SECONDS).until(() -> logsContain(strings));
|
||||
}
|
||||
|
||||
protected void loginWithClient() {
|
||||
this.client = new TcpClientSession(
|
||||
container().getHost(),
|
||||
container().getFirstMappedPort(),
|
||||
new MinecraftProtocol("lucko")
|
||||
);
|
||||
this.client.connect();
|
||||
}
|
||||
|
||||
protected void disconnectClient() {
|
||||
this.client.disconnect("Disconnecting");
|
||||
}
|
||||
|
||||
protected void executeServerCommand(String command) throws IOException, InterruptedException {
|
||||
assertEquals(0, container().execInContainer("mc-send-to-console", command).getExitCode());
|
||||
}
|
||||
|
||||
protected void executeClientCommand(String command) {
|
||||
// TODO: the other args here are a bit of a mystery but it seems to work
|
||||
this.client.send(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0, new ArrayList<>(), 0, new BitSet()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
14
integration-tests/src/test/resources/log4j2.xml
Normal file
14
integration-tests/src/test/resources/log4j2.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="warn" shutdownHook="disable">
|
||||
<Appenders>
|
||||
<Console name="Console">
|
||||
<PatternLayout pattern="%highlight{[%d{HH:mm:ss} %level]: %msg%n%xEx}"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
|
||||
<Loggers>
|
||||
<Root level="info">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
@@ -40,5 +40,6 @@ include (
|
||||
'velocity',
|
||||
'standalone',
|
||||
'standalone:loader',
|
||||
'standalone:app'
|
||||
'standalone:app',
|
||||
'integration-tests'
|
||||
)
|
||||
|
Reference in New Issue
Block a user