Skip to content

Commit ba30286

Browse files
test: Allow for the detection of whether to run locally or remotely. (#2054)
* Set up for launching remotely * Set up for launching remotely * Report on WorkerCount and LaunchRemotely state * Store the Process as it will complete later * add a little more logging * Simplified name * Update GetWorkerCount to no longer set internal state * Update BaseMultiprocessTests.cs respond to PR feedback Co-authored-by: ashwini <36935028+ashwinimurt@users.noreply.github.com>
1 parent 399b8ab commit ba30286

File tree

3 files changed

+128
-15
lines changed

3 files changed

+128
-15
lines changed

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

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
35
using NUnit.Framework;
46
using UnityEngine;
57
using UnityEngine.SceneManagement;
@@ -22,6 +24,14 @@ public MultiprocessTestsAttribute() : base(MultiprocessCategoryName) { }
2224
[MultiprocessTests]
2325
public abstract class BaseMultiprocessTests
2426
{
27+
protected string[] platformList { get; set; }
28+
29+
protected int GetWorkerCount()
30+
{
31+
platformList = MultiprocessOrchestration.GetRemotePlatformList();
32+
return platformList == null ? WorkerCount : platformList.Length;
33+
}
34+
protected bool m_LaunchRemotely;
2535
private bool m_HasSceneLoaded = false;
2636
// TODO: Remove UTR check once we have Multiprocess tests fully working
2737
protected bool IgnoreMultiprocessTests => MultiprocessOrchestration.ShouldIgnoreUTRTests();
@@ -30,7 +40,7 @@ public abstract class BaseMultiprocessTests
3040

3141
/// <summary>
3242
/// Implement this to specify the amount of workers to spawn from your main test runner
33-
/// TODO there's a good chance this will be re-factored with something fancier once we start integrating with bokken
43+
/// Note: If using remote workers, the woorker count will come from the environment variable
3444
/// </summary>
3545
protected abstract int WorkerCount { get; }
3646

@@ -131,16 +141,16 @@ private bool VerifySceneIsValidForClientsToLoad(int sceneIndex, string sceneName
131141
public virtual IEnumerator Setup()
132142
{
133143
yield return new WaitUntil(() => NetworkManager.Singleton != null);
134-
MultiprocessLogger.Log("NetworkManager.Singleton != null");
135144
yield return new WaitUntil(() => NetworkManager.Singleton.IsServer);
136-
MultiprocessLogger.Log("NetworkManager.Singleton.IsServer");
137145
yield return new WaitUntil(() => NetworkManager.Singleton.IsListening);
138-
MultiprocessLogger.Log("NetworkManager.Singleton.IsListening");
139146
yield return new WaitUntil(() => m_HasSceneLoaded == true);
140-
MultiprocessLogger.Log("m_HasSceneLoaded");
141147
var startTime = Time.time;
148+
m_LaunchRemotely = MultiprocessOrchestration.IsRemoteOperationEnabled();
142149

143-
MultiprocessLogger.Log($"Active Worker Count is {MultiprocessOrchestration.ActiveWorkerCount()} and connected client count is {NetworkManager.Singleton.ConnectedClients.Count}");
150+
MultiprocessLogger.Log($"Active Worker Count is {MultiprocessOrchestration.ActiveWorkerCount()}" +
151+
$" and connected client count is {NetworkManager.Singleton.ConnectedClients.Count} " +
152+
$" and WorkerCount is {GetWorkerCount()} " +
153+
$" and LaunchRemotely is {m_LaunchRemotely}");
144154
if (MultiprocessOrchestration.ActiveWorkerCount() + 1 < NetworkManager.Singleton.ConnectedClients.Count)
145155
{
146156
MultiprocessLogger.Log("Is this a bad state?");
@@ -149,20 +159,32 @@ public virtual IEnumerator Setup()
149159
// Moved this out of OnSceneLoaded as OnSceneLoaded is a callback from the SceneManager and just wanted to avoid creating
150160
// processes from within the same callstack/context as the SceneManager. This will instantiate up to the WorkerCount and
151161
// then any subsequent calls to Setup if there are already workers it will skip this step
152-
if (NetworkManager.Singleton.ConnectedClients.Count - 1 < WorkerCount)
162+
if (!m_LaunchRemotely)
153163
{
154-
var numProcessesToCreate = WorkerCount - (NetworkManager.Singleton.ConnectedClients.Count - 1);
155-
for (int i = 1; i <= numProcessesToCreate; i++)
164+
if (NetworkManager.Singleton.ConnectedClients.Count - 1 < WorkerCount)
156165
{
157-
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()} ");
158-
string logPath = MultiprocessOrchestration.StartWorkerNode(); // will automatically start built player as clients
159-
MultiprocessLogger.Log($"logPath to new process is {logPath}");
160-
MultiprocessLogger.Log($"Active Worker Count {MultiprocessOrchestration.ActiveWorkerCount()} and connected client count is {NetworkManager.Singleton.ConnectedClients.Count}");
166+
var numProcessesToCreate = WorkerCount - (NetworkManager.Singleton.ConnectedClients.Count - 1);
167+
for (int i = 1; i <= numProcessesToCreate; i++)
168+
{
169+
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()} ");
170+
string logPath = MultiprocessOrchestration.StartWorkerNode(); // will automatically start built player as clients
171+
MultiprocessLogger.Log($"logPath to new process is {logPath}");
172+
MultiprocessLogger.Log($"Active Worker Count {MultiprocessOrchestration.ActiveWorkerCount()} and connected client count is {NetworkManager.Singleton.ConnectedClients.Count}");
173+
}
161174
}
162175
}
163176
else
164177
{
165-
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}");
178+
var launchProcessList = new List<Process>();
179+
if (NetworkManager.Singleton.ConnectedClients.Count - 1 < GetWorkerCount())
180+
{
181+
var machines = MultiprocessOrchestration.GetRemoteMachineList();
182+
foreach (var machine in machines)
183+
{
184+
MultiprocessLogger.Log($"Would launch on {machine.Name} too get worker count to {GetWorkerCount()} from {NetworkManager.Singleton.ConnectedClients.Count - 1}");
185+
launchProcessList.Add(MultiprocessOrchestration.StartWorkersOnRemoteNodes(machine));
186+
}
187+
}
166188
}
167189

168190
var timeOutTime = Time.realtimeSinceStartup + TestCoordinator.MaxWaitTimeoutSec;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public void LogFormat(LogType logType, UnityEngine.Object context, string format
6262
testName = "unknown";
6363
}
6464

65-
Debug.unityLogger.logHandler.LogFormat(logType, context, $"MPLOG({DateTime.Now:T}) : {testName} : {format}", args);
65+
Debug.LogFormat(logType, LogOption.NoStacktrace, context, $"MPLOG({DateTime.Now:T}) : {testName} : {format}", args);
6666
}
6767
}
6868
}

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

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ public static DirectoryInfo MultiprocessDirInfo
2121
}
2222
private static List<Process> s_Processes = new List<Process>();
2323
private static int s_TotalProcessCounter = 0;
24+
public static string PathToDll { get; private set; }
25+
public static List<Process> ProcessList = new List<Process>();
26+
private static FileInfo s_Localip_fileinfo;
2427

