Skip to content

Commit ee6684c

Browse files
committed
chore: Add a DA service unit test
1 parent 10ef2eb commit ee6684c

File tree

6 files changed

+195
-54
lines changed

6 files changed

+195
-54
lines changed

.yamato/desktop-standalone-tests.yml

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# DESCRIPTION--------------------------------------------------------------------------
55
# This job is responsible for Desktop platform test validation.
66
# Those tests cover both PlayMode and EditMode tests from package test assemblies.
7-
7+
88
# CONFIGURATION STRUCTURE--------------------------------------------------------------
99
# Jobs are generated using nested loops (separate build phase and run phase). Worth noting that run phase uses the build as dependency:
1010
# 1. For all desktop platform (Windows, macOS, Ubuntu)
@@ -17,17 +17,17 @@
1717
# 1. Build Phase: Creates standalone players for desktop platforms
1818
# 2. Run Phase: Executes runtime tests on actual desktop devices
1919
# The Run phase uses build job as dependency
20-
20+
2121
# Note: More of a Unity specific but test assemblies need to be included in the build phase command
2222
# Note: All builds can be made on x64 machines since those are compatible with ARM64 target devices
2323

2424
# QUALITY THOUGHTS--------------------------------------------------------------------
2525
# TODO: consider adding all projects that have tests
2626
# To see where this job is included (in trigger job definitions) look into _triggers.yml file
27-
27+
2828
#-----------------------------------------------------------------------------------
29-
30-
29+
30+
3131
# BUILD PHASE CONFIGURATION------------------------------------------------------------------------------------
3232
{% for project in projects.default -%}
3333
{% for platform in test_platforms.desktop -%}
@@ -58,10 +58,10 @@ desktop_standalone_build_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{
5858
{% endfor -%}
5959
{% endfor -%}
6060
{% endfor -%}
61-
62-
63-
64-
61+
62+
63+
64+
6565
# RUN PHASE CONFIGURATION------------------------------------------------------------------------------------
6666
{% for project in projects.default -%}
6767
{% for platform in test_platforms.desktop -%}
@@ -81,21 +81,16 @@ desktop_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{
8181
{% if platform.name != "win" %} # Issues with win and mac are tracked in MTT-11606
8282
variables:
8383
ECHO_SERVER_PORT: "7788"
84+
COMB_SERVER_PORT: "7789"
8485
# Set this to ensure the DA codec tests will fail if they cannot connect to the echo-server
8586
# The default is to ignore the codec tests if the echo-server fails to connect
8687
ENSURE_CODEC_TESTS: "true"
8788
{% endif %}
8889

8990
commands:
90-
# If ubuntu, run rust echo server (This is needed ONLY for NGOv2.X because relates to Distributed Authority)
91+
# If not windows, run rust echo server (This is needed ONLY for NGOv2.X because relates to Distributed Authority)
9192
{% if platform.name != "win" %} # Issues with win and mac are tracked in MTT-11606
92-
- git clone https://github.com/Unity-Technologies/mps-common-multiplayer-backend.git
93-
# Install rust
94-
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
95-
# Build the echo server
96-
- cd ./mps-common-multiplayer-backend/runtime && $HOME/.cargo/bin/cargo build --example ngo_echo_server
97-
# Run the echo server in the background - this will reuse the artifacts from the build
98-
- cd ./mps-common-multiplayer-backend/runtime && $HOME/.cargo/bin/cargo run --example ngo_echo_server -- --port $ECHO_SERVER_PORT &
93+
- ./Tools/CI/rust.sh
9994
{% endif %}
10095

10196
- unity-downloader-cli --fast --wait -u {{ editor }} -c Editor {% if backend == "il2cpp" %} -c il2cpp {% endif %} {% if platform.name == "mac" %} --arch arm64 {% endif %} # For macOS we use ARM64 models

Tools/CI/rust.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# clone the latest rust repo
2+
git clone https://github.com/Unity-Technologies/mps-common-multiplayer-backend.git
3+
cd ./mps-common-multiplayer-backend/runtime
4+
5+
# Install rust
6+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
7+
export PATH="$HOME/.cargo/bin:$PATH"
8+
9+
# Build the echo server
10+
cargo build --example ngo_echo_server
11+
12+
# Run the echo server in the background - this will reuse the artifacts from the build
13+
cargo run --example ngo_echo_server -- --port $ECHO_SERVER_PORT &
14+
15+
# Build the standalone server
16+
cargo build
17+
18+
# Run the standalone server loop in the background
19+
runstandalone &
20+
21+
# Use a function to run the standalone server in a loop, when it exits, it will always restart
22+
runstandalone() {
23+
while :; do
24+
# loop infinitely
25+
cargo run -- --metrics-port 5000 standalone --port $COMB_SERVER_PORT -t 10m
26+
done
27+
}

com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,8 @@ protected virtual bool ShouldWaitForNewClientToConnect(NetworkManager networkMan
522522
/// <returns>An IEnumerator to be used in a coroutine for asynchronous execution.</returns>
523523
protected IEnumerator CreateAndStartNewClient()
524524
{
525-
var networkManager = NetcodeIntegrationTestHelpers.CreateNewClient(m_ClientNetworkManagers.Length, m_EnableTimeTravel);
525+
bool useCmbService = UseCMBService() && m_DistributedAuthority;
526+
var networkManager = NetcodeIntegrationTestHelpers.CreateNewClient(m_ClientNetworkManagers.Length, m_EnableTimeTravel, useCmbService);
526527
networkManager.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
527528
SetDistributedAuthorityProperties(networkManager);
528529

@@ -576,14 +577,15 @@ private bool AllPlayerObjectClonesSpawned(NetworkManager joinedClient)
576577

577578
// Continue to populate the PlayerObjects list until all player object (local and clone) are found
578579
ClientNetworkManagerPostStart(joinedClient);
579-
var playerObjectRelative = m_ServerNetworkManager.SpawnManager.PlayerObjects.Where((c) => c.OwnerClientId == joinedClient.LocalClientId).FirstOrDefault();
580-
if (playerObjectRelative == null)
581-
{
582-
m_InternalErrorLog.Append($"[AllPlayerObjectClonesSpawned][Server-Side] Joining Client-{joinedClient.LocalClientId} was not populated in the {nameof(NetworkSpawnManager.PlayerObjects)} list!");
583-
return false;
584-
}
585-
else
580+
if (!(UseCMBService() && m_DistributedAuthority))
586581
{
582+
var playerObjectRelative = m_ServerNetworkManager.SpawnManager.PlayerObjects.Where((c) => c.OwnerClientId == joinedClient.LocalClientId).FirstOrDefault();
583+
if (playerObjectRelative == null)
584+
{
585+
m_InternalErrorLog.Append($"[AllPlayerObjectClonesSpawned][Server-Side] Joining Client-{joinedClient.LocalClientId} was not populated in the {nameof(NetworkSpawnManager.PlayerObjects)} list!");
586+
return false;
587+
}
588+
587589
// Go ahead and create an entry for this new client
588590
if (!m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId].ContainsKey(joinedClient.LocalClientId))
589591
{
@@ -598,19 +600,17 @@ private bool AllPlayerObjectClonesSpawned(NetworkManager joinedClient)
598600
continue;
599601
}
600602

601-
playerObjectRelative = clientNetworkManager.SpawnManager.PlayerObjects.Where((c) => c.OwnerClientId == joinedClient.LocalClientId).FirstOrDefault();
603+
var playerObjectRelative = clientNetworkManager.SpawnManager.PlayerObjects.Where((c) => c.OwnerClientId == joinedClient.LocalClientId).FirstOrDefault();
602604
if (playerObjectRelative == null)
603605
{
604606
m_InternalErrorLog.Append($"[AllPlayerObjectClonesSpawned][Client-{clientNetworkManager.LocalClientId}] Client-{joinedClient.LocalClientId} was not populated in the {nameof(NetworkSpawnManager.PlayerObjects)} list!");
605607
return false;
606608
}
607-
else
609+
610+
// Go ahead and create an entry for this new client
611+
if (!m_PlayerNetworkObjects[clientNetworkManager.LocalClientId].ContainsKey(joinedClient.LocalClientId))
608612
{
609-
// Go ahead and create an entry for this new client
610-
if (!m_PlayerNetworkObjects[clientNetworkManager.LocalClientId].ContainsKey(joinedClient.LocalClientId))
611-
{
612-
m_PlayerNetworkObjects[clientNetworkManager.LocalClientId].Add(joinedClient.LocalClientId, playerObjectRelative);
613-
}
613+
m_PlayerNetworkObjects[clientNetworkManager.LocalClientId].Add(joinedClient.LocalClientId, playerObjectRelative);
614614
}
615615
}
616616
return true;
@@ -722,7 +722,8 @@ protected void CreateServerAndClients(int numberOfClients)
722722
}
723723

724724
// Create multiple NetworkManager instances
725-
if (!NetcodeIntegrationTestHelpers.Create(numberOfClients, out NetworkManager server, out NetworkManager[] clients, m_TargetFrameRate, m_CreateServerFirst, m_EnableTimeTravel))
725+
var useCmbService = UseCMBService() && m_DistributedAuthority;
726+
if (!NetcodeIntegrationTestHelpers.Create(numberOfClients, out NetworkManager server, out NetworkManager[] clients, m_TargetFrameRate, m_CreateServerFirst, m_EnableTimeTravel, useCmbService))
726727
{
727728
Debug.LogError("Failed to create instances");
728729
Assert.Fail("Failed to create instances");
@@ -939,8 +940,9 @@ protected IEnumerator StartServerAndClients()
939940
if (m_UseHost || m_ServerNetworkManager.IsHost)
940941
{
941942
#if UNITY_2023_1_OR_NEWER
943+
var manager = startServer ? m_ServerNetworkManager : m_ClientNetworkManagers[0];
942944
// Add the server player instance to all m_ClientSidePlayerNetworkObjects entries
943-
var serverPlayerClones = Object.FindObjectsByType<NetworkObject>(FindObjectsSortMode.None).Where((c) => c.IsPlayerObject && c.OwnerClientId == m_ServerNetworkManager.LocalClientId);
945+
var serverPlayerClones = Object.FindObjectsByType<NetworkObject>(FindObjectsSortMode.None).Where((c) => c.IsPlayerObject && c.OwnerClientId == manager.LocalClientId);
944946
#else
945947
// Add the server player instance to all m_ClientSidePlayerNetworkObjects entries
946948
var serverPlayerClones = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsPlayerObject && c.OwnerClientId == m_ServerNetworkManager.LocalClientId);
@@ -952,7 +954,10 @@ protected IEnumerator StartServerAndClients()
952954
m_PlayerNetworkObjects.Add(playerNetworkObject.NetworkManager.LocalClientId, new Dictionary<ulong, NetworkObject>());
953955
}
954956

955-
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(m_ServerNetworkManager.LocalClientId, playerNetworkObject);
957+
if (startServer)
958+
{
959+
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(m_ServerNetworkManager.LocalClientId, playerNetworkObject);
960+
}
956961
}
957962
}
958963
if (m_DistributedAuthority)
@@ -967,7 +972,7 @@ protected IEnumerator StartServerAndClients()
967972
AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for all sessions to spawn Client-{networkManager.LocalClientId}'s player object!\n {m_InternalErrorLog}");
968973
}
969974
}
970-
if (m_ServerNetworkManager != null)
975+
if (m_ServerNetworkManager != null && startServer)
971976
{
972977
yield return WaitForConditionOrTimeOut(() => AllPlayerObjectClonesSpawned(m_ServerNetworkManager));
973978
AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for all sessions to spawn Client-{m_ServerNetworkManager.LocalClientId}'s player object!\n {m_InternalErrorLog}");
@@ -1534,8 +1539,10 @@ private bool CheckClientsConnected(NetworkManager[] clientsToCheck)
15341539
m_InternalErrorLog.AppendLine($"[Client-{i + 1}] Client is not connected!");
15351540
}
15361541
}
1537-
var expectedCount = m_ServerNetworkManager.IsHost ? clientsToCheck.Length + 1 : clientsToCheck.Length;
1538-
var currentCount = m_ServerNetworkManager.ConnectedClients.Count;
1542+
1543+
var manager = UseCMBService() ? m_ClientNetworkManagers[0] : m_ServerNetworkManager;
1544+
var expectedCount = manager.IsHost ? clientsToCheck.Length + 1 : clientsToCheck.Length;
1545+
var currentCount = manager.ConnectedClients.Count;
15391546

