Skip to content

Commit af827f3

Browse files
zain-mecklaiNoelStephensUnitySamuelBellomoJesse Olmer
authored
test: enable multiprocess tests on windows mac and ubuntu (#1195)
Co-authored-by: NoelStephensUnity <[email protected]> Co-authored-by: Noel Stephens <[email protected]> Co-authored-by: Sam Bellomo <[email protected]> Co-authored-by: Jesse Olmer <[email protected]>
1 parent 5fc93b9 commit af827f3

14 files changed

+301
-81
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,10 @@
33
.vscode
44
.idea
55
.DS_Store
6+
.bin
7+
.Editor
8+
upm-ci~
9+
utr
10+
utr.bat
11+
.download
12+

.yamato/_run-all.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ run_all_tests:
1414
- .yamato/package-tests.yml#test_{{ project.name}}_{{ package.name }}_{{ editor }}_{{ platform.name }}
1515
{% endfor -%}
1616
- .yamato/project-tests.yml#test_{{ project.name }}_{{ editor }}_{{ platform.name }}
17+
- .yamato/project-tests.yml#multiprocess_test_testproject_{{ editor }}_{{ platform.name }}
1718
{% endfor -%}
1819
{% endfor -%}
1920
{% endfor -%}

.yamato/project-tests.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,38 @@ test_{{ project.name }}_{{ editor }}_{{ platform.name }}:
5454
{% endfor -%}
5555
{% endfor -%}
5656
{% endfor -%}
57+
58+
{% for project in projects -%}
59+
{% if project.name == "testproject" %}
60+
{% for editor in project.test_editors -%}
61+
{% for platform in test_platforms -%}
62+
multiprocess_test_testproject_{{ editor }}_{{ platform.name }}:
63+
name : multiprocess tests - {{ editor }} on {{ platform.name }}
64+
agent:
65+
type: {{ platform.type }}
66+
image: {{ platform.image }}
67+
flavor: {{ platform.flavor}}
68+
commands:
69+
- pip install unity-downloader-cli --index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
70+
- unity-downloader-cli -u {{ editor }} -c editor -w --fast
71+
- curl -s https://artifactory.prd.it.unity3d.com/artifactory/unity-tools-local/utr-standalone/utr{% if platform.name == "win" %}.bat --output utr.bat{% endif %}{% if platform.name != "win" %} --output utr && chmod +x ./utr{% endif %}
72+
- {{ platform.editorpath }} -projectpath testproject -batchmode -nographics -quit -logfile BuildMultiprocessTestPlayer.log -executeMethod Unity.Netcode.MultiprocessRuntimeTests.BuildMultiprocessTestPlayer.BuildRelease
73+
{% if platform.name == "mac" %} - sudo codesign --force --deep --sign - ./testproject/Builds/MultiprocessTests/MultiprocessTestPlayer.app{% endif %}
74+
- {{ platform.utr }} --suite=playmode --testproject=testproject --editor-location=.Editor --testfilter=Unity.Netcode.MultiprocessRuntimeTests --extra-editor-arg=-bypassIgnoreUTR
75+
after:
76+
{% if platform.name == "win" %} - copy %USERPROFILE%\.multiprocess\logfile* .{% endif %}
77+
{% if platform.name != "win" %} - cp $HOME/.multiprocess/logfile* .{% endif %}
78+
artifacts:
79+
logs:
80+
paths:
81+
- "upm-ci~/test-results/**/*"
82+
- BuildMultiprocessTestPlayer.log
83+
- "logfile*"
84+
- "*.log"
85+
- "*.txt"
86+
dependencies:
87+
- .yamato/project-pack.yml#pack_{{ project.name }}
88+
{% endfor -%}
89+
{% endfor -%}
90+
{% endif -%}
91+
{% endfor -%}

.yamato/project.metafile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ test_platforms:
88
image: package-ci/win10:stable
99
flavor: b1.large
1010
editorpath: .Editor\Unity.exe
11+
utr: .\utr.bat
1112
- name: mac
1213
type: Unity::VM::osx
1314
image: package-ci/mac:stable
14-
flavor: m1.mac
15+
flavor: b1.large
1516
editorpath: .Editor/Unity.app/Contents/MacOS/Unity
17+
utr: ./utr
1618
- name: ubuntu
1719
type: Unity::VM
1820
image: package-ci/ubuntu:stable
1921
flavor: b1.large
2022
editorpath: .Editor/Unity
23+
utr: ./utr
2124

2225
# Projects within the repository that will be tested. Name will be used
2326
# for job ids, so it should not contain spaces/non-supported characters

testproject/Assets/Scenes/MultiprocessTestScene.unity

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ LightingSettings:
262262
m_PVREnvironmentReferencePointCount: 2048
263263
m_LightProbeSampleCountMultiplier: 4
264264
m_PVRBounces: 2
265-
m_PVRMinBounces: 1
265+
m_PVRMinBounces: 2
266266
m_PVREnvironmentMIS: 1
267267
m_PVRFilteringMode: 1
268268
m_PVRDenoiserTypeDirect: 1
@@ -658,8 +658,8 @@ GameObject:
658658
m_Component:
659659
- component: {fileID: 1211923376}
660660
- component: {fileID: 1211923375}
661-
- component: {fileID: 1211923377}
662661
- component: {fileID: 1211923378}
662+
- component: {fileID: 1211923377}
663663
m_Layer: 0
664664
m_Name: '[NetworkManager] (Multiprocess)'
665665
m_TagString: Untagged
@@ -685,13 +685,6 @@ MonoBehaviour:
685685
NetworkConfig:
686686
ProtocolVersion: 0
687687
NetworkTransport: {fileID: 1674777073}
688-
RegisteredScenes:
689-
- MultiprocessTestScene
690-
- SampleScene
691-
RegisteredSceneAssets:
692-
- {fileID: 102900000, guid: 76743cb7b342c49279327834918a9c6e, type: 3}
693-
- {fileID: 102900000, guid: 9fc0d4010bbf28b4594072e72b8655ab, type: 3}
694-
AllowRuntimeSceneChanges: 0
695688
PlayerPrefab: {fileID: 4700706668509470175, guid: 7eeaaf9e50c0afc4dab93584a54fb0d6,
696689
type: 3}
697690
NetworkPrefabs:
@@ -707,7 +700,6 @@ MonoBehaviour:
707700
ConnectionData:
708701
EnableTimeResync: 0
709702
TimeResyncInterval: 30
710-
EnableNetworkVariable: 1
711703
EnsureNetworkVariableLengthSafety: 0
712704
EnableSceneManagement: 1
713705
ForceSamePrefabs: 1
@@ -742,10 +734,10 @@ MonoBehaviour:
742734
m_GameObject: {fileID: 1211923374}
743735
m_Enabled: 1
744736
m_EditorHideFlags: 0
745-
m_Script: {fileID: 0}
737+
m_Script: {fileID: 11500000, guid: 068bf11ceb1344667af4cc40950f44f4, type: 3}
746738
m_Name:
747739
m_EditorClassIdentifier:
748-
ReferencedPrefab: {fileID: 5637023994061915634, guid: b0952a471c5a147cb92f6afcdb648f8a,
740+
ReferencedPrefab: {fileID: 9115731988109684252, guid: c2851feb7276442cc86a6f2d1d69ea11,
749741
type: 3}
750742
--- !u!114 &1211923378
751743
MonoBehaviour:
@@ -868,12 +860,6 @@ MonoBehaviour:
868860
ConnectAddress: 127.0.0.1
869861
ConnectPort: 7777
870862
ServerListenPort: 7777
871-
ServerWebsocketListenPort: 8887
872-
SupportWebsocket: 0
873-
Channels: []
874-
UseNetcodeRelay: 0
875-
NetcodeRelayAddress: 127.0.0.1
876-
NetcodeRelayPort: 8888
877863
MessageSendMode: 0
878864
--- !u!1 &2027640071
879865
GameObject:
@@ -915,8 +901,13 @@ MonoBehaviour:
915901
m_GameObject: {fileID: 2027640071}
916902
m_Enabled: 1
917903
m_EditorHideFlags: 0
918-
m_Script: {fileID: 11500000, guid: fc5ef7b69296d69458910681f29471e6, type: 3}
904+
m_Script: {fileID: 11500000, guid: 6960e84d07fb87f47956e7a81d71c4e6, type: 3}
919905
m_Name:
920906
m_EditorClassIdentifier:
921-
Port: 7777
922-
Address: 127.0.0.1
907+
m_ProtocolType: 0
908+
m_MessageBufferSize: 6144
909+
m_ReciveQueueSize: 128
910+
m_SendQueueSize: 128
911+
m_SendQueueBatchSize: 4096
912+
m_ServerAddress: 127.0.0.1
913+
m_ServerPort: 7777

testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ public MultiprocessTestsAttribute() : base(MultiprocessCategoryName) { }
1717
[MultiprocessTests]
1818
public abstract class BaseMultiprocessTests
1919
{
20+
private bool m_HasSceneLoaded = false;
2021
// TODO: Remove UTR check once we have Multiprocess tests fully working
2122
protected bool IgnoreMultiprocessTests => MultiprocessOrchestration.ShouldIgnoreUTRTests();
2223

23-
2424
protected virtual bool IsPerformanceTest => true;
2525

2626
/// <summary>
@@ -38,6 +38,7 @@ public abstract class BaseMultiprocessTests
3838
[OneTimeSetUp]
3939
public virtual void SetupTestSuite()
4040
{
41+
MultiprocessLogger.Log("Running SetupTestSuite - OneTimeSetup");
4142
if (IgnoreMultiprocessTests)
4243
{
4344
Assert.Ignore("Ignoring tests under UTR. For testing, include the \"-bypassIgnoreUTR\" command line parameter.");
@@ -47,7 +48,7 @@ public virtual void SetupTestSuite()
4748
{
4849
Assert.Ignore("Performance tests should be run from remote test execution on device (this can be ran using the \"run selected tests (your platform)\" button");
4950
}
50-
51+
MultiprocessLogger.Log($"Currently active scene {SceneManager.GetActiveScene().name}");
5152
var currentlyActiveScene = SceneManager.GetActiveScene();
5253

5354
// Just adding a sanity check here to help with debugging in the event that SetupTestSuite is
@@ -56,7 +57,9 @@ public virtual void SetupTestSuite()
5657
// or could not unload the BuildMultiprocessTestPlayer.MainSceneName.
5758
if (!currentlyActiveScene.name.StartsWith(k_FirstPartOfTestRunnerSceneName))
5859
{
59-
Debug.LogError($"Expected the currently active scene to begin with ({k_FirstPartOfTestRunnerSceneName}) but currently active scene is {currentlyActiveScene.name}");
60+
MultiprocessLogger.LogError(
61+
$"Expected the currently active scene to begin with ({k_FirstPartOfTestRunnerSceneName}) but" +
62+
$" currently active scene is {currentlyActiveScene.name}");
6063
}
6164
m_OriginalActiveScene = currentlyActiveScene;
6265

@@ -66,6 +69,7 @@ public virtual void SetupTestSuite()
6669

6770
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
6871
{
72+
MultiprocessLogger.Log($"OnSceneLoaded {scene.name}");
6973
SceneManager.sceneLoaded -= OnSceneLoaded;
7074
if (scene.name == BuildMultiprocessTestPlayer.MainSceneName)
7175
{
@@ -76,6 +80,8 @@ private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
7680

7781
// Use scene verification to make sure we don't try to get clients to synchronize the TestRunner scene
7882
NetworkManager.Singleton.SceneManager.VerifySceneBeforeLoading = VerifySceneIsValidForClientsToLoad;
83+
84+
m_HasSceneLoaded = true;
7985
}
8086

8187
/// <summary>
@@ -95,20 +101,40 @@ private bool VerifySceneIsValidForClientsToLoad(int sceneIndex, string sceneName
95101
[UnitySetUp]
96102
public virtual IEnumerator Setup()
97103
{
98-
yield return new WaitUntil(() => NetworkManager.Singleton != null && NetworkManager.Singleton.IsServer && NetworkManager.Singleton.IsListening);
104+
yield return new WaitUntil(() => NetworkManager.Singleton != null);
105+
MultiprocessLogger.Log("NetworkManager.Singleton != null");
106+
yield return new WaitUntil(() => NetworkManager.Singleton.IsServer);
107+
MultiprocessLogger.Log("NetworkManager.Singleton.IsServer");
108+
yield return new WaitUntil(() => NetworkManager.Singleton.IsListening);
109+
MultiprocessLogger.Log("NetworkManager.Singleton.IsListening");
110+
yield return new WaitUntil(() => m_HasSceneLoaded == true);
111+
MultiprocessLogger.Log("m_HasSceneLoaded");
99112
var startTime = Time.time;
100113

114+
MultiprocessLogger.Log($"Active Worker Count is {MultiprocessOrchestration.ActiveWorkerCount()} and connected client count is {NetworkManager.Singleton.ConnectedClients.Count}");
115+
if (MultiprocessOrchestration.ActiveWorkerCount() + 1 < NetworkManager.Singleton.ConnectedClients.Count)
116+
{
117+
MultiprocessLogger.Log("Is this a bad state?");
118+
}
119+
101120
// Moved this out of OnSceneLoaded as OnSceneLoaded is a callback from the SceneManager and just wanted to avoid creating
102121
// processes from within the same callstack/context as the SceneManager. This will instantiate up to the WorkerCount and
103122
// then any subsequent calls to Setup if there are already workers it will skip this step
104-
if (MultiprocessOrchestration.Processes.Count < WorkerCount)
123+
if (NetworkManager.Singleton.ConnectedClients.Count - 1 < WorkerCount)
105124
{
106-
var numProcessesToCreate = WorkerCount - MultiprocessOrchestration.Processes.Count;
107-
for (int i = 0; i < numProcessesToCreate; i++)
125+
var numProcessesToCreate = WorkerCount - (NetworkManager.Singleton.ConnectedClients.Count - 1);
126+
for (int i = 1; i <= numProcessesToCreate; i++)
108127
{
109-
MultiprocessOrchestration.StartWorkerNode(); // will automatically start built player as clients
128+
MultiprocessLogger.Log($"Spawning testplayer {i} since connected client count is {NetworkManager.Singleton.ConnectedClients.Count} is less than {WorkerCount} and Number of spawned external players is {MultiprocessOrchestration.ActiveWorkerCount()} ");
129+
string logPath = MultiprocessOrchestration.StartWorkerNode(); // will automatically start built player as clients
130+
MultiprocessLogger.Log($"logPath to new process is {logPath}");
131+
MultiprocessLogger.Log($"Active Worker Count {MultiprocessOrchestration.ActiveWorkerCount()} and connected client count is {NetworkManager.Singleton.ConnectedClients.Count}");
110132
}
111133
}
134+
else
135+
{
136+
MultiprocessLogger.Log($"No need to spawn a new test player as there are already existing processes {MultiprocessOrchestration.ActiveWorkerCount()} and connected clients {NetworkManager.Singleton.ConnectedClients.Count}");
137+
}
112138

113139
var timeOutTime = Time.realtimeSinceStartup + TestCoordinator.MaxWaitTimeoutSec;
114140
while (NetworkManager.Singleton.ConnectedClients.Count <= WorkerCount)
@@ -117,15 +143,18 @@ public virtual IEnumerator Setup()
117143

118144
if (Time.realtimeSinceStartup > timeOutTime)
119145
{
120-
throw new Exception($"waiting too long to see clients to connect, got {NetworkManager.Singleton.ConnectedClients.Count - 1} clients, but was expecting {WorkerCount}, failing");
146+
throw new Exception($" {DateTime.Now:T} Waiting too long to see clients to connect, got {NetworkManager.Singleton.ConnectedClients.Count - 1} clients, and ActiveWorkerCount: {MultiprocessOrchestration.ActiveWorkerCount()} but was expecting {WorkerCount}, failing");
121147
}
122148
}
123149
TestCoordinator.Instance.KeepAliveClientRpc();
150+
MultiprocessLogger.Log($"Active Worker Count {MultiprocessOrchestration.ActiveWorkerCount()} and connected client count is {NetworkManager.Singleton.ConnectedClients.Count}");
124151
}
125152

153+
126154
[TearDown]
127155
public virtual void Teardown()
128156
{
157+
MultiprocessLogger.Log("Running teardown");
129158
if (!IgnoreMultiprocessTests)
130159
{
131160
TestCoordinator.Instance.TestRunTeardown();
@@ -135,16 +164,23 @@ public virtual void Teardown()
135164
[OneTimeTearDown]
136165
public virtual void TeardownSuite()
137166
{
167+
MultiprocessLogger.Log($"TeardownSuite");
138168
if (!IgnoreMultiprocessTests)
139169
{
170+
MultiprocessLogger.Log($"TeardownSuite - ShutdownAllProcesses");
140171
MultiprocessOrchestration.ShutdownAllProcesses();
172+
MultiprocessLogger.Log($"TeardownSuite - NetworkManager.Singleton.Shutdown");
141173
NetworkManager.Singleton.Shutdown();
142174
Object.Destroy(NetworkManager.Singleton.gameObject); // making sure we clear everything before reloading our scene
175+
MultiprocessLogger.Log($"Currently active scene {SceneManager.GetActiveScene().name}");
176+
MultiprocessLogger.Log($"m_OriginalActiveScene.IsValid {m_OriginalActiveScene.IsValid()}");
143177
if (m_OriginalActiveScene.IsValid())
144178
{
145179
SceneManager.SetActiveScene(m_OriginalActiveScene);
146180
}
181+
MultiprocessLogger.Log($"TeardownSuite - Unload {BuildMultiprocessTestPlayer.MainSceneName}");
147182
SceneManager.UnloadSceneAsync(BuildMultiprocessTestPlayer.MainSceneName);
183+
MultiprocessLogger.Log($"TeardownSuite - Unload {BuildMultiprocessTestPlayer.MainSceneName}");
148184
}
149185
}
150186
}

testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ public ExecuteStepInContext(StepExecutionContext actionContext, Action<byte[]> s
207207
{
208208
if (networkManager.IsServer)
209209
{
210-
TestCoordinator.Instance.TriggerActionIdClientRpc(currentActionId, paramToPass,
210+
TestCoordinator.Instance.TriggerActionIdClientRpc(currentActionId, paramToPass, m_IgnoreTimeoutException,
211211
clientRpcParams: new ClientRpcParams
212212
{
213213
Send = new ClientRpcSendParams { TargetClientIds = TestCoordinator.AllClientIdsExceptMine.ToArray() }

testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,4 @@ void UpdateFunc(float _)
258258
}
259259
}
260260
}
261+

testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/CallbackComponent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ private void Update()
1717
}
1818
catch (Exception e)
1919
{
20-
TestCoordinator.Instance.WriteErrorServerRpc(e.Message);
20+
TestCoordinator.Instance.WriteErrorServerRpc(e.ToString());
2121
throw;
2222
}
2323
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using UnityEngine;
2+
using System;
3+
using NUnit.Framework;
4+
5+
namespace Unity.Netcode.MultiprocessRuntimeTests
6+
{
7+
public class MultiprocessLogger
8+
{
9+
private static Logger s_Logger;
10+
11+
static MultiprocessLogger() => s_Logger = new Logger(logHandler: new MultiprocessLogHandler());
12+
13+
public static void Log(string msg)
14+
{
15+
s_Logger.Log(msg);
16+
}
17+
18+
public static void LogError(string msg)
19+
{
20+
s_Logger.LogError("", msg);
21+
}
22+
23+
public static void LogWarning(string msg)
24+
{
25+
s_Logger.LogWarning("", msg);
26+
}
27+
}
28+
29+
public class MultiprocessLogHandler : ILogHandler
30+
{
31+
public void LogException(Exception exception, UnityEngine.Object context)
32+
{
33+
Debug.unityLogger.LogException(exception, context);
34+
}
35+
36+
public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args)
37+
{
38+
string testName = null;
39+
try
40+
{
41+
testName = TestContext.CurrentContext.Test.Name;
42+
}
43+
catch (Exception)
44+
{
45+
// ignored
46+
}
47+
48+
if (string.IsNullOrEmpty(testName))
49+
{
50+
testName = "unknown";
51+
}
52+
53+
Debug.unityLogger.logHandler.LogFormat(logType, context, $"MPLOG({DateTime.Now:T}) : {testName} : {format}", args);
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)