Skip to content

Commit 6e454fa

Browse files
test: add RpcQueue unit tests (#521)
* test: RPC Queue tests The following tests are performed on the RPC Queue: Test the ingress (receive) and egress (send) pipeline (no network connection) Tests RPC SendParams (client-server) are working properly( RPC update stage) Tests that RPCs are invoked at their appropriate stages. * test: refactoring additional test against each rpc update stage This addition assures that all rpcs invoked were invoked with the same network update stage as the originating value. * fix: removing interface Didn't need this anyway. * refactor and style: fixed some minor issues and standards update Fixed some minor issues with what was being logged and made adjustments to keep compliant with Unity standards. * style: removing function names and CamelCase Some more standards adjustments. * style: standards Some more adjustments for standards. * style: standards Fixing some naming convention issues with m_ServerParms (to m_ServerParams) and m_ClientParms ( to m_ClientParams). * fix: bug with standards change Fixing a bug with the last update that fixes the issue with out of synch network update stages. * style: standards Fixing issues with missing private declarations and a few missed vars. * style: standards local vars camelCase for local vars. * refactor: stopping host and shutting down Per Matt's comment, I added the stopping of the host and the shutting down of the networking manager. * fix: Unity Editor define Exclude the in-editor setup and tear down methods from a runtime build. * Including * refactor and style Refactoring the timing: removing the time limit check as it appears things can take much longer in "yamato" world. Renamed RpcQueueTests.cs to RpcQueueTest.cs and renamed the class to singular form as well. * refactor Adding additional debug information to determine why the tests pass in the editor and as a runtime but fail in yamato. * refactor Removing any time based update as well as adding a trap to detect for the condition that we have exceeded the maximum number of defined rpcs to be sent and still haven't detected that the proper sequence is complete. * refactor Removing unneeded if statement * refactor Adding additional debug information to help narrow down the issue with this test in Yamato. * refactor Trying one last thing before waiting until I can discuss with Fatih. * refactor Also removing all debug statements in the event this might be causing issues. * fix and refactor rpcqueuetests * fix compile errors after merging develop branch * set server/client receive params' updatestage fields to initialization at start * add unitysetup and unityteardown steps into rpcqueuetests * destroy gameobjects created during the test * if-guard around unitysetup and unityteardown * try more stuff * revert asmdef changes * revert proejctsettings change * disable rpcqueuetests on 2019.4 (due to ILPP issues) * comment why we disabled RpcQueueUnitTest Co-authored-by: M. Fatih MAR <[email protected]>
1 parent 399c7b3 commit 6e454fa

File tree

4 files changed

+327
-0
lines changed

4 files changed

+327
-0
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
using MLAPI.Messaging;
5+
6+
namespace MLAPI.RuntimeTests
7+
{
8+
/// <summary>
9+
/// Used in conjunction with the RpcQueueTest to validate:
10+
/// - Sending and Receiving pipeline to validate that both sending and receiving pipelines are functioning properly.
11+
/// - Usage of the ServerRpcParams.Send.UpdateStage and ClientRpcParams.Send.UpdateStage functionality.
12+
/// - Rpcs receive will be invoked at the appropriate NetworkUpdateStage.
13+
/// </summary>
14+
public class RpcPipelineTestComponent : NetworkBehaviour
15+
{
16+
/// <summary>
17+
/// Allows the external RPCQueueTest to begin testing or stop it
18+
/// </summary>
19+
public bool PingSelfEnabled;
20+
21+
/// <summary>
22+
/// How many times will we iterate through the various NetworkUpdateStage values?
23+
/// (defaults to 2)
24+
/// </summary>
25+
public int MaxIterations = 2;
26+
27+
28+
// Start is called before the first frame update
29+
private void Start()
30+
{
31+
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.Initialization;
32+
m_ClientParams.Send.UpdateStage = NetworkUpdateStage.Update;
33+
34+
m_ServerParams.Receive.UpdateStage = NetworkUpdateStage.Initialization;
35+
m_ClientParams.Receive.UpdateStage = NetworkUpdateStage.Initialization;
36+
37+
m_MaxStagesSent = (Enum.GetValues(typeof(NetworkUpdateStage)).Length) * MaxIterations;
38+
39+
//Start out with this being true (for first sequence)
40+
m_ClientReceivedRpc = true;
41+
}
42+
43+
/// <summary>
44+
/// Determine if we have iterated over more than our maximum stages we want to test
45+
/// </summary>
46+
/// <returns>true or false (did we exceed the max iterations or not?)</returns>
47+
public bool ExceededMaxIterations()
48+
{
49+
if (m_StagesSent.Count > m_MaxStagesSent && m_MaxStagesSent > 0)
50+
{
51+
return true;
52+
}
53+
54+
return false;
55+
}
56+
57+
/// <summary>
58+
/// Returns back whether the test has completed the total number of iterations
59+
/// </summary>
60+
/// <returns></returns>
61+
public bool IsTestComplete()
62+
{
63+
if (m_Counter >= MaxIterations)
64+
{
65+
return true;
66+
}
67+
68+
return false;
69+
}
70+
71+
private bool m_ClientReceivedRpc;
72+
private int m_Counter = 0;
73+
private int m_MaxStagesSent = 0;
74+
private ServerRpcParams m_ServerParams;
75+
private ClientRpcParams m_ClientParams;
76+
private NetworkUpdateStage m_LastUpdateStage;
77+
78+
// Update is called once per frame
79+
private void Update()
80+
{
81+
if (NetworkManager.Singleton.IsListening && PingSelfEnabled && m_ClientReceivedRpc)
82+
{
83+
//Reset this for the next sequence of rpcs
84+
m_ClientReceivedRpc = false;
85+
86+
//As long as testing isn't completed, keep testing
87+
if (!IsTestComplete() && m_StagesSent.Count < m_MaxStagesSent)
88+
{
89+
m_LastUpdateStage = m_ServerParams.Send.UpdateStage;
90+
m_StagesSent.Add(m_LastUpdateStage);
91+
92+
PingMySelfServerRpc(m_StagesSent.Count, m_ServerParams);
93+
94+
switch (m_ServerParams.Send.UpdateStage)
95+
{
96+
case NetworkUpdateStage.Initialization:
97+
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.EarlyUpdate;
98+
break;
99+
case NetworkUpdateStage.EarlyUpdate:
100+
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.FixedUpdate;
101+
break;
102+
case NetworkUpdateStage.FixedUpdate:
103+
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.PreUpdate;
104+
break;
105+
case NetworkUpdateStage.PreUpdate:
106+
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.Update;
107+
break;
108+
case NetworkUpdateStage.Update:
109+
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.PreLateUpdate;
110+
break;
111+
case NetworkUpdateStage.PreLateUpdate:
112+
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.PostLateUpdate;
113+
break;
114+
case NetworkUpdateStage.PostLateUpdate:
115+
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.Initialization;
116+
break;
117+
}
118+
}
119+
}
120+
}
121+
122+
123+
private readonly List<NetworkUpdateStage> m_ServerStagesReceived = new List<NetworkUpdateStage>();
124+
private readonly List<NetworkUpdateStage> m_ClientStagesReceived = new List<NetworkUpdateStage>();
125+
private readonly List<NetworkUpdateStage> m_StagesSent = new List<NetworkUpdateStage>();
126+
127+
/// <summary>
128+
/// Assures all update stages were in alginment with one another
129+
/// </summary>
130+
/// <returns>true or false</returns>
131+
public bool ValidateUpdateStages()
132+
{
133+
var validated = false;
134+
if (m_ServerStagesReceived.Count == m_ClientStagesReceived.Count && m_ClientStagesReceived.Count == m_StagesSent.Count)
135+
{
136+
for (int i = 0; i < m_StagesSent.Count; i++)
137+
{
138+
var currentStage = m_StagesSent[i];
139+
if (m_ServerStagesReceived[i] != currentStage)
140+
{
141+
Debug.Log($"ServerRpc Update Stage ({m_ServerStagesReceived[i]}) is not equal to the current update stage ({currentStage})");
142+
143+
return validated;
144+
}
145+
146+
if (m_ClientStagesReceived[i] != currentStage)
147+
{
148+
Debug.Log($"ClientRpc Update Stage ({m_ClientStagesReceived[i]}) is not equal to the current update stage ({currentStage})");
149+
150+
return validated;
151+
}
152+
}
153+
154+
validated = true;
155+
}
156+
157+
return validated;
158+
}
159+
160+
/// <summary>
161+
/// Server side RPC for testing
162+
/// </summary>
163+
/// <param name="parameters">server rpc parameters</param>
164+
[ServerRpc]
165+
private void PingMySelfServerRpc(int currentCount, ServerRpcParams parameters = default)
166+
{
167+
Debug.Log($"{nameof(PingMySelfServerRpc)}: [HostClient][ServerRpc][{currentCount}] invoked during the {parameters.Receive.UpdateStage} stage.");
168+
169+
m_ClientParams.Send.UpdateStage = parameters.Receive.UpdateStage;
170+
m_ServerStagesReceived.Add(parameters.Receive.UpdateStage);
171+
172+
PingMySelfClientRpc(currentCount, m_ClientParams);
173+
}
174+
175+
/// <summary>
176+
/// Client Side RPC called by PingMySelfServerRPC to validate both Client->Server and Server-Client pipeline is working
177+
/// </summary>
178+
/// <param name="parameters">client rpc parameters</param>
179+
[ClientRpc]
180+
private void PingMySelfClientRpc(int currentCount, ClientRpcParams parameters = default)
181+
{
182+
Debug.Log($"{nameof(PingMySelfClientRpc)}: [HostServer][ClientRpc][{currentCount}] invoked during the {parameters.Receive.UpdateStage} stage. (previous output line should confirm this)");
183+
184+
m_ClientStagesReceived.Add(parameters.Receive.UpdateStage);
185+
186+
//If we reached the last update state, then go ahead and increment our iteration counter
187+
if (parameters.Receive.UpdateStage == NetworkUpdateStage.PostLateUpdate)
188+
{
189+
m_Counter++;
190+
}
191+
192+
m_ClientReceivedRpc = true;
193+
}
194+
}
195+
}

com.unity.multiplayer.mlapi/Tests/Runtime/RpcPipelineTestComponent.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
using System.Collections;
2+
using UnityEngine;
3+
using UnityEngine.SceneManagement;
4+
using UnityEngine.TestTools;
5+
using NUnit.Framework;
6+
using MLAPI.SceneManagement;
7+
using MLAPI.Transports.UNET;
8+
9+
namespace MLAPI.RuntimeTests
10+
{
11+
/// <summary>
12+
/// The RpcQueue unit tests to validate:
13+
/// - Sending and Receiving pipeline to validate that both sending and receiving pipelines are functioning properly.
14+
/// - Usage of the ServerRpcParams.Send.UpdateStage and ClientRpcParams.Send.UpdateStage functionality.
15+
/// - Rpcs receive will be invoked at the appropriate NetworkUpdateStage.
16+
/// Requires: RpcPipelineTestComponent
17+
/// </summary>
18+
public class RpcQueueTests
19+
{
20+
private NetworkManager m_NetworkManager;
21+
22+
/// <summary>
23+
/// Tests the egress and ingress RPC queue functionality
24+
/// ** This does not include any of the MLAPI to Transport code **
25+
/// </summary>
26+
/// <returns>IEnumerator</returns>
27+
[UnityTest]
28+
public IEnumerator RpcQueueUnitTest()
29+
{
30+
#if UNITY_2020_2_OR_NEWER // Disabling this test on 2019.4 due to ILPP issues on Yamato CI/CD runs
31+
var networkManagerObject = new GameObject(nameof(NetworkManager));
32+
m_NetworkManager = networkManagerObject.AddComponent<NetworkManager>();
33+
var unetTransport = networkManagerObject.AddComponent<UnetTransport>();
34+
m_NetworkManager.NetworkConfig = new Configuration.NetworkConfig
35+
{
36+
CreatePlayerPrefab = false,
37+
AllowRuntimeSceneChanges = true,
38+
EnableSceneManagement = false
39+
};
40+
unetTransport.ConnectAddress = "127.0.0.1";
41+
unetTransport.ConnectPort = 7777;
42+
unetTransport.ServerListenPort = 7777;
43+
unetTransport.MessageBufferSize = 65535;
44+
unetTransport.MaxConnections = 100;
45+
unetTransport.MessageSendMode = UnetTransport.SendMode.Immediately;
46+
m_NetworkManager.NetworkConfig.NetworkTransport = unetTransport;
47+
48+
var currentActiveScene = SceneManager.GetActiveScene();
49+
var instantiatedNetworkManager = false;
50+
var testsAreComplete = false;
51+
var testsAreValidated = false;
52+
var exceededMaximumStageIterations = false;
53+
54+
//Add our test scene name
55+
NetworkSceneManager.AddRuntimeSceneName(currentActiveScene.name, 0);
56+
57+
//Create the player object that we will spawn as a host
58+
var playerObject = new GameObject("RpcTestObject");
59+
playerObject.AddComponent<NetworkObject>();
60+
var rpcPipelineTestComponent = playerObject.AddComponent<RpcPipelineTestComponent>();
61+
62+
instantiatedNetworkManager = true;
63+
Debug.Log("NetworkManager Instantiated.");
64+
65+
//Start as host mode as loopback only works in hostmode
66+
NetworkManager.Singleton.StartHost();
67+
Debug.Log("Host Started.");
68+
69+
//Enable the simple ping test
70+
rpcPipelineTestComponent.PingSelfEnabled = true;
71+
72+
Debug.Log("Running RPC Queue Tests...");
73+
74+
//Wait for the rpc pipeline test to complete or if we exceeded the maximum iterations bail
75+
while (!testsAreComplete && !exceededMaximumStageIterations)
76+
{
77+
//Wait for 20ms
78+
yield return new WaitForSeconds(0.02f);
79+
80+
testsAreComplete = rpcPipelineTestComponent.IsTestComplete();
81+
exceededMaximumStageIterations = rpcPipelineTestComponent.ExceededMaxIterations();
82+
}
83+
84+
if (!exceededMaximumStageIterations)
85+
{
86+
testsAreValidated = rpcPipelineTestComponent.ValidateUpdateStages();
87+
}
88+
89+
//Stop pinging
90+
rpcPipelineTestComponent.PingSelfEnabled = false;
91+
Debug.Log("RPC Queue Testing completed.");
92+
93+
//Stop the host
94+
NetworkManager.Singleton.StopHost();
95+
96+
//Shutdown the NetworkManager
97+
NetworkManager.Singleton.Shutdown();
98+
99+
Debug.Log($"Exiting status => {nameof(testsAreComplete)}: {testsAreComplete} - {nameof(testsAreValidated)}: {testsAreValidated} - {nameof(instantiatedNetworkManager)}: {instantiatedNetworkManager} - {nameof(exceededMaximumStageIterations)}: {exceededMaximumStageIterations}");
100+
101+
Assert.IsTrue(testsAreComplete && testsAreValidated && instantiatedNetworkManager);
102+
103+
GameObject.DestroyImmediate(playerObject);
104+
GameObject.DestroyImmediate(networkManagerObject);
105+
#else
106+
yield return null;
107+
#endif
108+
}
109+
}
110+
}

com.unity.multiplayer.mlapi/Tests/Runtime/RpcQueueTests.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)