15401547
if (currentCount != expectedCount)
15411548
{

com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTestHelpers.cs

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,20 @@ public static void RegisterHandlers(NetworkManager networkManager, bool serverSi
170170
}
171171
}
172172

173-
private static void AddUnityTransport(NetworkManager networkManager)
173+
private static readonly string k_TransportHost = Environment.GetEnvironmentVariable("NGO_HOST") ?? "127.0.0.1";
174+
private static readonly ushort k_TransportPort = GetPortToBind();
175+
176+
/// <summary>
177+
/// Configures the port to look for the rust service.
178+
/// </summary>
179+
/// <returns>The port from the environment variable "ECHO_SERVER_PORT" if it is set and valid; otherwise uses port 7777</returns>
180+
private static ushort GetPortToBind()
181+
{
182+
var value = Environment.GetEnvironmentVariable("CMB_SERVICE_PORT");
183+
return ushort.TryParse(value, out var configuredPort) ? configuredPort : (ushort)7789;
184+
}
185+
186+
private static void AddUnityTransport(NetworkManager networkManager, bool useCmbService = false)
174187
{
175188
// Create transport
176189
var unityTransport = networkManager.gameObject.AddComponent<UnityTransport>();
@@ -181,6 +194,12 @@ private static void AddUnityTransport(NetworkManager networkManager)
181194
// Allow 4 connection attempts that each will time out after 500ms
182195
unityTransport.MaxConnectAttempts = 4;
183196
unityTransport.ConnectTimeoutMS = 500;
197+
if (useCmbService)
198+
{
199+
unityTransport.ConnectionData.Address = Dns.GetHostAddresses(k_TransportHost).First().ToString();
200+
unityTransport.ConnectionData.Port = k_TransportPort;
201+
Debug.Log($"Using CmbService: {k_TransportHost}:{k_TransportPort}");
202+
}
184203

185204
// Set the NetworkConfig
186205
networkManager.NetworkConfig ??= new NetworkConfig();
@@ -196,7 +215,7 @@ private static void AddMockTransport(NetworkManager networkManager)
196215
networkManager.NetworkConfig.NetworkTransport = mockTransport;
197216
}
198217