2528
private static DirectoryInfo initMultiprocessDirinfo()
2629
{
@@ -39,12 +42,27 @@ private static DirectoryInfo initMultiprocessDirinfo()
3942
{
4043
MultiprocessDirInfo.Create();
4144
}
45+
s_Localip_fileinfo = new FileInfo(Path.Combine(s_MultiprocessDirInfo.FullName, "localip"));
46+
4247
return s_MultiprocessDirInfo;
4348
}
4449

4550
static MultiprocessOrchestration()
4651
{
4752
initMultiprocessDirinfo();
53+
MultiprocessLogger.Log($" userprofile: {s_MultiprocessDirInfo.FullName} localipfile: {s_Localip_fileinfo}");
54+
var rootdir_FileInfo = new FileInfo(Path.Combine(MultiprocessDirInfo.FullName, "rootdir"));
55+
MultiprocessLogger.Log($"Checking for the existence of {rootdir_FileInfo.FullName}");
56+
if (rootdir_FileInfo.Exists)
57+
{
58+
var rootDirText = (File.ReadAllText(rootdir_FileInfo.FullName)).Trim();
59+
PathToDll = Path.Combine(rootDirText, "multiplayer-multiprocess-test-tools/BokkenForNetcode/ProvisionBokkenMachines/bin/Debug/netcoreapp3.1/osx-x64", "ProvisionBokkenMachines.dll");
60+
}
61+
else
62+
{
63+
MultiprocessLogger.Log("PathToDll cannot be set as rootDir doesn't exist");
64+
PathToDll = "unknown";
65+
}
4866
}
4967

5068
/// <summary>
@@ -185,4 +203,77 @@ public static void ShutdownAllProcesses()
185203

186204
s_Processes.Clear();
187205
}
206+
207+
public static bool IsRemoteOperationEnabled()
208+
{
209+
string encodedPlatformList = Environment.GetEnvironmentVariable("MP_PLATFORM_LIST");
210+
if (encodedPlatformList != null && encodedPlatformList.Split(',').Length > 1)
211+
{
212+
return true;
213+
}
214+
return false;
215+
}
216+
217+
public static string[] GetRemotePlatformList()
218+
{
219+
// "default-win:test-win,default-mac:test-mac"
220+
if (!IsRemoteOperationEnabled())
221+
{
222+
return null;
223+
}
224+
string encodedPlatformList = Environment.GetEnvironmentVariable("MP_PLATFORM_LIST");
225+
string[] separated = encodedPlatformList.Split(',');
226+
return separated;
227+
}
228+
229+
public static List<FileInfo> GetRemoteMachineList()
230+
{
231+
var machineJson = new List<FileInfo>();
232+
foreach (var f in MultiprocessDirInfo.GetFiles("*.json"))
233+
{
234+
if (f.Name.Equals("remoteConfig.json"))
235+
{
236+
continue;
237+
}
238+
else
239+
{
240+
machineJson.Add(f);
241+
}
242+
}
243+
return machineJson;
244+
}
245+
246+
public static Process StartWorkersOnRemoteNodes(FileInfo machine)
247+
{
248+
string command = $" --command launch " +
249+
$"--input-path {machine.FullName} ";
250+
251+
var workerProcess = new Process();
252+
253+
workerProcess.StartInfo.FileName = Path.Combine("dotnet");
254+
workerProcess.StartInfo.UseShellExecute = false;
255+
workerProcess.StartInfo.RedirectStandardError = true;
256+
workerProcess.StartInfo.RedirectStandardOutput = true;
257+
workerProcess.StartInfo.Arguments = $"{PathToDll} {command} ";
258+
try
259+
{
260+
var newProcessStarted = workerProcess.Start();
261+
262+
if (!newProcessStarted)
263+
{
264+
throw new Exception("Failed to start worker process!");
265+
}
266+
}
267+
catch (Win32Exception e)
268+
{
269+
MultiprocessLogger.LogError($"Error starting bokken process, {e.Message} {e.Data} {e.ErrorCode}");
270+
throw;
271+
}
272+
273+
274+
ProcessList.Add(workerProcess);
275+
276+
MultiprocessLogger.Log($"Execute Command: {PathToDll} {command} End");
277+
return workerProcess;
278+
}
188279
}

0 commit comments

Comments
 (0)