using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Net; using System.Threading; using Hazel.Udp; using System.Net.Sockets; using System.Threading.Tasks; namespace Hazel.UnitTests { [TestClass] public class UnityUdpConnectionTests { private ILogger logger = new ConsoleLogger(true); [TestMethod] public void ServerDisposeDisconnectsTest() { IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 4296); bool serverConnected = false; bool serverDisconnected = false; bool clientDisconnected = false; using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, ep)) { listener.NewConnection += (evt) => { serverConnected = true; evt.Connection.Disconnected += (o, et) => serverDisconnected = true; }; connection.Disconnected += (o, evt) => clientDisconnected = true; listener.Start(); connection.Connect(); Thread.Sleep(100); // Gotta wait for the server to set up the events. listener.Dispose(); Thread.Sleep(100); Assert.IsTrue(serverConnected); Assert.IsTrue(clientDisconnected); Assert.IsFalse(serverDisconnected); } } [TestMethod] public void ClientServerDisposeDisconnectsTest() { IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 4296); bool serverConnected = false; bool serverDisconnected = false; bool clientDisconnected = false; using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, ep)) { listener.NewConnection += (evt) => { serverConnected = true; evt.Connection.Disconnected += (o, et) => serverDisconnected = true; }; connection.Disconnected += (o, et) => clientDisconnected = true; listener.Start(); connection.Connect(); Thread.Sleep(100); // Gotta wait for the server to set up the events. connection.Dispose(); Thread.Sleep(100); Assert.IsTrue(serverConnected); Assert.IsTrue(serverDisconnected); Assert.IsFalse(clientDisconnected); } } /// /// Tests the fields on UdpConnection. /// [TestMethod] public void UdpFieldTest() { IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 4296); using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, ep)) { listener.Start(); connection.Connect(); //Connection fields Assert.AreEqual(ep, connection.EndPoint); //UdpConnection fields Assert.AreEqual(new IPEndPoint(IPAddress.Loopback, 4296), connection.EndPoint); Assert.AreEqual(1, connection.Statistics.DataBytesSent); Assert.AreEqual(0, connection.Statistics.DataBytesReceived); } } [TestMethod] public void UdpHandshakeTest() { byte[] TestData = new byte[] { 1, 2, 3, 4, 5, 6 }; using (ManualResetEventSlim mutex = new ManualResetEventSlim(false)) using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { listener.Start(); MessageReader output = null; listener.NewConnection += delegate (NewConnectionEventArgs e) { output = e.HandshakeData.Duplicate(); mutex.Set(); }; connection.Connect(TestData); mutex.Wait(5000); for (int i = 0; i < TestData.Length; ++i) { Assert.AreEqual(TestData[i], output.ReadByte()); } } } [TestMethod] public void UdpUnreliableMessageSendTest() { byte[] TestData = new byte[] { 1, 2, 3, 4, 5, 6 }; using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { MessageReader output = null; listener.NewConnection += delegate (NewConnectionEventArgs e) { e.Connection.DataReceived += delegate (DataReceivedEventArgs evt) { output = evt.Message; }; }; listener.Start(); connection.Connect(); for (int i = 0; i < 4; ++i) { var msg = MessageWriter.Get(SendOption.None); msg.Write(TestData); connection.Send(msg); msg.Recycle(); } Thread.Sleep(10); for (int i = 0; i < TestData.Length; ++i) { Assert.AreEqual(TestData[i], output.ReadByte()); } } } /// /// Tests IPv4 connectivity. /// [TestMethod] public void UdpIPv4ConnectionTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { listener.Start(); connection.Connect(); } } /// /// Tests dual mode connectivity. /// [TestMethod] public void MixedConnectionTest() { using (UdpConnectionListener listener2 = new UdpConnectionListener(new IPEndPoint(IPAddress.IPv6Any, 4296), IPMode.IPv6)) { listener2.Start(); listener2.NewConnection += (evt) => { Console.WriteLine("v6 connection: " + ((NetworkConnection)evt.Connection).GetIP4Address()); }; using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4296))) { connection.Connect(); Assert.AreEqual(ConnectionState.Connected, connection.State); } using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.IPv6Loopback, 4296), IPMode.IPv6)) { connection.Connect(); Assert.AreEqual(ConnectionState.Connected, connection.State); } } } /// /// Tests IPv4 resilience to non-hello connections. /// [TestMethod] public void FalseConnectionTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { int connects = 0; listener.NewConnection += (obj) => { Interlocked.Increment(ref connects); }; listener.Start(); socket.Bind(new IPEndPoint(IPAddress.Any, 0)); var bytes = new byte[2]; bytes[0] = (byte)32; for (int i = 0; i < 10; ++i) { socket.SendTo(bytes, new IPEndPoint(IPAddress.Loopback, 4296)); } Thread.Sleep(500); Assert.AreEqual(0, connects); } } /// /// Tests IPv4 resilience to multiple hellos. /// [TestMethod] public void ConnectLikeAJerkTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { int connects = 0; listener.NewConnection += (obj) => { Interlocked.Increment(ref connects); }; listener.Start(); socket.Bind(new IPEndPoint(IPAddress.Any, 0)); var bytes = new byte[2]; bytes[0] = (byte)UdpSendOption.Hello; for (int i = 0; i < 10; ++i) { socket.SendTo(bytes, new IPEndPoint(IPAddress.Loopback, 4296)); } Thread.Sleep(500); Assert.AreEqual(1, connects); } } /// /// Tests dual mode connectivity. /// [TestMethod] public void UdpIPv6ConnectionTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.IPv6Any, 4296), IPMode.IPv6)) { listener.Start(); using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4296), IPMode.IPv6)) { connection.Connect(); } } } /// /// Tests server to client unreliable communication on the UdpConnection. /// [TestMethod] public void UdpUnreliableServerToClientTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { TestHelper.RunServerToClientTest(listener, connection, 10, SendOption.None); } } /// /// Tests server to client reliable communication on the UdpConnection. /// [TestMethod] public void UdpReliableServerToClientTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { TestHelper.RunServerToClientTest(listener, connection, 10, SendOption.Reliable); } } /// /// Tests server to client unreliable communication on the UdpConnection. /// [TestMethod] public void UdpUnreliableClientToServerTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { TestHelper.RunClientToServerTest(listener, connection, 10, SendOption.None); } } /// /// Tests server to client reliable communication on the UdpConnection. /// [TestMethod] public void UdpReliableClientToServerTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { TestHelper.RunClientToServerTest(listener, connection, 10, SendOption.Reliable); } } /// /// Tests the keepalive functionality from the client, /// [TestMethod] public void KeepAliveClientTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { listener.Start(); connection.Connect(); connection.KeepAliveInterval = 100; Thread.Sleep(1050); //Enough time for ~10 keep alive packets Assert.AreEqual(ConnectionState.Connected, connection.State); Assert.IsTrue( connection.Statistics.TotalBytesSent >= 30 && connection.Statistics.TotalBytesSent <= 50, "Sent: " + connection.Statistics.TotalBytesSent ); } } /// /// Tests the keepalive functionality from the client, /// [TestMethod] public void KeepAliveServerTest() { ManualResetEvent mutex = new ManualResetEvent(false); using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { UdpConnection client = null; listener.NewConnection += delegate (NewConnectionEventArgs args) { client = (UdpConnection)args.Connection; client.KeepAliveInterval = 100; Thread.Sleep(1050); //Enough time for ~10 keep alive packets mutex.Set(); }; listener.Start(); connection.Connect(); mutex.WaitOne(); Assert.AreEqual(ConnectionState.Connected, client.State); Assert.IsTrue( client.Statistics.TotalBytesSent >= 27 && client.Statistics.TotalBytesSent <= 50, "Sent: " + client.Statistics.TotalBytesSent ); } } /// /// Tests disconnection from the client. /// [TestMethod] public void ClientDisconnectTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { TestHelper.RunClientDisconnectTest(listener, connection); } } /// /// Test that a disconnect is sent when the client is disposed. /// public void ClientDisconnectOnDisposeTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { TestHelper.RunClientDisconnectOnDisposeTest(listener, connection); } } /// /// Tests disconnection from the server. /// [TestMethod] public void ServerDisconnectTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { TestHelper.RunServerDisconnectTest(listener, connection); } } /// /// Tests disconnection from the server. /// [TestMethod] public void ServerExtraDataDisconnectTest() { using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) using (UdpConnection connection = new UnityUdpClientConnection(logger, new IPEndPoint(IPAddress.Loopback, 4296))) { string received = null; ManualResetEvent mutex = new ManualResetEvent(false); connection.Disconnected += delegate (object sender, DisconnectedEventArgs args) { // We don't own the message, we have to read the string now received = args.Message.ReadString(); mutex.Set(); }; listener.NewConnection += delegate (NewConnectionEventArgs args) { // As it turns out, the UdpConnectionListener can have an issue on loopback where the disconnect can happen before the hello confirm // Tossing it on a different thread makes this test more reliable. Perhaps something to think about elsewhere though. Task.Run(async () => { await Task.Delay(1); MessageWriter writer = MessageWriter.Get(SendOption.None); writer.Write("Goodbye"); args.Connection.Disconnect("Testing", writer); }); }; listener.Start(); connection.Connect(); mutex.WaitOne(); Assert.IsNotNull(received); Assert.AreEqual("Goodbye", received); } } } }