199-
public static NetworkManager CreateServer(bool mockTransport = false)
218+
public static NetworkManager CreateServer(bool mockTransport = false, bool useCmbService = false)
200219
{
201220
// Create gameObject
202221
var go = new GameObject("NetworkManager - Server");
@@ -210,7 +229,7 @@ public static NetworkManager CreateServer(bool mockTransport = false)
210229
}
211230
else
212231
{
213-
AddUnityTransport(server);
232+
AddUnityTransport(server, useCmbService);
214233
}
215234
return server;
216235
}
@@ -223,20 +242,21 @@ public static NetworkManager CreateServer(bool mockTransport = false)
223242
/// <param name="clients">The clients NetworkManagers</param>
224243
/// <param name="targetFrameRate">The targetFrameRate of the Unity engine to use while the multi instance helper is running. Will be reset on shutdown.</param>
225244
/// <param name="serverFirst">This determines if the server or clients will be instantiated first (defaults to server first)</param>
226-
public static bool Create(int clientCount, out NetworkManager server, out NetworkManager[] clients, int targetFrameRate = 60, bool serverFirst = true, bool useMockTransport = false)
245+
/// <param name="useCmbService">If true, the server transport will use a mock transport, and the clients will be created with a connection to a locally hosted da service</param>
246+
public static bool Create(int clientCount, out NetworkManager server, out NetworkManager[] clients, int targetFrameRate = 60, bool serverFirst = true, bool useMockTransport = false, bool useCmbService = false)
227247
{
228248
s_NetworkManagerInstances = new List<NetworkManager>();
229249
server = null;
230250
if (serverFirst)
231251
{
232-
server = CreateServer(useMockTransport);
252+
server = CreateServer(useMockTransport || useCmbService);
233253
}
234254

235-
CreateNewClients(clientCount, out clients, useMockTransport);
255+
CreateNewClients(clientCount, out clients, useMockTransport, useCmbService);
236256

237257
if (!serverFirst)
238258
{
239-
server = CreateServer(useMockTransport);
259+
server = CreateServer(useMockTransport || useCmbService);
240260
}
241261

242262
s_OriginalTargetFrameRate = Application.targetFrameRate;
@@ -245,7 +265,7 @@ public static bool Create(int clientCount, out NetworkManager server, out Networ
245265
return true;
246266
}
247267

248-
internal static NetworkManager CreateNewClient(int identifier, bool mockTransport = false)
268+
internal static NetworkManager CreateNewClient(int identifier, bool mockTransport = false, bool useCmbService = false)
249269
{
250270
// Create gameObject
251271
var go = new GameObject("NetworkManager - Client - " + identifier);
@@ -257,7 +277,7 @@ internal static NetworkManager CreateNewClient(int identifier, bool mockTranspor
257277
}
258278
else
259279
{
260-
AddUnityTransport(networkManager);
280+
AddUnityTransport(networkManager, useCmbService);
261281
}
262282
return networkManager;
263283
}
@@ -269,13 +289,14 @@ internal static NetworkManager CreateNewClient(int identifier, bool mockTranspor
269289
/// <param name="clientCount">The amount of clients</param>
270290
/// <param name="clients">Output array containing the created NetworkManager instances</param>
271291
/// <param name="useMockTransport">When true, uses mock transport for testing, otherwise uses real transport. Default value is false</param>
272-
public static bool CreateNewClients(int clientCount, out NetworkManager[] clients, bool useMockTransport = false)
292+
/// <param name="useCmbService">If true, each client will be created with transport configured to connect to a locally hosted da service</param>
293+
public static bool CreateNewClients(int clientCount, out NetworkManager[] clients, bool useMockTransport = false, bool useCmbService = false)
273294
{
274295
clients = new NetworkManager[clientCount];
275296
for (int i = 0; i < clientCount; i++)
276297
{
277298
// Create networkManager component
278-
clients[i] = CreateNewClient(i, useMockTransport);
299+
clients[i] = CreateNewClient(i, useMockTransport, useCmbService);
279300
}
280301

281302
NetworkManagerInstances.AddRange(clients);
@@ -486,15 +507,15 @@ public static bool Start(bool host, NetworkManager server, NetworkManager[] clie
486507
callback?.Invoke();
487508
}
488509

489-
for (int i = 0; i < clients.Length; i++)
510+
foreach (var client in clients)
490511
{
491-
clients[i].StartClient();
512+
client.StartClient();
492513
hooks = new MultiInstanceHooks();
493-
clients[i].ConnectionManager.MessageManager.Hook(hooks);
494-
s_Hooks[clients[i]] = hooks;
514+
client.ConnectionManager.MessageManager.Hook(hooks);
515+
s_Hooks[client] = hooks;
495516

496517
// if set, then invoke this for the client
497-
RegisterHandlers(clients[i]);
518+
RegisterHandlers(client);
498519
}
499520

500521
return true;

0 commit comments

Comments
 (0)