diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs index eb2ed8a18d..a584ea61e6 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs @@ -90,10 +90,13 @@ public unsafe void Send(ulong clientId, NetworkDelivery delivery, FastBufferWrit break; } case TypeOfCorruption.CorruptBytes: - batchData.Seek(batchData.Length - 2); - var currentByte = batchData.GetUnsafePtr()[0]; - batchData.WriteByteSafe((byte)(currentByte == 0 ? 1 : 0)); - MessageQueue.Add(batchData.ToArray()); + for (int i = 0; i < 4; i++) + { + var currentByte = batchData.GetUnsafePtr()[i]; + currentByte = (byte)((currentByte + 1) % 255); + batchData.WriteByteSafe(currentByte); + MessageQueue.Add(batchData.ToArray()); + } break; case TypeOfCorruption.Truncated: batchData.Truncate(batchData.Length - 1); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs index 4963e5ea05..b6e7d2a012 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs @@ -51,6 +51,7 @@ public IEnumerator Cleanup() // Need to destroy the GameObject (all assigned components will get destroyed too) UnityEngine.Object.DestroyImmediate(m_Server.gameObject); + m_Server = null; } if (m_Client1) @@ -59,6 +60,7 @@ public IEnumerator Cleanup() // Need to destroy the GameObject (all assigned components will get destroyed too) UnityEngine.Object.DestroyImmediate(m_Client1.gameObject); + m_Client1 = null; } if (m_Client2) @@ -67,6 +69,7 @@ public IEnumerator Cleanup() // Need to destroy the GameObject (all assigned components will get destroyed too) UnityEngine.Object.DestroyImmediate(m_Client2.gameObject); + m_Client2 = null; } m_ServerEvents?.Clear(); m_Client1Events?.Clear(); @@ -317,7 +320,7 @@ public IEnumerator DisconnectOnReliableSendQueueOverflow() m_Server.StartServer(); m_Client1.StartClient(); - yield return WaitForNetworkEvent(NetworkEvent.Connect, m_Client1Events); + yield return WaitForNetworkEvent(NetworkEvent.Connect, m_Client1Events, 5.0f); var serverClientId = m_Client1.ServerClientId; diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/UniversalRpcTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/UniversalRpcTests.cs index 91a61fd4a8..bccb9aae40 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/UniversalRpcTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/UniversalRpcTests.cs @@ -1,5 +1,6 @@ #if !MULTIPLAYER_TOOLS && !NGO_MINIMALPROJECT using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -8,6 +9,7 @@ using Unity.Collections; using Unity.Netcode.TestHelpers.Runtime; using UnityEngine; +using UnityEngine.TestTools; using Object = UnityEngine.Object; using Random = System.Random; @@ -536,6 +538,8 @@ public void SelfRecursiveRpc() internal class UniversalRpcTestsBase : NetcodeIntegrationTest { + public static int YieldCheck = 0; + public const int YieldCycleCount = 10; protected override int NumberOfClients => 2; // TODO: [CmbServiceTests] Adapt to run with the service @@ -560,6 +564,7 @@ protected override NetworkManagerInstatiationMode OnSetIntegrationTestMode() protected override bool m_TearDownIsACoroutine => false; protected GameObject m_ServerObject; + internal NetworkObject ServerNetworkObject; protected override void OnCreatePlayerPrefab() { @@ -568,16 +573,9 @@ protected override void OnCreatePlayerPrefab() protected override void OnServerAndClientsCreated() { - m_ServerObject = new GameObject { name = "Server Object" }; - var networkObject = m_ServerObject.AddComponent(); + m_ServerObject = CreateNetworkObjectPrefab("Server Object"); + ServerNetworkObject = m_ServerObject.GetComponent(); m_ServerObject.AddComponent(); - networkObject.NetworkManagerOwner = m_ServerNetworkManager; - NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject); - m_ServerNetworkManager.AddNetworkPrefab(m_ServerObject); - foreach (var client in m_ClientNetworkManagers) - { - client.AddNetworkPrefab(m_ServerObject); - } } protected override void OnInlineTearDown() @@ -607,7 +605,7 @@ protected override void OnTimeTravelServerAndClientsConnected() WaitForMessageReceivedWithTimeTravel(m_ClientNetworkManagers.ToList()); } - protected UniversalRpcNetworkBehaviour GetPlayerObject(ulong ownerClientId, ulong onClient) + protected UniversalRpcNetworkBehaviour LegacyGetPlayerObject(ulong ownerClientId, ulong onClient) { if (ownerClientId == NetworkManager.ServerClientId && !m_ServerNetworkManager.IsHost) { @@ -623,6 +621,28 @@ protected UniversalRpcNetworkBehaviour GetPlayerObject(ulong ownerClientId, ulon return m_PlayerNetworkObjects[onClient][ownerClientId].GetComponent(); } + internal UniversalRpcNetworkBehaviour GetPlayerObject(ulong ownerClientId, ulong senderClientId) + { + var networkObjectId = 0UL; + + var senderNetworkManager = senderClientId == NetworkManager.ServerClientId ? m_ServerNetworkManager : + m_ClientNetworkManagers.Where((c) => c.LocalClientId == senderClientId).First(); + var ownerNetworkManager = ownerClientId == NetworkManager.ServerClientId ? m_ServerNetworkManager : + m_ClientNetworkManagers.Where((c) => c.LocalClientId == ownerClientId).First(); + + if (ownerClientId == NetworkManager.ServerClientId && !m_ServerNetworkManager.IsHost) + { + networkObjectId = ServerNetworkObject.NetworkObjectId; + } + else + { + networkObjectId = ownerNetworkManager.LocalClient.PlayerObject.NetworkObjectId; + } + + return senderNetworkManager.SpawnManager.SpawnedObjects[networkObjectId].GetComponent(); + } + + #region VERIFY METHODS protected void VerifyLocalReceived(ulong objectOwner, ulong sender, string name, bool verifyReceivedFrom, int expectedReceived = 1) { var obj = GetPlayerObject(objectOwner, sender); @@ -1048,6 +1068,7 @@ public void VerifySentToNotAuthorityWithParams(ulong objectOwner, ulong sender, } VerifySentToNotIdWithParams(objectOwner, sender, receiver, methodName, i, b, f, s); } + #endregion public void RethrowTargetInvocationException(Action action) { @@ -1062,6 +1083,496 @@ public void RethrowTargetInvocationException(Action action) } } + [Timeout(2400000)] // Extended time out + [TestFixture(HostOrServer.DAHost)] + [TestFixture(HostOrServer.Host)] + [TestFixture(HostOrServer.Server)] + internal class UniversalRpcGroupedTests : UniversalRpcTestsBase + { + public enum TestTypes + { + DisallowedOverride, + SenderClientId, + SendingNoOverride, + SendingNoOverrideWithParams, + SendingNoOverrideWithParamsAndRpcParams, + SendingWithTargetOverride, + TestRequireOwnership, + } + + public enum TestTypesC + { + SendingWithGroupNotOverride, + SendingWithGroupOverride, + } + + private enum TestTables + { + ActionTableA, + ActionTableB, + ActionTableC + } + + private Dictionary> m_TestTypeToActionTableA = new Dictionary>(); + private Dictionary> m_TestTypeToActionTableB = new Dictionary>(); + private Dictionary> m_TestTypeToActionTableC = new Dictionary>(); + + private delegate IEnumerator TestTypeHandler(TestTypes testType); + private Dictionary m_TestTypesToTableTypes = new Dictionary(); + private Dictionary> m_TableTypesToTestStartAction = new Dictionary>(); + + + private Dictionary m_TypeToRecipientGroupsTable = new Dictionary(); + + public UniversalRpcGroupedTests(HostOrServer hostOrServer) : base(hostOrServer) + { + InitTestTypeToActionTable(); + } + + private void AddTestTypeA(TestTypes testType, Action action) + { + m_TestTypesToTableTypes.Add(testType, TestTables.ActionTableA); + m_TestTypeToActionTableA.Add(testType, action); + } + + private void AddTestTypeB(TestTypes testType, Action action) + { + m_TestTypesToTableTypes.Add(testType, TestTables.ActionTableB); + m_TestTypeToActionTableB.Add(testType, action); + } + + private void AddTestTypeC(TestTypesC testType, Action action) + { + m_TestTypeToActionTableC.Add(testType, action); + } + + private void InitTestTypeToActionTable() + { + // Create a look up table to know what kind of test table action will be invoked + m_TableTypesToTestStartAction.Add(TestTables.ActionTableA, RunTestTypeA); + m_TableTypesToTestStartAction.Add(TestTables.ActionTableB, RunTestTypeB); + + // Type A action registrations + AddTestTypeA(TestTypes.DisallowedOverride, DisallowedOverride); + AddTestTypeA(TestTypes.SenderClientId, SenderClientId); + AddTestTypeA(TestTypes.SendingNoOverride, SendingNoOverride); + AddTestTypeA(TestTypes.SendingNoOverrideWithParams, SendingNoOverrideWithParams); + AddTestTypeA(TestTypes.SendingNoOverrideWithParamsAndRpcParams, SendingNoOverrideWithParamsAndRpcParams); + AddTestTypeA(TestTypes.TestRequireOwnership, TestRequireOwnership); + + // Type B action registrations + AddTestTypeB(TestTypes.SendingWithTargetOverride, SendingWithTargetOverride); + + // Type C action registrations + AddTestTypeC(TestTypesC.SendingWithGroupOverride, SendingWithGroupOverride); + m_TypeToRecipientGroupsTable.Add(TestTypesC.SendingWithGroupOverride, RecipientGroupsA); + AddTestTypeC(TestTypesC.SendingWithGroupNotOverride, SendingWithGroupNotOverride); + m_TypeToRecipientGroupsTable.Add(TestTypesC.SendingWithGroupNotOverride, RecipientGroupsB); + } + + private Action GetTestTypeActionA(TestTypes testType) + { + if (m_TestTypeToActionTableA.ContainsKey(testType)) + { + return m_TestTypeToActionTableA[testType]; + } + return MockSendA; + } + + private Action GetTestTypeActionB(TestTypes testType) + { + if (m_TestTypeToActionTableB.ContainsKey(testType)) + { + return m_TestTypeToActionTableB[testType]; + } + return MockSendB; + } + + private Action GetTestTypeActionC(TestTypesC testType) + { + if (m_TestTypeToActionTableC.ContainsKey(testType)) + { + return m_TestTypeToActionTableC[testType]; + } + return MockSendC; + } + + [UnityTest] + public IEnumerator RunGroupTestTypes([Values] TestTypes testType) + { + var testTypeToRun = m_TestTypesToTableTypes[testType]; + m_TableTypesToTestStartAction[testTypeToRun].Invoke(testType); + // Provide a small break to test runner in-between each test type + // since they are running all iterations of the legacy test type's + // values. + yield return s_DefaultWaitForTick; + } + + [Timeout(900000)] + [UnityTest] + public IEnumerator RunGroupWithGroupOverridesTestTypes([Values] TestTypesC testType, [Values(SendTo.Everyone, SendTo.Me, SendTo.Owner, SendTo.Server, SendTo.NotMe, SendTo.NotOwner, SendTo.NotServer, SendTo.ClientsAndHost)] SendTo sendTo) + { + RunTestTypeC(testType, sendTo); + + // Provide a small break to test runner in-between each test type + // since they are running all iterations of the legacy test type's + // values. + yield return s_DefaultWaitForTick; + } + + #region TYPE-A Tests + + private void RunTestTypeA(TestTypes testType) + { + var sendToValues = new List() { SendTo.Everyone, SendTo.Me, SendTo.Owner, SendTo.Server, SendTo.NotMe, SendTo.NotOwner, SendTo.NotServer, SendTo.ClientsAndHost }; + var numberOfClientsULong = (ulong)NumberOfClients; + var actionToInvoke = GetTestTypeActionA(testType); + try + { + foreach (var sendTo in sendToValues) + { + UnityEngine.Debug.Log($"[{testType}][{sendTo}]"); + for (ulong objectOwner = 0; objectOwner <= numberOfClientsULong; objectOwner++) + { + for (ulong sender = 0; sender <= numberOfClientsULong; sender++) + { + actionToInvoke.Invoke(sendTo, objectOwner, sender); + Clear(); + MockTransport.ClearQueues(); + } + } + } + } + catch (Exception ex) + { + Assert.Fail($"Threw Exception:{ex.Message}!\n{ex.StackTrace}"); + } + } + + /// + /// Invoked if a does not have an action yet for this action. + /// + private void MockSendA(SendTo sendTo, ulong objectOwner, ulong sender) + { + } + private void SenderClientId(SendTo sendTo, ulong objectOwner, ulong sender) + { + var sendMethodName = $"DefaultTo{sendTo}WithRpcParamsRpc"; + var verifyMethodName = $"VerifySentTo{sendTo}WithReceivedFrom"; + + var senderObject = GetPlayerObject(objectOwner, sender); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { new RpcParams() }); + + var verifyMethod = GetType().GetMethod(verifyMethodName); + verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); + } + + private void DisallowedOverride(SendTo sendTo, ulong objectOwner, ulong sender) + { + var senderObject = GetPlayerObject(objectOwner, sender); + var methodName = $"DefaultTo{sendTo}WithRpcParamsRpc"; + var method = senderObject.GetType().GetMethod(methodName); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.Everyone }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.Owner }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.NotOwner }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.Server }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.NotServer }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.ClientsAndHost }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.Me }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.NotMe }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.Single(0, RpcTargetUse.Temp) }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.Not(0, RpcTargetUse.Temp) }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.Group(new[] { 0ul, 1ul, 2ul }, RpcTargetUse.Temp) }))); + Assert.Throws(() => RethrowTargetInvocationException(() => method.Invoke(senderObject, new object[] { (RpcParams)senderObject.RpcTarget.Not(new[] { 0ul, 1ul, 2ul }, RpcTargetUse.Temp) }))); + } + + private void SendingNoOverride(SendTo sendTo, ulong objectOwner, ulong sender) + { + var sendMethodName = $"DefaultTo{sendTo}Rpc"; + var verifyMethodName = $"VerifySentTo{sendTo}"; + + var senderObject = GetPlayerObject(objectOwner, sender); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { }); + + var verifyMethod = GetType().GetMethod(verifyMethodName); + verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); + } + + private void SendingNoOverrideWithParams(SendTo sendTo, ulong objectOwner, ulong sender) + { + var rand = new Random(); + var i = rand.Next(); + var f = (float)rand.NextDouble(); + var b = rand.Next() % 2 == 1; + var s = ""; + var numChars = rand.Next() % 5 + 5; + const string chars = "abcdefghijklmnopqrstuvwxycABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+[]{}\\|;':\",./<>?"; + for (var j = 0; j < numChars; ++j) + { + s += chars[rand.Next(chars.Length)]; + } + + var sendMethodName = $"DefaultTo{sendTo}WithParamsRpc"; + var verifyMethodName = $"VerifySentTo{sendTo}WithParams"; + + var senderObject = GetPlayerObject(objectOwner, sender); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { i, b, f, s }); + + var verifyMethod = GetType().GetMethod(verifyMethodName); + verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName, i, b, f, s }); + } + + private void SendingNoOverrideWithParamsAndRpcParams(SendTo sendTo, ulong objectOwner, ulong sender) + { + var rand = new Random(); + var i = rand.Next(); + var f = (float)rand.NextDouble(); + var b = rand.Next() % 2 == 1; + var s = ""; + var numChars = rand.Next() % 5 + 5; + const string chars = "abcdefghijklmnopqrstuvwxycABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+[]{}\\|;':\",./<>?"; + for (var j = 0; j < numChars; ++j) + { + s += chars[rand.Next(chars.Length)]; + } + + var sendMethodName = $"DefaultTo{sendTo}WithParamsAndRpcParamsRpc"; + var verifyMethodName = $"VerifySentTo{sendTo}WithParams"; + + var senderObject = GetPlayerObject(objectOwner, sender); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { i, b, f, s, new RpcParams() }); + + var verifyMethod = GetType().GetMethod(verifyMethodName); + verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName, i, b, f, s }); + } + + private void TestRequireOwnership(SendTo sendTo, ulong objectOwner, ulong sender) + { + var sendMethodName = $"DefaultTo{sendTo}RequireOwnershipRpc"; + + var senderObject = GetPlayerObject(objectOwner, sender); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + if (sender != objectOwner) + { + Assert.Throws(() => RethrowTargetInvocationException(() => sendMethod.Invoke(senderObject, new object[] { }))); + } + else + { + var verifyMethodName = $"VerifySentTo{sendTo}"; + sendMethod.Invoke(senderObject, new object[] { }); + + var verifyMethod = GetType().GetMethod(verifyMethodName); + verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); + } + } + #endregion + + #region TYPE-B Tests + private void RunTestTypeB(TestTypes testType) + { + var sendToValues = new List() { SendTo.Everyone, SendTo.Me, SendTo.Owner, SendTo.Server, SendTo.NotMe, SendTo.NotOwner, SendTo.NotServer, SendTo.ClientsAndHost }; + var numberOfClientsULong = (ulong)NumberOfClients; + var actionToInvoke = GetTestTypeActionB(testType); + try + { + foreach (var defaultSendTo in sendToValues) + { + UnityEngine.Debug.Log($"[{testType}][{defaultSendTo}]"); + foreach (var overrideSendTo in sendToValues) + { + for (ulong objectOwner = 0; objectOwner <= numberOfClientsULong; objectOwner++) + { + for (ulong sender = 0; sender <= numberOfClientsULong; sender++) + { + actionToInvoke.Invoke(defaultSendTo, overrideSendTo, objectOwner, sender); + Clear(); + MockTransport.ClearQueues(); + } + } + } + } + } + catch (Exception ex) + { + Assert.Fail($"Threw Exception:{ex.Message}!\n{ex.StackTrace}"); + } + } + + /// + /// Invoked if a does not have an action yet for this action. + /// + private void MockSendB(SendTo defaultSendTo, SendTo overrideSendTo, ulong objectOwner, ulong sender) + { + } + private void SendingWithTargetOverride(SendTo defaultSendTo, SendTo overrideSendTo, ulong objectOwner, ulong sender) + { + var sendMethodName = $"DefaultTo{defaultSendTo}AllowOverrideRpc"; + var targetField = typeof(RpcTarget).GetField(overrideSendTo.ToString()); + var verifyMethodName = $"VerifySentTo{overrideSendTo}"; + + var senderObject = GetPlayerObject(objectOwner, sender); + var target = (BaseRpcTarget)targetField.GetValue(senderObject.RpcTarget); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { (RpcParams)target }); + + var verifyMethod = GetType().GetMethod(verifyMethodName); + verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); + } + #endregion + + #region TYPE-C Tests + public static ulong[][] RecipientGroupsA = new[]{ + new[] { 0ul }, + new[] { 1ul }, + new[] { 0ul, 1ul }, + new[] { 0ul, 1ul, 2ul } + }; + + public static ulong[][] RecipientGroupsB = new[] +{ + new ulong[] {}, + new[] { 0ul }, + new[] { 1ul }, + new[] { 0ul, 1ul }, + }; + + public enum AllocationType + { + Array, + NativeArray, + NativeList, + List + } + + private void RunTestTypeC(TestTypesC testType, SendTo defaultSendTo) + { + var allocationTypes = new List() { AllocationType.Array, AllocationType.NativeArray, AllocationType.NativeList, AllocationType.List }; + var numberOfClientsULong = (ulong)NumberOfClients; + var actionToInvoke = GetTestTypeActionC(testType); + var recipientGroups = m_TypeToRecipientGroupsTable[testType]; + foreach (var sendGroup in recipientGroups) + { + try + { + for (ulong objectOwner = 0; objectOwner <= numberOfClientsULong; objectOwner++) + { + for (ulong sender = 0; sender <= numberOfClientsULong; sender++) + { + foreach (var allocationType in allocationTypes) + { + actionToInvoke.Invoke(defaultSendTo, sendGroup, objectOwner, sender, allocationType); + TimeTravel(s_DefaultWaitForTick.waitTime, 4); + Clear(); + MockTransport.ClearQueues(); + } + } + } + } + catch (Exception ex) + { + Assert.Fail($"Threw Exception:{ex.Message}!\n{ex.StackTrace}"); + } + } + } + + private void MockSendC(SendTo defaultSendTo, ulong[] recipient, ulong objectOwner, ulong sender, AllocationType allocationType) + { + } + + private void SendingWithGroupOverride(SendTo defaultSendTo, ulong[] recipient, ulong objectOwner, ulong sender, AllocationType allocationType) + { + var sendMethodName = $"DefaultTo{defaultSendTo}AllowOverrideRpc"; + + var senderObject = GetPlayerObject(objectOwner, sender); + BaseRpcTarget target = null; + switch (allocationType) + { + case AllocationType.Array: + target = senderObject.RpcTarget.Group(recipient, RpcTargetUse.Temp); + break; + case AllocationType.List: + target = senderObject.RpcTarget.Group(recipient.ToList(), RpcTargetUse.Temp); + break; + case AllocationType.NativeArray: + var arr = new NativeArray(recipient, Allocator.Temp); + target = senderObject.RpcTarget.Group(arr, RpcTargetUse.Temp); + arr.Dispose(); + break; + case AllocationType.NativeList: + // For some reason on 2020.3, calling list.AsArray() and passing that to the next function + // causes Allocator.Temp allocations to become invalid somehow. This is not an issue on later + // versions of Unity. + var list = new NativeList(recipient.Length, Allocator.TempJob); + foreach (var id in recipient) + { + list.Add(id); + } + target = senderObject.RpcTarget.Group(list, RpcTargetUse.Temp); + list.Dispose(); + break; + } + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { (RpcParams)target }); + + VerifyRemoteReceived(objectOwner, sender, sendMethodName, s_ClientIds.Where(c => recipient.Contains(c)).ToArray(), false); + VerifyNotReceived(objectOwner, s_ClientIds.Where(c => !recipient.Contains(c)).ToArray()); + + // Pass some time to make sure that no other client ever receives this + TimeTravel(1f, 30); + VerifyNotReceived(objectOwner, s_ClientIds.Where(c => !recipient.Contains(c)).ToArray()); + } + + private void SendingWithGroupNotOverride(SendTo defaultSendTo, ulong[] recipient, ulong objectOwner, ulong sender, AllocationType allocationType) + { + var sendMethodName = $"DefaultTo{defaultSendTo}AllowOverrideRpc"; + + var senderObject = GetPlayerObject(objectOwner, sender); + BaseRpcTarget target = null; + switch (allocationType) + { + case AllocationType.Array: + target = senderObject.RpcTarget.Not(recipient, RpcTargetUse.Temp); + break; + case AllocationType.List: + target = senderObject.RpcTarget.Not(recipient.ToList(), RpcTargetUse.Temp); + break; + case AllocationType.NativeArray: + var arr = new NativeArray(recipient, Allocator.Temp); + target = senderObject.RpcTarget.Not(arr, RpcTargetUse.Temp); + arr.Dispose(); + break; + case AllocationType.NativeList: + // For some reason on 2020.3, calling list.AsArray() and passing that to the next function + // causes Allocator.Temp allocations to become invalid somehow. This is not an issue on later + // versions of Unity. + var list = new NativeList(recipient.Length, Allocator.TempJob); + foreach (var id in recipient) + { + list.Add(id); + } + target = senderObject.RpcTarget.Not(list, RpcTargetUse.Temp); + list.Dispose(); + break; + } + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { (RpcParams)target }); + + VerifyRemoteReceived(objectOwner, sender, sendMethodName, s_ClientIds.Where(c => !recipient.Contains(c)).ToArray(), false); + VerifyNotReceived(objectOwner, s_ClientIds.Where(c => recipient.Contains(c)).ToArray()); + + // Pass some time to make sure that no other client ever receives this + TimeTravel(1f, 30); + VerifyNotReceived(objectOwner, s_ClientIds.Where(c => recipient.Contains(c)).ToArray()); + } + #endregion + + } + +#if USE_LEGACY_UNIVERSALRPC_TESTS [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] @@ -1319,7 +1830,10 @@ public void TestSendingWithTargetOverride( } +#endif + + [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] internal class UniversalRpcTestSendingWithSingleOverride : UniversalRpcTestsBase @@ -1329,31 +1843,41 @@ public UniversalRpcTestSendingWithSingleOverride(HostOrServer hostOrServer) : ba } - [Test] - public void TestSendingWithSingleOverride( - [Values] SendTo defaultSendTo, - [Values(0u, 1u, 2u)] ulong recipient, - [Values(0u, 1u, 2u)] ulong objectOwner, - [Values(0u, 1u, 2u)] ulong sender - ) + [UnityTest] + public IEnumerator TestSendingWithSingleOverride([Values(SendTo.Everyone, SendTo.Me, SendTo.Owner, SendTo.Server, SendTo.NotMe, SendTo.NotOwner, SendTo.NotServer, SendTo.ClientsAndHost)] SendTo defaultSendTo) { - var sendMethodName = $"DefaultTo{defaultSendTo}AllowOverrideRpc"; + for (ulong recipient = 0u; recipient <= 2u; ++recipient) + { + for (ulong objectOwner = 0u; objectOwner <= 2u; ++objectOwner) + { + for (ulong sender = 0u; sender <= 2u; ++sender) + { + if (++YieldCheck % YieldCycleCount == 0) + { + yield return null; + } + OnInlineSetup(); + var sendMethodName = $"DefaultTo{defaultSendTo}AllowOverrideRpc"; - var senderObject = GetPlayerObject(objectOwner, sender); - var target = senderObject.RpcTarget.Single(recipient, RpcTargetUse.Temp); - var sendMethod = senderObject.GetType().GetMethod(sendMethodName); - sendMethod.Invoke(senderObject, new object[] { (RpcParams)target }); + var senderObject = GetPlayerObject(objectOwner, sender); + var target = senderObject.RpcTarget.Single(recipient, RpcTargetUse.Temp); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { (RpcParams)target }); - VerifyRemoteReceived(objectOwner, sender, sendMethodName, new[] { recipient }, false); - VerifyNotReceived(objectOwner, s_ClientIds.Where(c => recipient != c).ToArray()); + VerifyRemoteReceived(objectOwner, sender, sendMethodName, new[] { recipient }, false); + VerifyNotReceived(objectOwner, s_ClientIds.Where(c => recipient != c).ToArray()); - // Pass some time to make sure that no other client ever receives this - TimeTravel(1f, 30); - VerifyNotReceived(objectOwner, s_ClientIds.Where(c => recipient != c).ToArray()); + // Pass some time to make sure that no other client ever receives this + TimeTravel(1f, 30); + VerifyNotReceived(objectOwner, s_ClientIds.Where(c => recipient != c).ToArray()); + OnInlineTearDown(); + } + } + } } - } + [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] internal class UniversalRpcTestSendingWithSingleNotOverride : UniversalRpcTestsBase @@ -1363,31 +1887,41 @@ public UniversalRpcTestSendingWithSingleNotOverride(HostOrServer hostOrServer) : } - [Test] - public void TestSendingWithSingleNotOverride( - [Values] SendTo defaultSendTo, - [Values(0u, 1u, 2u)] ulong recipient, - [Values(0u, 1u, 2u)] ulong objectOwner, - [Values(0u, 1u, 2u)] ulong sender - ) + [UnityTest] + public IEnumerator TestSendingWithSingleNotOverride([Values(SendTo.Everyone, SendTo.Me, SendTo.Owner, SendTo.Server, SendTo.NotMe, SendTo.NotOwner, SendTo.NotServer, SendTo.ClientsAndHost)] SendTo defaultSendTo) { - var sendMethodName = $"DefaultTo{defaultSendTo}AllowOverrideRpc"; + for (ulong recipient = 0u; recipient <= 2u; ++recipient) + { + for (ulong objectOwner = 0u; objectOwner <= 2u; ++objectOwner) + { + for (ulong sender = 0u; sender <= 2u; ++sender) + { + if (++YieldCheck % YieldCycleCount == 0) + { + yield return null; + } + OnInlineSetup(); + var sendMethodName = $"DefaultTo{defaultSendTo}AllowOverrideRpc"; - var senderObject = GetPlayerObject(objectOwner, sender); - var target = senderObject.RpcTarget.Not(recipient, RpcTargetUse.Temp); - var sendMethod = senderObject.GetType().GetMethod(sendMethodName); - sendMethod.Invoke(senderObject, new object[] { (RpcParams)target }); + var senderObject = GetPlayerObject(objectOwner, sender); + var target = senderObject.RpcTarget.Not(recipient, RpcTargetUse.Temp); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { (RpcParams)target }); - VerifyRemoteReceived(objectOwner, sender, sendMethodName, s_ClientIds.Where(c => recipient != c).ToArray(), false); - VerifyNotReceived(objectOwner, new[] { recipient }); + VerifyRemoteReceived(objectOwner, sender, sendMethodName, s_ClientIds.Where(c => recipient != c).ToArray(), false); + VerifyNotReceived(objectOwner, new[] { recipient }); - // Pass some time to make sure that no other client ever receives this - TimeTravel(1f, 30); - VerifyNotReceived(objectOwner, new[] { recipient }); + // Pass some time to make sure that no other client ever receives this + TimeTravel(1f, 30); + VerifyNotReceived(objectOwner, new[] { recipient }); + OnInlineTearDown(); + } + } + } } - } +#if USE_LEGACY_UNIVERSALRPC_TESTS [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] internal class UniversalRpcTestSendingWithGroupOverride : UniversalRpcTestsBase @@ -1542,6 +2076,8 @@ [Values] AllocationType allocationType } +#endif + [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] @@ -1552,273 +2088,184 @@ public UniversalRpcTestDeferLocal(HostOrServer hostOrServer) : base(hostOrServer } - [Test] - // All the test cases that involve sends that will be delivered locally - [TestCase(SendTo.Everyone, 0u, 0u)] - [TestCase(SendTo.Everyone, 0u, 1u)] - [TestCase(SendTo.Everyone, 0u, 2u)] - [TestCase(SendTo.Everyone, 1u, 0u)] - [TestCase(SendTo.Everyone, 1u, 1u)] - [TestCase(SendTo.Everyone, 1u, 2u)] - [TestCase(SendTo.Everyone, 2u, 0u)] - [TestCase(SendTo.Everyone, 2u, 1u)] - [TestCase(SendTo.Everyone, 2u, 2u)] - [TestCase(SendTo.Me, 0u, 0u)] - [TestCase(SendTo.Me, 0u, 1u)] - [TestCase(SendTo.Me, 0u, 2u)] - [TestCase(SendTo.Me, 1u, 0u)] - [TestCase(SendTo.Me, 1u, 1u)] - [TestCase(SendTo.Me, 1u, 2u)] - [TestCase(SendTo.Me, 2u, 0u)] - [TestCase(SendTo.Me, 2u, 1u)] - [TestCase(SendTo.Me, 2u, 2u)] - [TestCase(SendTo.Owner, 0u, 0u)] - [TestCase(SendTo.Owner, 1u, 1u)] - [TestCase(SendTo.Owner, 2u, 2u)] - [TestCase(SendTo.Server, 0u, 0u)] - [TestCase(SendTo.Server, 1u, 0u)] - [TestCase(SendTo.Server, 2u, 0u)] - [TestCase(SendTo.NotOwner, 0u, 1u)] - [TestCase(SendTo.NotOwner, 0u, 2u)] - [TestCase(SendTo.NotOwner, 1u, 0u)] - [TestCase(SendTo.NotOwner, 1u, 2u)] - [TestCase(SendTo.NotOwner, 2u, 0u)] - [TestCase(SendTo.NotOwner, 2u, 1u)] - [TestCase(SendTo.NotServer, 0u, 1u)] - [TestCase(SendTo.NotServer, 0u, 2u)] - [TestCase(SendTo.NotServer, 1u, 1u)] - [TestCase(SendTo.NotServer, 1u, 2u)] - [TestCase(SendTo.NotServer, 2u, 1u)] - [TestCase(SendTo.NotServer, 2u, 2u)] - [TestCase(SendTo.ClientsAndHost, 0u, 0u)] - [TestCase(SendTo.ClientsAndHost, 0u, 1u)] - [TestCase(SendTo.ClientsAndHost, 0u, 2u)] - [TestCase(SendTo.ClientsAndHost, 1u, 0u)] - [TestCase(SendTo.ClientsAndHost, 1u, 1u)] - [TestCase(SendTo.ClientsAndHost, 1u, 2u)] - [TestCase(SendTo.ClientsAndHost, 2u, 0u)] - [TestCase(SendTo.ClientsAndHost, 2u, 1u)] - [TestCase(SendTo.ClientsAndHost, 2u, 2u)] - [TestCase(SendTo.Authority, 0u, 0u)] - [TestCase(SendTo.Authority, 1u, 1u)] - [TestCase(SendTo.Authority, 2u, 2u)] - [TestCase(SendTo.NotAuthority, 0u, 1u)] - [TestCase(SendTo.NotAuthority, 0u, 2u)] - [TestCase(SendTo.NotAuthority, 1u, 0u)] - [TestCase(SendTo.NotAuthority, 1u, 2u)] - [TestCase(SendTo.NotAuthority, 2u, 0u)] - [TestCase(SendTo.NotAuthority, 2u, 1u)] - public void TestDeferLocal( - SendTo defaultSendTo, - ulong objectOwner, - ulong sender - ) + private struct TestData { - if (defaultSendTo == SendTo.ClientsAndHost && sender == 0u && !m_ServerNetworkManager.IsHost) + public SendTo SendTo; + public ulong ObjectOwner; + public ulong Sender; + + public TestData(SendTo sendTo, ulong objectOwner, ulong sender) { - // Not calling Assert.Ignore() because Unity will mark the whole block of tests as ignored - // Just consider this case a success... - return; + SendTo = sendTo; + ObjectOwner = objectOwner; + Sender = sender; } + } + + // All the test cases that involve sends that will be delivered locally + private static TestData[] s_LocalDeliveryTestCases = + { + new TestData(SendTo.Everyone, 0u, 0u), + new TestData(SendTo.Everyone, 0u, 1u), + new TestData(SendTo.Everyone, 0u, 2u), + new TestData(SendTo.Everyone, 1u, 0u), + new TestData(SendTo.Everyone, 1u, 1u), + new TestData(SendTo.Everyone, 1u, 2u), + new TestData(SendTo.Everyone, 2u, 0u), + new TestData(SendTo.Everyone, 2u, 1u), + new TestData(SendTo.Everyone, 2u, 2u), + new TestData(SendTo.Me, 0u, 0u), + new TestData(SendTo.Me, 0u, 1u), + new TestData(SendTo.Me, 0u, 2u), + new TestData(SendTo.Me, 1u, 0u), + new TestData(SendTo.Me, 1u, 1u), + new TestData(SendTo.Me, 1u, 2u), + new TestData(SendTo.Me, 2u, 0u), + new TestData(SendTo.Me, 2u, 1u), + new TestData(SendTo.Me, 2u, 2u), + new TestData(SendTo.Owner, 0u, 0u), + new TestData(SendTo.Owner, 1u, 1u), + new TestData(SendTo.Owner, 2u, 2u), + new TestData(SendTo.Server, 0u, 0u), + new TestData(SendTo.Server, 1u, 0u), + new TestData(SendTo.Server, 2u, 0u), + new TestData(SendTo.NotOwner, 0u, 1u), + new TestData(SendTo.NotOwner, 0u, 2u), + new TestData(SendTo.NotOwner, 1u, 0u), + new TestData(SendTo.NotOwner, 1u, 2u), + new TestData(SendTo.NotOwner, 2u, 0u), + new TestData(SendTo.NotOwner, 2u, 1u), + new TestData(SendTo.NotServer, 0u, 1u), + new TestData(SendTo.NotServer, 0u, 2u), + new TestData(SendTo.NotServer, 1u, 1u), + new TestData(SendTo.NotServer, 1u, 2u), + new TestData(SendTo.NotServer, 2u, 1u), + new TestData(SendTo.NotServer, 2u, 2u), + new TestData(SendTo.ClientsAndHost, 0u, 0u), + new TestData(SendTo.ClientsAndHost, 0u, 1u), + new TestData(SendTo.ClientsAndHost, 0u, 2u), + new TestData(SendTo.ClientsAndHost, 1u, 0u), + new TestData(SendTo.ClientsAndHost, 1u, 1u), + new TestData(SendTo.ClientsAndHost, 1u, 2u), + new TestData(SendTo.ClientsAndHost, 2u, 0u), + new TestData(SendTo.ClientsAndHost, 2u, 1u), + new TestData(SendTo.ClientsAndHost, 2u, 2u), + }; + - // Similar to above, since Server and NotServer are already tested we can consider this a success - if (!m_DistributedAuthority && defaultSendTo == SendTo.Authority || defaultSendTo == SendTo.NotAuthority) + [UnityTest] + public IEnumerator TestDeferLocal() + { + foreach (var testCase in s_LocalDeliveryTestCases) { - return; - } + if (++YieldCheck % YieldCycleCount == 0) + { + yield return null; + } + OnInlineSetup(); + var defaultSendTo = testCase.SendTo; + var sender = testCase.Sender; + var objectOwner = testCase.ObjectOwner; - var sendMethodName = $"DefaultTo{defaultSendTo}DeferLocalRpc"; - var verifyMethodName = $"VerifySentTo{defaultSendTo}"; - var senderObject = GetPlayerObject(objectOwner, sender); - var sendMethod = senderObject.GetType().GetMethod(sendMethodName); - sendMethod.Invoke(senderObject, new object[] { new RpcParams() }); + if (defaultSendTo == SendTo.ClientsAndHost && sender == 0u && !m_ServerNetworkManager.IsHost) + { + // Not calling Assert.Ignore() because Unity will mark the whole block of tests as ignored + // Just consider this case a success... + yield break; + } - VerifyNotReceived(objectOwner, new[] { sender }); - // Should be received on the next frame - SimulateOneFrame(); - VerifyLocalReceived(objectOwner, sender, sendMethodName, false); + var sendMethodName = $"DefaultTo{defaultSendTo}DeferLocalRpc"; + var verifyMethodName = $"VerifySentTo{defaultSendTo}"; + var senderObject = GetPlayerObject(objectOwner, sender); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { new RpcParams() }); - var verifyMethod = GetType().GetMethod(verifyMethodName); - verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); + VerifyNotReceived(objectOwner, new[] { sender }); + // Should be received on the next frame + SimulateOneFrame(); + VerifyLocalReceived(objectOwner, sender, sendMethodName, false); + + var verifyMethod = GetType().GetMethod(verifyMethodName); + verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); + OnInlineTearDown(); + } } - [Test] - // All the test cases that involve sends that will be delivered locally - [TestCase(SendTo.Everyone, 0u, 0u)] - [TestCase(SendTo.Everyone, 0u, 1u)] - [TestCase(SendTo.Everyone, 0u, 2u)] - [TestCase(SendTo.Everyone, 1u, 0u)] - [TestCase(SendTo.Everyone, 1u, 1u)] - [TestCase(SendTo.Everyone, 1u, 2u)] - [TestCase(SendTo.Everyone, 2u, 0u)] - [TestCase(SendTo.Everyone, 2u, 1u)] - [TestCase(SendTo.Everyone, 2u, 2u)] - [TestCase(SendTo.Me, 0u, 0u)] - [TestCase(SendTo.Me, 0u, 1u)] - [TestCase(SendTo.Me, 0u, 2u)] - [TestCase(SendTo.Me, 1u, 0u)] - [TestCase(SendTo.Me, 1u, 1u)] - [TestCase(SendTo.Me, 1u, 2u)] - [TestCase(SendTo.Me, 2u, 0u)] - [TestCase(SendTo.Me, 2u, 1u)] - [TestCase(SendTo.Me, 2u, 2u)] - [TestCase(SendTo.Owner, 0u, 0u)] - [TestCase(SendTo.Owner, 1u, 1u)] - [TestCase(SendTo.Owner, 2u, 2u)] - [TestCase(SendTo.Server, 0u, 0u)] - [TestCase(SendTo.Server, 1u, 0u)] - [TestCase(SendTo.Server, 2u, 0u)] - [TestCase(SendTo.NotOwner, 0u, 1u)] - [TestCase(SendTo.NotOwner, 0u, 2u)] - [TestCase(SendTo.NotOwner, 1u, 0u)] - [TestCase(SendTo.NotOwner, 1u, 2u)] - [TestCase(SendTo.NotOwner, 2u, 0u)] - [TestCase(SendTo.NotOwner, 2u, 1u)] - [TestCase(SendTo.NotServer, 0u, 1u)] - [TestCase(SendTo.NotServer, 0u, 2u)] - [TestCase(SendTo.NotServer, 1u, 1u)] - [TestCase(SendTo.NotServer, 1u, 2u)] - [TestCase(SendTo.NotServer, 2u, 1u)] - [TestCase(SendTo.NotServer, 2u, 2u)] - [TestCase(SendTo.ClientsAndHost, 0u, 0u)] - [TestCase(SendTo.ClientsAndHost, 0u, 1u)] - [TestCase(SendTo.ClientsAndHost, 0u, 2u)] - [TestCase(SendTo.ClientsAndHost, 1u, 0u)] - [TestCase(SendTo.ClientsAndHost, 1u, 1u)] - [TestCase(SendTo.ClientsAndHost, 1u, 2u)] - [TestCase(SendTo.ClientsAndHost, 2u, 0u)] - [TestCase(SendTo.ClientsAndHost, 2u, 1u)] - [TestCase(SendTo.ClientsAndHost, 2u, 2u)] - [TestCase(SendTo.Authority, 0u, 0u)] - [TestCase(SendTo.Authority, 1u, 1u)] - [TestCase(SendTo.Authority, 2u, 2u)] - [TestCase(SendTo.NotAuthority, 0u, 1u)] - [TestCase(SendTo.NotAuthority, 0u, 2u)] - [TestCase(SendTo.NotAuthority, 1u, 0u)] - [TestCase(SendTo.NotAuthority, 1u, 2u)] - [TestCase(SendTo.NotAuthority, 2u, 0u)] - [TestCase(SendTo.NotAuthority, 2u, 1u)] - public void TestDeferLocalOverrideToTrue( - SendTo defaultSendTo, - ulong objectOwner, - ulong sender - ) + [UnityTest] + public IEnumerator TestDeferLocalOverrideToTrue() { - if (defaultSendTo == SendTo.ClientsAndHost && sender == 0u && !m_ServerNetworkManager.IsHost) - { - // Not calling Assert.Ignore() because Unity will mark the whole block of tests as ignored - // Just consider this case a success... - return; - } - // Similar to above, since Server and NotServer are already tested we can consider this a success - if (!m_DistributedAuthority && defaultSendTo == SendTo.Authority || defaultSendTo == SendTo.NotAuthority) + foreach (var testCase in s_LocalDeliveryTestCases) { - return; - } + if (++YieldCheck % YieldCycleCount == 0) + { + yield return null; + } + OnInlineSetup(); + var defaultSendTo = testCase.SendTo; + var sender = testCase.Sender; + var objectOwner = testCase.ObjectOwner; - var sendMethodName = $"DefaultTo{defaultSendTo}WithRpcParamsRpc"; - var verifyMethodName = $"VerifySentTo{defaultSendTo}"; - var senderObject = GetPlayerObject(objectOwner, sender); - var sendMethod = senderObject.GetType().GetMethod(sendMethodName); - sendMethod.Invoke(senderObject, new object[] { (RpcParams)LocalDeferMode.Defer }); + if (defaultSendTo == SendTo.ClientsAndHost && sender == 0u && !m_ServerNetworkManager.IsHost) + { + // Not calling Assert.Ignore() because Unity will mark the whole block of tests as ignored + // Just consider this case a success... + yield break; + } - VerifyNotReceived(objectOwner, new[] { sender }); - // Should be received on the next frame - SimulateOneFrame(); - VerifyLocalReceived(objectOwner, sender, sendMethodName, false); + var sendMethodName = $"DefaultTo{defaultSendTo}WithRpcParamsRpc"; + var verifyMethodName = $"VerifySentTo{defaultSendTo}"; + var senderObject = GetPlayerObject(objectOwner, sender); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { (RpcParams)LocalDeferMode.Defer }); - var verifyMethod = GetType().GetMethod(verifyMethodName); - verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); + VerifyNotReceived(objectOwner, new[] { sender }); + // Should be received on the next frame + SimulateOneFrame(); + VerifyLocalReceived(objectOwner, sender, sendMethodName, false); + + var verifyMethod = GetType().GetMethod(verifyMethodName); + verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); + OnInlineTearDown(); + } } - [Test] - // All the test cases that involve sends that will be delivered locally - [TestCase(SendTo.Everyone, 0u, 0u)] - [TestCase(SendTo.Everyone, 0u, 1u)] - [TestCase(SendTo.Everyone, 0u, 2u)] - [TestCase(SendTo.Everyone, 1u, 0u)] - [TestCase(SendTo.Everyone, 1u, 1u)] - [TestCase(SendTo.Everyone, 1u, 2u)] - [TestCase(SendTo.Everyone, 2u, 0u)] - [TestCase(SendTo.Everyone, 2u, 1u)] - [TestCase(SendTo.Everyone, 2u, 2u)] - [TestCase(SendTo.Me, 0u, 0u)] - [TestCase(SendTo.Me, 0u, 1u)] - [TestCase(SendTo.Me, 0u, 2u)] - [TestCase(SendTo.Me, 1u, 0u)] - [TestCase(SendTo.Me, 1u, 1u)] - [TestCase(SendTo.Me, 1u, 2u)] - [TestCase(SendTo.Me, 2u, 0u)] - [TestCase(SendTo.Me, 2u, 1u)] - [TestCase(SendTo.Me, 2u, 2u)] - [TestCase(SendTo.Owner, 0u, 0u)] - [TestCase(SendTo.Owner, 1u, 1u)] - [TestCase(SendTo.Owner, 2u, 2u)] - [TestCase(SendTo.Server, 0u, 0u)] - [TestCase(SendTo.Server, 1u, 0u)] - [TestCase(SendTo.Server, 2u, 0u)] - [TestCase(SendTo.NotOwner, 0u, 1u)] - [TestCase(SendTo.NotOwner, 0u, 2u)] - [TestCase(SendTo.NotOwner, 1u, 0u)] - [TestCase(SendTo.NotOwner, 1u, 2u)] - [TestCase(SendTo.NotOwner, 2u, 0u)] - [TestCase(SendTo.NotOwner, 2u, 1u)] - [TestCase(SendTo.NotServer, 0u, 1u)] - [TestCase(SendTo.NotServer, 0u, 2u)] - [TestCase(SendTo.NotServer, 1u, 1u)] - [TestCase(SendTo.NotServer, 1u, 2u)] - [TestCase(SendTo.NotServer, 2u, 1u)] - [TestCase(SendTo.NotServer, 2u, 2u)] - [TestCase(SendTo.ClientsAndHost, 0u, 0u)] - [TestCase(SendTo.ClientsAndHost, 0u, 1u)] - [TestCase(SendTo.ClientsAndHost, 0u, 2u)] - [TestCase(SendTo.ClientsAndHost, 1u, 0u)] - [TestCase(SendTo.ClientsAndHost, 1u, 1u)] - [TestCase(SendTo.ClientsAndHost, 1u, 2u)] - [TestCase(SendTo.ClientsAndHost, 2u, 0u)] - [TestCase(SendTo.ClientsAndHost, 2u, 1u)] - [TestCase(SendTo.ClientsAndHost, 2u, 2u)] - [TestCase(SendTo.Authority, 0u, 0u)] - [TestCase(SendTo.Authority, 1u, 1u)] - [TestCase(SendTo.Authority, 2u, 2u)] - [TestCase(SendTo.NotAuthority, 0u, 1u)] - [TestCase(SendTo.NotAuthority, 0u, 2u)] - [TestCase(SendTo.NotAuthority, 1u, 0u)] - [TestCase(SendTo.NotAuthority, 1u, 2u)] - [TestCase(SendTo.NotAuthority, 2u, 0u)] - [TestCase(SendTo.NotAuthority, 2u, 1u)] - public void TestDeferLocalOverrideToFalse( - SendTo defaultSendTo, - ulong objectOwner, - ulong sender - ) + [UnityTest] + public IEnumerator TestDeferLocalOverrideToFalse() { - if (defaultSendTo == SendTo.ClientsAndHost && sender == 0u && !m_ServerNetworkManager.IsHost) - { - // Not calling Assert.Ignore() because Unity will mark the whole block of tests as ignored - // Just consider this case a success... - return; - } - // Similar to above, since Server and NotServer are already tested we can consider this a success - if (!m_DistributedAuthority && defaultSendTo == SendTo.Authority || defaultSendTo == SendTo.NotAuthority) + foreach (var testCase in s_LocalDeliveryTestCases) { - return; - } + if (++YieldCheck % YieldCycleCount == 0) + { + yield return null; + } + OnInlineSetup(); + var defaultSendTo = testCase.SendTo; + var sender = testCase.Sender; + var objectOwner = testCase.ObjectOwner; - var sendMethodName = $"DefaultTo{defaultSendTo}DeferLocalRpc"; - var verifyMethodName = $"VerifySentTo{defaultSendTo}"; - var senderObject = GetPlayerObject(objectOwner, sender); - var sendMethod = senderObject.GetType().GetMethod(sendMethodName); - sendMethod.Invoke(senderObject, new object[] { (RpcParams)LocalDeferMode.SendImmediate }); + if (defaultSendTo == SendTo.ClientsAndHost && sender == 0u && !m_ServerNetworkManager.IsHost) + { + // Not calling Assert.Ignore() because Unity will mark the whole block of tests as ignored + // Just consider this case a success... + yield break; + } - VerifyLocalReceived(objectOwner, sender, sendMethodName, false); + var sendMethodName = $"DefaultTo{defaultSendTo}DeferLocalRpc"; + var verifyMethodName = $"VerifySentTo{defaultSendTo}"; + var senderObject = GetPlayerObject(objectOwner, sender); + var sendMethod = senderObject.GetType().GetMethod(sendMethodName); + sendMethod.Invoke(senderObject, new object[] { (RpcParams)LocalDeferMode.SendImmediate }); - var verifyMethod = GetType().GetMethod(verifyMethodName); - verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); - } + VerifyLocalReceived(objectOwner, sender, sendMethodName, false); + var verifyMethod = GetType().GetMethod(verifyMethodName); + verifyMethod.Invoke(this, new object[] { objectOwner, sender, sendMethodName }); + OnInlineTearDown(); + } + } } + [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] internal class UniversalRpcTestMutualRecursion : UniversalRpcTestsBase @@ -1868,6 +2315,7 @@ public void TestMutualRecursion() } + [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] internal class UniversalRpcTestSelfRecursion : UniversalRpcTestsBase