From 00bddb17cf3a4a8a257511b10d685bb82b83271f Mon Sep 17 00:00:00 2001 From: Simon Lemay Date: Wed, 21 Jul 2021 15:01:25 -0400 Subject: [PATCH 1/4] Add some basic UTPTranport tests --- .../Runtime/UTPTransport.cs | 10 +- .../Tests/Editor/BasicUTPTest.cs | 27 ------ .../Tests/Editor/UTPTransportTests.cs | 97 +++++++++++++++++++ ...Test.cs.meta => UTPTransportTests.cs.meta} | 2 +- 4 files changed, 104 insertions(+), 32 deletions(-) delete mode 100644 com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs create mode 100644 com.unity.multiplayer.transport.utp/Tests/Editor/UTPTransportTests.cs rename com.unity.multiplayer.transport.utp/Tests/Editor/{BasicUTPTest.cs.meta => UTPTransportTests.cs.meta} (83%) diff --git a/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs b/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs index ab53839f2e..bd84406107 100644 --- a/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs +++ b/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs @@ -481,17 +481,20 @@ public override void Shutdown() public override SocketTasks StartClient() { - var task = SocketTask.Working; + if (m_Driver.IsCreated) + return SocketTask.Fault.AsTasks(); + var task = SocketTask.Working; StartCoroutine(ClientBindAndConnect(task)); - return task.AsTasks(); } public override SocketTasks StartServer() { - var task = SocketTask.Working; + if (m_Driver.IsCreated) + return SocketTask.Fault.AsTasks(); + var task = SocketTask.Working; switch (m_ProtocolType) { case ProtocolType.UnityTransport: @@ -501,7 +504,6 @@ public override SocketTasks StartServer() StartCoroutine(StartRelayServer(task)); break; } - return task.AsTasks(); } } diff --git a/com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs b/com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs deleted file mode 100644 index 40fabf1933..0000000000 --- a/com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.TestTools; -using NUnit.Framework; -using Unity.Networking.Transport; -using MLAPI.Transports; - -namespace MLAPI.UTP.RuntimeTests -{ - public class BasicUTPTest : MonoBehaviour - { - [Test] - public void BasicUTPInitializationTest() - { - var o = new GameObject(); - var utpTransport = (UTPTransport)o.AddComponent(typeof(UTPTransport)); - utpTransport.Init(); - - Assert.True(utpTransport.ServerClientId == 0); - - utpTransport.Shutdown(); - } - } -} - - diff --git a/com.unity.multiplayer.transport.utp/Tests/Editor/UTPTransportTests.cs b/com.unity.multiplayer.transport.utp/Tests/Editor/UTPTransportTests.cs new file mode 100644 index 0000000000..dbfabf0dfa --- /dev/null +++ b/com.unity.multiplayer.transport.utp/Tests/Editor/UTPTransportTests.cs @@ -0,0 +1,97 @@ +using NUnit.Framework; + +using MLAPI.Transports; +using MLAPI.Transports.Tasks; +using Unity.Networking.Transport; +using UnityEngine; +using UnityEngine.TestTools; + +namespace MLAPI.UTP.EditorTests +{ + public class UTPTransportTests + { + // Check that starting a server doesn't immediately result in faulted tasks. + [Test] + public void BasicInitServer() + { + UTPTransport transport = new GameObject().AddComponent(); + transport.Init(); + + var tasks = transport.StartServer(); + Assert.False(tasks.IsDone && !tasks.Success); + + transport.Shutdown(); + } + + // Check that starting a client doesn't immediately result in faulted tasks. + [Test] + public void BasicInitClient() + { + UTPTransport transport = new GameObject().AddComponent(); + transport.Init(); + + var tasks = transport.StartClient(); + Assert.False(tasks.IsDone && !tasks.Success); + + transport.Shutdown(); + } + + // Check that we can't restart a server. + [Test] + public void NoRestartServer() + { + UTPTransport transport = new GameObject().AddComponent(); + transport.Init(); + + transport.StartServer(); + var tasks = transport.StartServer(); + Assert.True(tasks.IsDone && !tasks.AnySuccess); + + transport.Shutdown(); + } + + // Check that we can't restart a client. + [Test] + public void NoRestartClient() + { + UTPTransport transport = new GameObject().AddComponent(); + transport.Init(); + + transport.StartClient(); + var tasks = transport.StartClient(); + Assert.True(tasks.IsDone && !tasks.AnySuccess); + + transport.Shutdown(); + } + + // Check that we can't start both a server and client on the same transport. + [Test] + public void NotBothServerAndClient() + { + UTPTransport transport; + SocketTasks tasks; + + // Start server then client. + transport = new GameObject().AddComponent(); + transport.Init(); + + transport.StartServer(); + tasks = transport.StartClient(); + Assert.True(tasks.IsDone && !tasks.AnySuccess); + + transport.Shutdown(); + + // Start client then server. + transport = new GameObject().AddComponent(); + transport.Init(); + + transport.StartClient(); + tasks = transport.StartServer(); + Assert.True(tasks.IsDone && !tasks.AnySuccess); + + transport.Shutdown(); + } + } +} + + diff --git a/com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs.meta b/com.unity.multiplayer.transport.utp/Tests/Editor/UTPTransportTests.cs.meta similarity index 83% rename from com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs.meta rename to com.unity.multiplayer.transport.utp/Tests/Editor/UTPTransportTests.cs.meta index b984108d7f..0f68020ec5 100644 --- a/com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs.meta +++ b/com.unity.multiplayer.transport.utp/Tests/Editor/UTPTransportTests.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4d51a9ee9a7131d47acc9ecb8c99dd65 +guid: 1559305d14837ed449c15c194aff6e6b MonoImporter: externalObjects: {} serializedVersion: 2 From 9c62068bc31c32fbedee19dc41d07388d379cd95 Mon Sep 17 00:00:00 2001 From: Simon Lemay Date: Thu, 22 Jul 2021 13:52:50 -0400 Subject: [PATCH 2/4] Implement OnDestroy in UTPTransport The implementation is the same as Shutdown, meaning it only disposes of the driver (if not already disposed of). The driver (!) for this change is to avoid leaking resources when tests fail. --- .../Runtime/UTPTransport.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs b/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs index bd84406107..528dac0219 100644 --- a/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs +++ b/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs @@ -367,6 +367,11 @@ private void Update() } + private void OnDestroy() + { + DisposeDriver(); + } + private static unsafe ulong ParseClientId(NetworkConnection utpConnectionId) { return *(ulong*)&utpConnectionId; @@ -474,11 +479,6 @@ public override void Send(ulong clientId, ArraySegment data, NetworkChanne Debug.LogError("Error sending the message"); } - public override void Shutdown() - { - DisposeDriver(); - } - public override SocketTasks StartClient() { if (m_Driver.IsCreated) @@ -506,5 +506,10 @@ public override SocketTasks StartServer() } return task.AsTasks(); } + + public override void Shutdown() + { + DisposeDriver(); + } } } From b80aaa42e5442c08540d1cb822c64153f460e455 Mon Sep 17 00:00:00 2001 From: Simon Lemay Date: Fri, 23 Jul 2021 00:09:53 -0400 Subject: [PATCH 3/4] Add connection tests for UTPTransport --- .../Runtime/UTPTransport.cs | 4 +- .../Tests/Runtime/ConnectionTests.cs | 292 ++++++++++++++++++ .../Tests/Runtime/ConnectionTests.cs.meta | 11 + .../Tests/Runtime/Helpers.meta | 8 + .../Runtime/Helpers/RuntimeTestsHelpers.cs | 85 +++++ .../Helpers/RuntimeTestsHelpers.cs.meta | 11 + ...tiplayer.transport.utp.runtimetests.asmdef | 2 +- 7 files changed, 409 insertions(+), 4 deletions(-) create mode 100644 com.unity.multiplayer.transport.utp/Tests/Runtime/ConnectionTests.cs create mode 100644 com.unity.multiplayer.transport.utp/Tests/Runtime/ConnectionTests.cs.meta create mode 100644 com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers.meta create mode 100644 com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers/RuntimeTestsHelpers.cs create mode 100644 com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers/RuntimeTestsHelpers.cs.meta diff --git a/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs b/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs index 528dac0219..c14fbaf1af 100644 --- a/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs +++ b/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs @@ -402,9 +402,7 @@ public override void DisconnectLocalClient() public override void DisconnectRemoteClient(ulong clientId) { - Debug.Assert(m_State == State.Connected, "DisconnectRemoteClient should be called on a listening server"); - - Debug.Log("Disconnecting"); + Debug.Assert(m_State == State.Listening, "DisconnectRemoteClient should be called on a listening server"); if (m_State == State.Listening) { diff --git a/com.unity.multiplayer.transport.utp/Tests/Runtime/ConnectionTests.cs b/com.unity.multiplayer.transport.utp/Tests/Runtime/ConnectionTests.cs new file mode 100644 index 0000000000..b88f5d92ce --- /dev/null +++ b/com.unity.multiplayer.transport.utp/Tests/Runtime/ConnectionTests.cs @@ -0,0 +1,292 @@ +using NUnit.Framework; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +using MLAPI.Transports; +using UnityEngine; +using UnityEngine.TestTools; + +namespace MLAPI.UTP.RuntimeTests +{ + using static RuntimeTestsHelpers; + + public class ConnectionTests + { + // For tests using multiple clients. + private const int NumClients = 5; + + // Check connection with a single client. + [UnityTest] + public IEnumerator ConnectSingleClient() + { + UTPTransport server, client; + List serverEvents, clientEvents; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client, out clientEvents); + + server.StartServer(); + client.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + // Check we've received Connect event on client too. + Assert.AreEqual(1, clientEvents.Count); + Assert.AreEqual(NetworkEvent.Connect, clientEvents[0].Type); + + server.Shutdown(); + client.Shutdown(); + + yield return null; + } + + // Check connection with multiple clients. + [UnityTest] + public IEnumerator ConnectMultipleClients() + { + UTPTransport server; + var clients = new UTPTransport[NumClients]; + + List serverEvents; + var clientsEvents = new List[NumClients]; + + InitializeTransport(out server, out serverEvents); + server.StartServer(); + + for (int i = 0; i < NumClients; i++) + { + InitializeTransport(out clients[i], out clientsEvents[i]); + clients[i].StartClient(); + } + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + // Check that every client also received a Connect event. + Assert.True(clientsEvents.All(evs => evs.Count == 1)); + Assert.True(clientsEvents.All(evs => evs[0].Type == NetworkEvent.Connect)); + + server.Shutdown(); + for (int i = 0; i < NumClients; i++) + clients[i].Shutdown(); + + yield return null; + } + + // Check server disconnection with a single client. + [UnityTest] + public IEnumerator ServerDisconnectSingleClient() + { + UTPTransport server, client; + List serverEvents, clientEvents; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client, out clientEvents); + + server.StartServer(); + client.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + server.DisconnectRemoteClient(serverEvents[0].ClientID); + + yield return WaitForNetworkEvent(NetworkEvent.Disconnect, clientEvents); + + server.Shutdown(); + client.Shutdown(); + + yield return null; + } + + // Check server disconnection with multiple clients. + [UnityTest] + public IEnumerator ServerDisconnectMultipleClients() + { + UTPTransport server; + var clients = new UTPTransport[NumClients]; + + List serverEvents; + var clientsEvents = new List[NumClients]; + + InitializeTransport(out server, out serverEvents); + server.StartServer(); + + for (int i = 0; i < NumClients; i++) + { + InitializeTransport(out clients[i], out clientsEvents[i]); + clients[i].StartClient(); + } + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + // Disconnect a single client. + server.DisconnectRemoteClient(serverEvents[0].ClientID); + + // Need to manually wait since we don't know which client will get the Disconnect. + yield return new WaitForSeconds(MaxNetworkEventWaitTime); + + // Check that we received a Disconnect event on only one client. + Assert.AreEqual(1, clientsEvents.Count(evs => evs.Count == 2 && evs[1].Type == NetworkEvent.Disconnect)); + + // Disconnect all the other clients. + for (int i = 1; i < NumClients; i++) + server.DisconnectRemoteClient(serverEvents[i].ClientID); + + // Need to manually wait since we don't know which client will got the Disconnect. + yield return new WaitForSeconds(MaxNetworkEventWaitTime); + + // Check that all clients got a Disconnect event. + Assert.True(clientsEvents.All(evs => evs.Count == 2)); + Assert.True(clientsEvents.All(evs => evs[1].Type == NetworkEvent.Disconnect)); + + server.Shutdown(); + for (int i = 0; i < NumClients; i++) + clients[i].Shutdown(); + + yield return null; + } + + // Check client disconnection from a single client. + [UnityTest] + public IEnumerator ClientDisconnectSingleClient() + { + UTPTransport server, client; + List serverEvents, clientEvents; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client, out clientEvents); + + server.StartServer(); + client.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + client.DisconnectLocalClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Disconnect, serverEvents); + + server.Shutdown(); + client.Shutdown(); + + yield return null; + } + + // Check client disconnection with multiple clients. + [UnityTest] + public IEnumerator ClientDisconnectMultipleClients() + { + UTPTransport server; + var clients = new UTPTransport[NumClients]; + + List serverEvents; + var clientsEvents = new List[NumClients]; + + InitializeTransport(out server, out serverEvents); + server.StartServer(); + + for (int i = 0; i < NumClients; i++) + { + InitializeTransport(out clients[i], out clientsEvents[i]); + clients[i].StartClient(); + } + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + // Disconnect a single client. + clients[0].DisconnectLocalClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Disconnect, serverEvents); + + // Disconnect all the other clients. + for (int i = 1; i < NumClients; i++) + clients[i].DisconnectLocalClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Disconnect, serverEvents); + + // Check that we got the correct number of Disconnect events on the server. + Assert.AreEqual(NumClients * 2, serverEvents.Count); + Assert.AreEqual(NumClients, serverEvents.Count(e => e.Type == NetworkEvent.Disconnect)); + + server.Shutdown(); + for (int i = 0; i < NumClients; i++) + clients[i].Shutdown(); + + yield return null; + } + + // Check that server re-disconnects are no-ops. + [UnityTest] + public IEnumerator RepeatedServerDisconnectsNoop() + { + UTPTransport server, client; + List serverEvents, clientEvents; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client, out clientEvents); + + server.StartServer(); + client.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + server.DisconnectRemoteClient(serverEvents[0].ClientID); + + yield return WaitForNetworkEvent(NetworkEvent.Disconnect, clientEvents); + + var previousServerEventsCount = serverEvents.Count; + var previousClientEventsCount = clientEvents.Count; + + server.DisconnectRemoteClient(serverEvents[0].ClientID); + + // Need to wait manually since no event should be generated. + yield return new WaitForSeconds(MaxNetworkEventWaitTime); + + // Check we haven't received anything else on the client or server. + Assert.AreEqual(serverEvents.Count, previousServerEventsCount); + Assert.AreEqual(clientEvents.Count, previousClientEventsCount); + + server.Shutdown(); + client.Shutdown(); + + yield return null; + } + + // Check that client re-disconnects are no-ops. + [UnityTest] + public IEnumerator RepeatedClientDisconnectsNoop() + { + UTPTransport server, client; + List serverEvents, clientEvents; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client, out clientEvents); + + server.StartServer(); + client.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + client.DisconnectLocalClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Disconnect, serverEvents); + + var previousServerEventsCount = serverEvents.Count; + var previousClientEventsCount = clientEvents.Count; + + client.DisconnectLocalClient(); + + // Need to wait manually since no event should be generated. + yield return new WaitForSeconds(MaxNetworkEventWaitTime); + + // Check we haven't received anything else on the client or server. + Assert.AreEqual(serverEvents.Count, previousServerEventsCount); + Assert.AreEqual(clientEvents.Count, previousClientEventsCount); + + server.Shutdown(); + client.Shutdown(); + + yield return null; + } + } +} diff --git a/com.unity.multiplayer.transport.utp/Tests/Runtime/ConnectionTests.cs.meta b/com.unity.multiplayer.transport.utp/Tests/Runtime/ConnectionTests.cs.meta new file mode 100644 index 0000000000..18635a6b14 --- /dev/null +++ b/com.unity.multiplayer.transport.utp/Tests/Runtime/ConnectionTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e1692ce08a2f72e459680dc1524327a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers.meta b/com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers.meta new file mode 100644 index 0000000000..27015e3540 --- /dev/null +++ b/com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc69b0a277c4d024eb9f7813ad4db7d1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers/RuntimeTestsHelpers.cs b/com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers/RuntimeTestsHelpers.cs new file mode 100644 index 0000000000..298f812fe8 --- /dev/null +++ b/com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers/RuntimeTestsHelpers.cs @@ -0,0 +1,85 @@ +using NUnit.Framework; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +using MLAPI.Transports; +using UnityEngine; +using UnityEngine.TestTools; + +namespace MLAPI.UTP.RuntimeTests +{ + public static class RuntimeTestsHelpers + { + // 50ms should be plenty enough for any network interaction to occur (even roundtrips). + public const float MaxNetworkEventWaitTime = 0.05f; + + // Wait for an event to appear in the given event list (must be the very next event). + public static IEnumerator WaitForNetworkEvent(NetworkEvent type, List events) + { + int initialCount = events.Count; + float startTime = Time.realtimeSinceStartup; + + while (Time.realtimeSinceStartup - startTime < MaxNetworkEventWaitTime) + { + if (events.Count > initialCount) + { + Assert.AreEqual(type, events[initialCount].Type); + yield break; + } + + yield return null; + } + + Assert.Fail("Timed out while waiting for network event."); + } + + // Common code to initialize a UTPTransport that logs its events. + public static void InitializeTransport(out UTPTransport transport, out List events) + { + var logger = new TransportEventLogger(); + events = logger.Events; + + transport = new GameObject().AddComponent(); + transport.OnTransportEvent += logger.HandleEvent; + transport.Init(); + } + + // Information about an event generated by a transport (basically just the parameters that + // are normally passed along to a TransportEventDelegate). + public struct TransportEvent + { + public NetworkEvent Type; + public ulong ClientID; + public NetworkChannel Channel; + public ArraySegment Data; + public float ReceiveTime; + } + + // Utility class that logs events generated by a UTPTransport. Set it up by adding the + // HandleEvent method as an OnTransportEvent delegate of the transport. The list of events + // (in order in which they were generated) can be accessed through the Events property. + public class TransportEventLogger + { + private readonly List m_Events = new List(); + public List Events => m_Events; + + public void HandleEvent(NetworkEvent type, ulong clientID, NetworkChannel channel, ArraySegment data, float receiveTime) + { + // Copy the data since the backing array will be reused for future messages. + if (data != default(ArraySegment)) + data = new ArraySegment(data.ToArray()); + + m_Events.Add(new TransportEvent + { + Type = type, + ClientID = clientID, + Channel = channel, + Data = data, + ReceiveTime = receiveTime + }); + } + } + } +} diff --git a/com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers/RuntimeTestsHelpers.cs.meta b/com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers/RuntimeTestsHelpers.cs.meta new file mode 100644 index 0000000000..9943be2562 --- /dev/null +++ b/com.unity.multiplayer.transport.utp/Tests/Runtime/Helpers/RuntimeTestsHelpers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9e62c313ec32744c810875f6738b767 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.multiplayer.transport.utp/Tests/Runtime/com.unity.multiplayer.transport.utp.runtimetests.asmdef b/com.unity.multiplayer.transport.utp/Tests/Runtime/com.unity.multiplayer.transport.utp.runtimetests.asmdef index 16811cc2b1..0683d67241 100644 --- a/com.unity.multiplayer.transport.utp/Tests/Runtime/com.unity.multiplayer.transport.utp.runtimetests.asmdef +++ b/com.unity.multiplayer.transport.utp/Tests/Runtime/com.unity.multiplayer.transport.utp.runtimetests.asmdef @@ -5,7 +5,7 @@ "Unity.Multiplayer.MLAPI.Runtime", "UnityEngine.TestRunner", "UnityEditor.TestRunner", - "Unity MLAPI Transport", + "Unity.Multiplayer.Transport.UTP", "Unity.Networking.Transport" ], "includePlatforms": [], From bbf3ec87b6a0b115180e92a890480de12d5533c2 Mon Sep 17 00:00:00 2001 From: Simon Lemay Date: Fri, 23 Jul 2021 13:17:57 -0400 Subject: [PATCH 4/4] Add basic data transmission tests for UTPTransport --- .../Tests/Runtime/TransportTests.cs | 216 ++++++++++++++++++ .../Tests/Runtime/TransportTests.cs.meta | 11 + 2 files changed, 227 insertions(+) create mode 100644 com.unity.multiplayer.transport.utp/Tests/Runtime/TransportTests.cs create mode 100644 com.unity.multiplayer.transport.utp/Tests/Runtime/TransportTests.cs.meta diff --git a/com.unity.multiplayer.transport.utp/Tests/Runtime/TransportTests.cs b/com.unity.multiplayer.transport.utp/Tests/Runtime/TransportTests.cs new file mode 100644 index 0000000000..4990e46c2b --- /dev/null +++ b/com.unity.multiplayer.transport.utp/Tests/Runtime/TransportTests.cs @@ -0,0 +1,216 @@ +using NUnit.Framework; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using MLAPI.Transports; +using UnityEngine; +using UnityEngine.TestTools; + +namespace MLAPI.UTP.RuntimeTests +{ + using static RuntimeTestsHelpers; + + public class TransportTests + { + // Check if can make a simple data exchange. + [UnityTest] + public IEnumerator PingPong() + { + UTPTransport server, client; + List serverEvents, clientEvents; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client, out clientEvents); + + server.StartServer(); + client.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + var ping = new ArraySegment(Encoding.ASCII.GetBytes("ping")); + client.Send(client.ServerClientId, ping, NetworkChannel.Internal); + + yield return WaitForNetworkEvent(NetworkEvent.Data, serverEvents); + + Assert.That(serverEvents[1].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("ping"))); + + var pong = new ArraySegment(Encoding.ASCII.GetBytes("pong")); + server.Send(serverEvents[0].ClientID, pong, NetworkChannel.Internal); + + yield return WaitForNetworkEvent(NetworkEvent.Data, clientEvents); + + Assert.That(clientEvents[1].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("pong"))); + + server.Shutdown(); + client.Shutdown(); + + yield return null; + } + + // Check if can make a simple data exchange (both ways at a time). + [UnityTest] + public IEnumerator PingPongSimultaneous() + { + UTPTransport server, client; + List serverEvents, clientEvents; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client, out clientEvents); + + server.StartServer(); + client.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + var ping = new ArraySegment(Encoding.ASCII.GetBytes("ping")); + server.Send(serverEvents[0].ClientID, ping, NetworkChannel.Internal); + client.Send(client.ServerClientId, ping, NetworkChannel.Internal); + + // Once one event is in the other should be too. + yield return WaitForNetworkEvent(NetworkEvent.Data, serverEvents); + + Assert.That(serverEvents[1].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("ping"))); + Assert.That(clientEvents[1].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("ping"))); + + var pong = new ArraySegment(Encoding.ASCII.GetBytes("pong")); + server.Send(serverEvents[0].ClientID, pong, NetworkChannel.Internal); + client.Send(client.ServerClientId, pong, NetworkChannel.Internal); + + // Once one event is in the other should be too. + yield return WaitForNetworkEvent(NetworkEvent.Data, serverEvents); + + Assert.That(serverEvents[2].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("pong"))); + Assert.That(clientEvents[2].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("pong"))); + + server.Shutdown(); + client.Shutdown(); + + yield return null; + } + + // Check making multiple sends to a client in a single frame. + [UnityTest] + public IEnumerator MultipleSendsSingleFrame() + { + UTPTransport server, client; + List serverEvents, clientEvents; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client, out clientEvents); + + server.StartServer(); + client.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + var data1 = new ArraySegment(new byte [] { 11 }); + client.Send(client.ServerClientId, data1, NetworkChannel.Internal); + + var data2 = new ArraySegment(new byte [] { 22 }); + client.Send(client.ServerClientId, data2, NetworkChannel.Internal); + + yield return WaitForNetworkEvent(NetworkEvent.Data, serverEvents); + + Assert.AreEqual(3, serverEvents.Count); + Assert.AreEqual(NetworkEvent.Data, serverEvents[2].Type); + + Assert.AreEqual(11, serverEvents[1].Data.First()); + Assert.AreEqual(22, serverEvents[2].Data.First()); + + server.Shutdown(); + client.Shutdown(); + + yield return null; + } + + // Check sending data to multiple clients. + [UnityTest] + public IEnumerator SendMultipleClients() + { + UTPTransport server, client1, client2; + List serverEvents, client1Events, client2Events; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client1, out client1Events); + InitializeTransport(out client2, out client2Events); + + server.StartServer(); + client1.StartClient(); + client2.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, serverEvents); + + // Ensure we got both Connect events. + Assert.AreEqual(2, serverEvents.Count); + + var data1 = new ArraySegment(new byte [] { 11 }); + server.Send(serverEvents[0].ClientID, data1, NetworkChannel.Internal); + + var data2 = new ArraySegment(new byte [] { 22 }); + server.Send(serverEvents[1].ClientID, data2, NetworkChannel.Internal); + + // Once one has received its data, the other should have too. + yield return WaitForNetworkEvent(NetworkEvent.Data, client1Events); + + // Do make sure the other client got its Data event. + Assert.AreEqual(2, client2Events.Count); + Assert.AreEqual(NetworkEvent.Data, client2Events[1].Type); + + byte c1Data = client1Events[1].Data.First(); + byte c2Data = client2Events[1].Data.First(); + Assert.True((c1Data == 11 && c2Data == 22) || (c1Data == 22 && c2Data == 11)); + + server.Shutdown(); + client1.Shutdown(); + client2.Shutdown(); + + yield return null; + } + + // Check receiving data from multiple clients. + [UnityTest] + public IEnumerator ReceiveMultipleClients() + { + UTPTransport server, client1, client2; + List serverEvents, client1Events, client2Events; + + InitializeTransport(out server, out serverEvents); + InitializeTransport(out client1, out client1Events); + InitializeTransport(out client2, out client2Events); + + server.StartServer(); + client1.StartClient(); + client2.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, client1Events); + + // Ensure we got the Connect event on the other client too. + Assert.AreEqual(1, client2Events.Count); + + var data1 = new ArraySegment(new byte [] { 11 }); + client1.Send(client1.ServerClientId, data1, NetworkChannel.Internal); + + var data2 = new ArraySegment(new byte [] { 22 }); + client2.Send(client2.ServerClientId, data2, NetworkChannel.Internal); + + yield return WaitForNetworkEvent(NetworkEvent.Data, serverEvents); + + // Make sure we got both data messages. + Assert.AreEqual(4, serverEvents.Count); + Assert.AreEqual(NetworkEvent.Data, serverEvents[3].Type); + + byte sData1 = serverEvents[2].Data.First(); + byte sData2 = serverEvents[3].Data.First(); + Assert.True((sData1 == 11 && sData2 == 22) || (sData1 == 22 && sData2 == 11)); + + server.Shutdown(); + client1.Shutdown(); + client2.Shutdown(); + + yield return null; + } + } +} diff --git a/com.unity.multiplayer.transport.utp/Tests/Runtime/TransportTests.cs.meta b/com.unity.multiplayer.transport.utp/Tests/Runtime/TransportTests.cs.meta new file mode 100644 index 0000000000..6d81e3bad8 --- /dev/null +++ b/com.unity.multiplayer.transport.utp/Tests/Runtime/TransportTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1c4fedf1be1a7d84ba34595aae75f8da +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: