Update the integration test for Minecraft 1.7.2.

This commit is contained in:
Kristian S. Stangeland 2014-02-02 19:45:40 +01:00
parent 12286ebaa7
commit 8bd177daf5
8 changed files with 191 additions and 68 deletions

View File

@ -11,6 +11,8 @@ import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.simple.SimpleLogger;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
@ -20,6 +22,7 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import com.comphenix.protocol.ProtocolLibrary;
@ -29,6 +32,7 @@ import com.google.common.io.Files;
// Damn final classes ...
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
@PrepareForTest(PluginDescriptionFile.class)
public class SimpleCraftBukkitITCase {
// The fake plugin
@ -50,7 +54,14 @@ public class SimpleCraftBukkitITCase {
@BeforeClass
public static void setupCraftBukkit() throws Exception {
setupPlugins();
org.bukkit.craftbukkit.Main.main(new String[0]);
try {
org.bukkit.craftbukkit.Main.main(new String[0]);
} finally {
System.out.println("Current class loader: " + Thread.currentThread().getContextClassLoader());
System.out.println("Loader of SimpleLogger: " + SimpleLogger.class.getClassLoader());
System.out.println("Loader of Logger: " + Logger.class.getClassLoader());
}
// We need to wait until the server object is ready
while (Bukkit.getServer() == null)
@ -61,12 +72,13 @@ public class SimpleCraftBukkitITCase {
// No need to look for updates
FieldUtils.writeStaticField(ProtocolLibrary.class, "UPDATES_DISABLED", Boolean.TRUE, true);
// Wait until the server and all the plugins have loaded
Bukkit.getScheduler().callSyncMethod(FAKE_PLUGIN, new Callable<Object>() {
@Override
public Object call() throws Exception {
initializePlugin(FAKE_PLUGIN);
ProtocolLibrary.getConfiguration().setDebug(true);
return null;
}
}).get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
@ -98,7 +110,9 @@ public class SimpleCraftBukkitITCase {
int bestLength = Integer.MAX_VALUE;
// Copy the ProtocolLib plugin to the server
Files.deleteDirectoryContents(pluginDirectory);
if (pluginDirectory.exists()) {
Files.deleteDirectoryContents(pluginDirectory);
}
for (File file : new File("../").listFiles()) {
String name = file.getName();
@ -108,6 +122,7 @@ public class SimpleCraftBukkitITCase {
bestFile = file;
}
}
pluginDirectory.mkdirs();
Files.copy(bestFile, new File(pluginDirectory, bestFile.getName()));
}

View File

@ -1,5 +1,8 @@
package com.comphenix.integration.protocol;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
@ -7,24 +10,24 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.Charset;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Charsets;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.utility.StreamSerializer;
import com.google.common.io.ByteStreams;
public class SimpleMinecraftClient {
private static final int CONNECT_TIMEOUT = 2500;
private static final int READ_TIMEOUT = 15000;
// The version after which we must send a plugin message with the host name
private static final String PLUGIN_MESSAGE_VERSION = "1.6.0";
// Current Minecraft version
private final MinecraftVersion version;
private final int protocolVersion;
// Typical Minecraft serializer
private static StreamSerializer serializer = StreamSerializer.getDefault();
public SimpleMinecraftClient(MinecraftVersion version, int protocolVersion) {
this.version = version;
public SimpleMinecraftClient(int protocolVersion) {
this.protocolVersion = protocolVersion;
}
@ -49,9 +52,6 @@ public class SimpleMinecraftClient {
InputStream input = null;
InputStreamReader reader = null;
// UTF-16!
Charset charset = Charsets.UTF_16BE;
try {
socket = new Socket();
socket.connect(address, CONNECT_TIMEOUT);
@ -62,42 +62,20 @@ public class SimpleMinecraftClient {
// Retrieve sockets
output = socket.getOutputStream();
input = socket.getInputStream();
reader = new InputStreamReader(input, charset);
// The output writer
DataOutputStream data = new DataOutputStream(output);
// Request a server information packet
writePacket(data, new HandshakePacket(protocolVersion, address.getHostName(), address.getPort(), 1));
writePacket(data, new RequestPacket());
data.flush();
// Get the server to send a MOTD
output.write(new byte[] { (byte) 0xFE, (byte) 0x01 });
// For 1.6
if (version.compareTo(new MinecraftVersion(PLUGIN_MESSAGE_VERSION)) >= 0) {
DataOutputStream data = new DataOutputStream(output);
String host = address.getHostName();
data.writeByte(0xFA);
writeString(data, "MC|PingHost");
data.writeShort(3 + 2 * host.length() + 4);
data.writeByte(protocolVersion);
writeString(data, host);
data.writeInt(address.getPort());
data.flush();
}
int packetId = input.read();
int length = reader.read();
if (packetId != 255)
throw new IOException("Invalid packet ID: " + packetId);
if (length <= 0)
throw new IOException("Invalid string length.");
char[] chars = new char[length];
// Read all the characters
if (reader.read(chars, 0, length) != length) {
throw new IOException("Premature end of stream.");
}
return new String(chars);
// Read a single packet, and close the connection
SimplePacket packet = readPacket(new DataInputStream(input), Protocol.STATUS);
socket.close();
return ((ResponsePacket) packet).getPingJson();
} finally {
if (reader != null)
@ -111,10 +89,136 @@ public class SimpleMinecraftClient {
}
}
private void writeString(DataOutputStream output, String text) throws IOException {
if (text.length() > 32767)
throw new IOException("String too big: " + text.length());
output.writeShort(text.length());
output.writeChars(text);
private void writePacket(DataOutputStream output, SimplePacket packet) throws IOException {
ByteArrayOutputStream packetBuffer = new ByteArrayOutputStream();
DataOutputStream packetOutput = new DataOutputStream(packetBuffer);
// Prefix the packet with a length field
packet.write(packetOutput);
writeByteArray(output, packetBuffer.toByteArray());
}
private SimplePacket readPacket(DataInputStream input, Protocol protocol) throws IOException {
while (true) {
byte[] buffer = readByteArray(input);
// Skip empty packets
if (buffer.length == 0)
continue;
DataInputStream data = getDataInput(buffer);
PacketType type = PacketType.findCurrent(protocol, Sender.SERVER, serializer.deserializeVarInt(data));
if (type == PacketType.Status.Server.OUT_SERVER_INFO) {
ResponsePacket response = new ResponsePacket();
response.read(type, data);
return response;
} else {
throw new IllegalArgumentException("Unsuppported and unexpected type: " + type);
}
}
}
/**
* Wrap an input stream around a byte array.
* @param bytes - the array.
* @return The wrapped input stream.
*/
private DataInputStream getDataInput(byte[] bytes) {
return new DataInputStream(new ByteArrayInputStream(bytes));
}
/**
* Write a byte array to the output stream, prefixed by a length.
* @param output - the stream.
* @param data - the data to write.
*/
private static void writeByteArray(DataOutputStream output, byte[] data) throws IOException {
StreamSerializer.getDefault().serializeVarInt(output, data.length);
if (data.length > 0) {
output.write(data);
}
}
/**
* Read a byte array from an input stream, prefixed by length.
* @param input - the input stream.
* @return The read byte array.
*/
private static byte[] readByteArray(DataInputStream input) throws IOException {
int length = serializer.deserializeVarInt(input);
byte[] data = new byte[length];
ByteStreams.readFully(input, data);
return data;
}
private static class RequestPacket extends SimplePacket {
public RequestPacket() {
super(PacketType.Status.Client.IN_START);
}
}
private static class ResponsePacket extends SimplePacket {
private String ping;
public ResponsePacket() {
super(PacketType.Status.Server.OUT_SERVER_INFO);
}
@Override
public void read(PacketType type, DataInputStream input) throws IOException {
super.read(type, input);
ping = serializer.deserializeString(input, 32000);
}
public String getPingJson() {
return ping;
}
}
private static class HandshakePacket extends SimplePacket {
private int protocol;
private String host;
private int port;
private int nextState;
public HandshakePacket(int protocol, String host, int port, int nextState) {
super(PacketType.Handshake.Client.SET_PROTOCOL);
this.protocol = protocol;
this.host = host;
this.port = port;
this.nextState = nextState;
}
@Override
public void write(DataOutputStream output) throws IOException {
super.write(output);
serializer.serializeVarInt(output, protocol);
serializer.serializeString(output, host);
output.writeShort(port);
serializer.serializeVarInt(output, nextState);
}
}
private static class SimplePacket {
protected final PacketType type;
protected final StreamSerializer serializer = StreamSerializer.getDefault();
public SimplePacket(PacketType type) {
this.type = type;
}
public void write(DataOutputStream output) throws IOException {
serializer.serializeVarInt(output, type.getCurrentId());
}
public void read(PacketType type, DataInputStream input) throws IOException {
// Note - we don't read the packet id
if (this.type != type) {
throw new IllegalArgumentException("Unexpected type: " + type);
}
}
}
}

View File

@ -10,18 +10,14 @@ import java.util.concurrent.TimeUnit;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.Packets;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.utility.MinecraftVersion;
public class TestPingPacket {
// Current versions
private static final String CRAFTBUKKIT_VERSION = "1.6.2";
private static final int PROTOCOL_VERSION = 74;
private static final int PROTOCOL_VERSION = 4;
// Timeout
private static final int TIMEOUT_PING_MS = 10000;
@ -52,7 +48,7 @@ public class TestPingPacket {
// Make sure it's the same
System.out.println("Server string: " + transmitted);
assertEquals(transmitted, source);
assertEquals(source, transmitted);
} catch (ExecutionException e) {
throw e.getCause();
}
@ -60,10 +56,10 @@ public class TestPingPacket {
private Future<String> testInterception(Plugin test) {
ProtocolLibrary.getProtocolManager().addPacketListener(
new PacketAdapter(test, ConnectionSide.SERVER_SIDE, GamePhase.LOGIN, Packets.Server.KICK_DISCONNECT) {
new PacketAdapter(test, PacketType.Status.Server.OUT_SERVER_INFO) {
@Override
public void onPacketSending(PacketEvent event) {
source = event.getPacket().getStrings().read(0);
source = event.getPacket().getServerPings().read(0).toJson();
}
});
@ -71,8 +67,7 @@ public class TestPingPacket {
return Executors.newSingleThreadExecutor().submit(new Callable<String>() {
@Override
public String call() throws Exception {
SimpleMinecraftClient client = new SimpleMinecraftClient(
new MinecraftVersion(CRAFTBUKKIT_VERSION), PROTOCOL_VERSION);
SimpleMinecraftClient client = new SimpleMinecraftClient(PROTOCOL_VERSION);
String information = client.queryLocalPing();
// Wait for the listener to catch up

View File

@ -41,6 +41,7 @@ import org.bukkit.potion.PotionEffectType;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import com.comphenix.protocol.BukkitInitialization;
@ -50,7 +51,6 @@ import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.injector.PacketConstructor;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.ChunkPosition;
@ -65,6 +65,7 @@ import com.google.common.collect.Lists;
// Ensure that the CraftItemFactory is mockable
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
@PrepareForTest(CraftItemFactory.class)
public class PacketContainerTest {
// Helper converters

View File

@ -18,6 +18,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import com.comphenix.protocol.injector.PluginVerifier.VerificationResult;
import com.google.common.base.Objects;
@ -25,6 +26,7 @@ import com.google.common.collect.Lists;
// Damn final classes
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
@PrepareForTest(PluginDescriptionFile.class)
public class PluginVerifierTest {
@Test

View File

@ -16,6 +16,7 @@ import org.bukkit.inventory.ItemStack;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import com.comphenix.protocol.BukkitInitialization;
@ -23,6 +24,7 @@ import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
@PrepareForTest(CraftItemFactory.class)
public class StreamSerializerTest {
@BeforeClass

View File

@ -8,11 +8,13 @@ import org.bukkit.inventory.ItemStack;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import com.comphenix.protocol.BukkitInitialization;
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
@PrepareForTest(CraftItemFactory.class)
public class WrappedWatchableObjectTest {
@BeforeClass

View File

@ -32,6 +32,7 @@ import org.bukkit.inventory.ItemStack;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import com.comphenix.protocol.BukkitInitialization;
@ -39,6 +40,7 @@ import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
@PrepareForTest(CraftItemFactory.class)
public class NbtFactoryTest {
@BeforeClass