Add opt-in Paper integration tests
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
package com.majinnaibu.bukkitplugins.metropolis;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MetropolisServerIntegrationTest {
|
||||
@Test
|
||||
void runningPaperLoadsMetropolisAndDispatchesItsVersionCommand() throws IOException {
|
||||
try (RconClient rcon = connectToConfiguredServer()) {
|
||||
String installedPlugins = rcon.execute("plugins");
|
||||
String versionResponse = rcon.execute("metropolis");
|
||||
|
||||
assertTrue(installedPlugins.contains("Metropolis"), installedPlugins);
|
||||
assertTrue(versionResponse.contains("Metropolis: version"), versionResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void plotReservationIsPersistedByTheLoadedWorldGuardPlugin() throws IOException {
|
||||
String regionId = "metropolis-it-" + UUID.randomUUID().toString().substring(0, 8);
|
||||
try (RconClient rcon = connectToConfiguredServer()) {
|
||||
String response = rcon.execute("metropolis-plot-reserve " + regionId + " 100 60 100 105 70 105");
|
||||
assertTrue(response.contains("Reserved plot region " + regionId), response);
|
||||
}
|
||||
|
||||
Path serverDirectory = Path.of(requiredEnvironment("METROPOLIS_SERVER_DIR"));
|
||||
String worldName = System.getenv().getOrDefault("METROPOLIS_WORLD", "world");
|
||||
Path regionsFile = serverDirectory.resolve("plugins/WorldGuard/worlds")
|
||||
.resolve(worldName)
|
||||
.resolve("regions.yml");
|
||||
YamlConfiguration regions = YamlConfiguration.loadConfiguration(regionsFile.toFile());
|
||||
|
||||
assertTrue(regions.contains("regions." + regionId), "WorldGuard did not persist region " + regionId);
|
||||
}
|
||||
|
||||
private static RconClient connectToConfiguredServer() throws IOException {
|
||||
String host = requiredEnvironment("METROPOLIS_RCON_HOST");
|
||||
int port = Integer.parseInt(requiredEnvironment("METROPOLIS_RCON_PORT"));
|
||||
String password = requiredEnvironment("METROPOLIS_RCON_PASSWORD");
|
||||
return new RconClient(host, port, password);
|
||||
}
|
||||
|
||||
private static String requiredEnvironment(String name) {
|
||||
String value = System.getenv(name);
|
||||
if (value == null || value.isBlank()) {
|
||||
throw new IllegalStateException("Set " + name + " to run integrationTest.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static final class RconClient implements AutoCloseable {
|
||||
private final Socket socket = new Socket();
|
||||
private final DataInputStream input;
|
||||
private final DataOutputStream output;
|
||||
private int requestId = 1;
|
||||
|
||||
private RconClient(String host, int port, String password) throws IOException {
|
||||
socket.connect(new InetSocketAddress(host, port), 5000);
|
||||
socket.setSoTimeout(5000);
|
||||
input = new DataInputStream(socket.getInputStream());
|
||||
output = new DataOutputStream(socket.getOutputStream());
|
||||
int authId = requestId++;
|
||||
Packet response = send(authId, 3, password);
|
||||
if (response.id != authId) {
|
||||
throw new IOException("RCON authentication failed.");
|
||||
}
|
||||
}
|
||||
|
||||
private String execute(String command) throws IOException {
|
||||
return send(requestId++, 2, command).payload;
|
||||
}
|
||||
|
||||
private Packet send(int id, int type, String payload) throws IOException {
|
||||
byte[] data = payload.getBytes(StandardCharsets.UTF_8);
|
||||
writeLittleEndianInt(data.length + 10);
|
||||
writeLittleEndianInt(id);
|
||||
writeLittleEndianInt(type);
|
||||
output.write(data);
|
||||
output.writeByte(0);
|
||||
output.writeByte(0);
|
||||
output.flush();
|
||||
|
||||
int length = readLittleEndianInt();
|
||||
byte[] packet = input.readNBytes(length);
|
||||
if (packet.length != length || length < 10) {
|
||||
throw new IOException("Received an invalid RCON packet.");
|
||||
}
|
||||
int responseId = littleEndianInt(packet, 0);
|
||||
String response = new String(packet, 8, length - 10, StandardCharsets.UTF_8);
|
||||
return new Packet(responseId, response);
|
||||
}
|
||||
|
||||
private void writeLittleEndianInt(int value) throws IOException {
|
||||
output.writeInt(Integer.reverseBytes(value));
|
||||
}
|
||||
|
||||
private int readLittleEndianInt() throws IOException {
|
||||
return Integer.reverseBytes(input.readInt());
|
||||
}
|
||||
|
||||
private static int littleEndianInt(byte[] bytes, int offset) {
|
||||
return (bytes[offset] & 0xff)
|
||||
| ((bytes[offset + 1] & 0xff) << 8)
|
||||
| ((bytes[offset + 2] & 0xff) << 16)
|
||||
| (bytes[offset + 3] << 24);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
private record Packet(int id, String payload) {}
|
||||
}
|
||||
Reference in New Issue
Block a user