From 6d185e5d24a9836b164a0ddd6a7f79775bd3f69e Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 15:58:36 -0400 Subject: [PATCH 01/40] moving orchestration to this branch from test/multiprocess-testing/wip --- ...nity.multiplayer.mlapi.runtimetests.asmdef | 20 ++- testproject/.gitignore | 3 + testproject/Assets/StreamingAssets.meta | 8 ++ testproject/Assets/StreamingAssets/empty.txt | 0 .../Assets/StreamingAssets/empty.txt.meta | 7 ++ .../Helpers/BuildMultiprocessTestPlayer.cs | 118 ++++++++++++++++++ .../BuildMultiprocessTestPlayer.cs.meta | 11 ++ .../Helpers/MultiprocessOrchestration.cs | 61 +++++++++ .../Helpers/MultiprocessOrchestration.cs.meta | 11 ++ .../Runtime/testproject.runtimetests.asmdef | 22 +++- 10 files changed, 253 insertions(+), 8 deletions(-) create mode 100644 testproject/Assets/StreamingAssets.meta create mode 100644 testproject/Assets/StreamingAssets/empty.txt create mode 100644 testproject/Assets/StreamingAssets/empty.txt.meta create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs.meta create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs.meta diff --git a/com.unity.multiplayer.mlapi/Tests/Runtime/com.unity.multiplayer.mlapi.runtimetests.asmdef b/com.unity.multiplayer.mlapi/Tests/Runtime/com.unity.multiplayer.mlapi.runtimetests.asmdef index efbf850de3..07a21b8196 100644 --- a/com.unity.multiplayer.mlapi/Tests/Runtime/com.unity.multiplayer.mlapi.runtimetests.asmdef +++ b/com.unity.multiplayer.mlapi/Tests/Runtime/com.unity.multiplayer.mlapi.runtimetests.asmdef @@ -1,12 +1,24 @@ { "name": "Unity.Multiplayer.MLAPI.RuntimeTests", + "rootNamespace": "", "references": [ "Unity.Multiplayer.MLAPI.Runtime", + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", "Unity.Multiplayer.MLAPI.Editor" ], - "optionalUnityReferences": [ - "TestAssemblies" - ], "includePlatforms": [], - "excludePlatforms": [] + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS", + "UNITY_EDITOR" + ], + "versionDefines": [], + "noEngineReferences": false } \ No newline at end of file diff --git a/testproject/.gitignore b/testproject/.gitignore index 72c27e4fe2..933758634d 100644 --- a/testproject/.gitignore +++ b/testproject/.gitignore @@ -69,3 +69,6 @@ crashlytics-build.properties # Temporary auto-generated Android Assets /[Aa]ssets/[Ss]treamingAssets/aa.meta /[Aa]ssets/[Ss]treamingAssets/aa/* + +/[Aa]ssets/[Ss]treamingAssets/buildInfo.txt +/[Aa]ssets/[Ss]treamingAssets/buildInfo.txt.meta diff --git a/testproject/Assets/StreamingAssets.meta b/testproject/Assets/StreamingAssets.meta new file mode 100644 index 0000000000..2926e11ded --- /dev/null +++ b/testproject/Assets/StreamingAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 50c3bcef4ad84445a1f9eb2246d2e172 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/StreamingAssets/empty.txt b/testproject/Assets/StreamingAssets/empty.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testproject/Assets/StreamingAssets/empty.txt.meta b/testproject/Assets/StreamingAssets/empty.txt.meta new file mode 100644 index 0000000000..faaff388a0 --- /dev/null +++ b/testproject/Assets/StreamingAssets/empty.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ab2fb420f22574b13b33f6913b8736d8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs new file mode 100644 index 0000000000..b7917a266b --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -0,0 +1,118 @@ +using System; +using System.IO; +#if UNITY_EDITOR +using UnityEditor; +using UnityEditor.Build.Reporting; +#endif +using UnityEngine; + +/// +/// This is needed as Unity throws "An abnormal situation has occurred: the PlayerLoop internal function has been called recursively. Please contact Customer Support with a sample project so that we can reproduce the problem and troubleshoot it." +/// when trying to build from Setup() steps in tests. +/// +public class BuildMultiprocessTestPlayer : MonoBehaviour +{ + public const string multiprocessBaseMenuName = "MLAPI Multiprocess Test"; + public const string BuildAndExecuteMenuName = multiprocessBaseMenuName + "/Build - Execute multiprocess tests #%t"; + public static string buildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTestBuild"); + public const string mainSceneName = "MultiprocessTestingScene"; + + +#if UNITY_EDITOR + [MenuItem(multiprocessBaseMenuName+"/Build Test Player #t")] + public static void BuildNoExecute() + { + var success = Build(); + if (!success) + { + throw new Exception("Build failed!"); + } + } + + [MenuItem(multiprocessBaseMenuName+"/Build Test Player in debug mode")] + public static void BuildDebug() + { + var success = Build(true); + if (!success) + { + throw new Exception("Build failed!"); + } + } + + [MenuItem(multiprocessBaseMenuName+"/Delete Test Build")] + public static void DeleteBuild() + { + switch (Application.platform) + { + case RuntimePlatform.WindowsPlayer: + case RuntimePlatform.WindowsEditor: + var exePath = $"{buildPath}.exe"; + if (File.Exists(exePath)) + { + File.Delete(exePath); + } + else + { + Debug.Log($"exe {exePath} doesn't exists"); + } + break; + case RuntimePlatform.OSXPlayer: + case RuntimePlatform.OSXEditor: + var toDelete = buildPath + ".app"; + if (Directory.Exists(toDelete)) + { + Directory.Delete(toDelete, recursive: true); + } + else + { + Debug.Log($"directory {toDelete} doesn't exists"); + } + break; + default: + throw new NotImplementedException(); + } + } + + /// + /// Needs a separate build than the standalone test builds since we don't want the player to try to connect to the editor to do test + /// reporting. We only want to main node to do that, worker nodes should be dumb + /// + /// + public static bool Build(bool isDebug = false) + { + // Save standalone build path to file + var f = File.CreateText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.buildInfoFileName)); + f.Write(buildPath); + f.Close(); + + // var buildPath = Application.streamingAssetsPath; + // deleting so we don't end up testing on outdated builds if there's a build failure + DeleteBuild(); + + var buildOptions = BuildOptions.None; + buildOptions |= BuildOptions.IncludeTestAssemblies; + buildOptions |= BuildOptions.StrictMode; + if (isDebug) + { + buildOptions |= BuildOptions.Development; + buildOptions |= BuildOptions.AllowDebugging; // enable this if you want to debug your players. Your players + // will have more connection permission popups when launching though + } + + var buildPathToUse = buildPath; + if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor) + { + buildPathToUse += ".exe"; + } + + buildOptions &= ~BuildOptions.AutoRunPlayer; + var buildReport = BuildPipeline.BuildPlayer( + new[] { $"Assets/Scenes/{mainSceneName}.unity" }, + buildPathToUse, + EditorUserBuildSettings.activeBuildTarget, + buildOptions); + + return buildReport.summary.result == BuildResult.Succeeded; + } +#endif +} diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs.meta new file mode 100644 index 0000000000..87acf05da8 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b389565fd8544431db4c24940cb569c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs new file mode 100644 index 0000000000..7f9f84d82c --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs @@ -0,0 +1,61 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using UnityEditor; +using UnityEngine; +using Debug = UnityEngine.Debug; + +public class MultiprocessOrchestration +{ + public const string buildInfoFileName = "buildInfo.txt"; + public const string isWorkerArg = "-isWorker"; + + public static void StartWorkerNode() + { + var workerNode = new Process(); + + //TODO this should be replaced eventually by proper orchestration for all supported platforms + string buildInstructions = $"You probably didn't generate your build. Please make sure you build a player using the '{BuildMultiprocessTestPlayer.BuildAndExecuteMenuName}' menu"; + try + { + var buildInfo = File.ReadAllText(Path.Combine(Application.streamingAssetsPath, buildInfoFileName)); + switch (Application.platform) + { + case RuntimePlatform.OSXPlayer: + case RuntimePlatform.OSXEditor: + workerNode.StartInfo.FileName = $"{buildInfo}.app/Contents/MacOS/testproject"; + break; + case RuntimePlatform.WindowsPlayer: + case RuntimePlatform.WindowsEditor: + workerNode.StartInfo.FileName = $"{buildInfo}.exe"; + break; + default: + throw new NotImplementedException("StartWorkerNode: Current platform not supported"); + } + } + catch (FileNotFoundException) + { + throw new Exception($"Couldn't find build info file. {buildInstructions}"); + } + + workerNode.StartInfo.UseShellExecute = false; + workerNode.StartInfo.RedirectStandardError = true; + workerNode.StartInfo.RedirectStandardOutput = true; + workerNode.StartInfo.Arguments = $"{isWorkerArg} -popupwindow -screen-width 100 -screen-height 100"; + // workerNode.StartInfo.Arguments += " -deepprofiling"; // enable for deep profiling + try + { + var newProcessStarted = workerNode.Start(); + if (!newProcessStarted) + { + throw new Exception("Process not started!"); + } + } + catch (Win32Exception e) + { + Debug.LogError($"Error starting player, {buildInstructions}, {e.Message} {e.Data} {e.ErrorCode}"); + throw; + } + } +} diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs.meta new file mode 100644 index 0000000000..4797a6c5a7 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b59a46cbb2c54f4d977a05103227453 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/testproject.runtimetests.asmdef b/testproject/Assets/Tests/Runtime/testproject.runtimetests.asmdef index 2aa7afc6f7..45c640863c 100644 --- a/testproject/Assets/Tests/Runtime/testproject.runtimetests.asmdef +++ b/testproject/Assets/Tests/Runtime/testproject.runtimetests.asmdef @@ -1,11 +1,25 @@ { "name": "TestProject.RuntimeTests", + "rootNamespace": "", "references": [ "Unity.Multiplayer.MLAPI.Runtime", "Unity.Multiplayer.MLAPI.RuntimeTests", - "TestProject.ManualTests" + "TestProject.ManualTests", + "UnityEngine.TestRunner", + "UnityEditor.TestRunner" ], - "optionalUnityReferences": [ - "TestAssemblies" - ] + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS", + "UNITY_EDITOR" + ], + "versionDefines": [], + "noEngineReferences": false } \ No newline at end of file From 4f6d799560c3d5da95364c835174330a56e426f9 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 16:10:49 -0400 Subject: [PATCH 02/40] moving base for multiprocess tests to this branch from test/multiprocess-testing/wip --- .../Prefabs/PerfTestNetworkObject.prefab | 49 + .../Prefabs/PerfTestNetworkObject.prefab.meta | 7 + .../PerfTestVisualNetworkObject.prefab | 100 ++ .../PerfTestVisualNetworkObject.prefab.meta | 7 + .../Scenes/MultiprocessTestingScene.unity | 922 ++++++++++++++++++ .../MultiprocessTestingScene.unity.meta | 7 + .../BaseMultiprocessTests.cs | 87 ++ .../BaseMultiprocessTests.cs.meta | 11 + .../TestCoordinatorTests.cs | 70 ++ .../TestCoordinatorTests.cs.meta | 11 + ...ltiplayer.mlapi.multiprocessruntime.asmdef | 25 + ...ayer.mlapi.multiprocessruntime.asmdef.meta | 7 + 12 files changed, 1303 insertions(+) create mode 100644 testproject/Assets/Prefabs/PerfTestNetworkObject.prefab create mode 100644 testproject/Assets/Prefabs/PerfTestNetworkObject.prefab.meta create mode 100644 testproject/Assets/Prefabs/PerfTestVisualNetworkObject.prefab create mode 100644 testproject/Assets/Prefabs/PerfTestVisualNetworkObject.prefab.meta create mode 100644 testproject/Assets/Scenes/MultiprocessTestingScene.unity create mode 100644 testproject/Assets/Scenes/MultiprocessTestingScene.unity.meta create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs.meta create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs.meta create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/com.unity.multiplayer.mlapi.multiprocessruntime.asmdef create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/com.unity.multiplayer.mlapi.multiprocessruntime.asmdef.meta diff --git a/testproject/Assets/Prefabs/PerfTestNetworkObject.prefab b/testproject/Assets/Prefabs/PerfTestNetworkObject.prefab new file mode 100644 index 0000000000..91de39f222 --- /dev/null +++ b/testproject/Assets/Prefabs/PerfTestNetworkObject.prefab @@ -0,0 +1,49 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5637023994061915634 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5637023994061915632} + - component: {fileID: 5637023994061915633} + m_Layer: 0 + m_Name: PerfTestNetworkObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5637023994061915632 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5637023994061915634} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5637023994061915633 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5637023994061915634} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} + m_Name: + m_EditorClassIdentifier: + GlobalObjectIdHash: 951099334 + AlwaysReplicateAsRoot: 0 + DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 diff --git a/testproject/Assets/Prefabs/PerfTestNetworkObject.prefab.meta b/testproject/Assets/Prefabs/PerfTestNetworkObject.prefab.meta new file mode 100644 index 0000000000..feebc7c48c --- /dev/null +++ b/testproject/Assets/Prefabs/PerfTestNetworkObject.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b0952a471c5a147cb92f6afcdb648f8a +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Prefabs/PerfTestVisualNetworkObject.prefab b/testproject/Assets/Prefabs/PerfTestVisualNetworkObject.prefab new file mode 100644 index 0000000000..6673fbefcd --- /dev/null +++ b/testproject/Assets/Prefabs/PerfTestVisualNetworkObject.prefab @@ -0,0 +1,100 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &9115731988109684252 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9115731988109684241} + - component: {fileID: 9115731988109684240} + - component: {fileID: 9115731988109684243} + - component: {fileID: 9115731988109684253} + m_Layer: 0 + m_Name: PerfTestVisualNetworkObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9115731988109684241 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9115731988109684252} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &9115731988109684240 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9115731988109684252} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9115731988109684243 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9115731988109684252} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!114 &9115731988109684253 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9115731988109684252} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} + m_Name: + m_EditorClassIdentifier: + GlobalObjectIdHash: 951099334 + AlwaysReplicateAsRoot: 0 + DontDestroyWithOwner: 0 diff --git a/testproject/Assets/Prefabs/PerfTestVisualNetworkObject.prefab.meta b/testproject/Assets/Prefabs/PerfTestVisualNetworkObject.prefab.meta new file mode 100644 index 0000000000..f268093417 --- /dev/null +++ b/testproject/Assets/Prefabs/PerfTestVisualNetworkObject.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c2851feb7276442cc86a6f2d1d69ea11 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Scenes/MultiprocessTestingScene.unity b/testproject/Assets/Scenes/MultiprocessTestingScene.unity new file mode 100644 index 0000000000..65e0b7ee89 --- /dev/null +++ b/testproject/Assets/Scenes/MultiprocessTestingScene.unity @@ -0,0 +1,922 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748172, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 130932425} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &127222500 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 127222502} + - component: {fileID: 127222501} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &127222501 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 127222500} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &127222502 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 127222500} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!850595691 &130932425 +LightingSettings: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + serializedVersion: 3 + m_GIWorkflowMode: 1 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_RealtimeEnvironmentLighting: 1 + m_BounceScale: 1 + m_AlbedoBoost: 1 + m_IndirectOutputScale: 1 + m_UsingShadowmask: 1 + m_BakeBackend: 1 + m_LightmapMaxSize: 1024 + m_BakeResolution: 40 + m_Padding: 2 + m_TextureCompression: 1 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAO: 0 + m_MixedBakeMode: 2 + m_LightmapsBakeMode: 1 + m_FilterMode: 1 + m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_RealtimeResolution: 2 + m_ForceWhiteAlbedo: 0 + m_ForceUpdates: 0 + m_FinalGather: 0 + m_FinalGatherRayCount: 256 + m_FinalGatherFiltering: 1 + m_PVRCulling: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_LightProbeSampleCountMultiplier: 4 + m_PVRBounces: 2 + m_PVRMinBounces: 1 + m_PVREnvironmentMIS: 1 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 +--- !u!1 &160940364 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 160940368} + - component: {fileID: 160940367} + - component: {fileID: 160940366} + - component: {fileID: 160940365} + m_Layer: 0 + m_Name: Boundary bottom left + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &160940365 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160940364} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &160940366 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160940364} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &160940367 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160940364} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &160940368 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160940364} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -10, y: -10, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &941021721 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 941021724} + - component: {fileID: 941021723} + - component: {fileID: 941021722} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &941021722 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 941021721} + m_Enabled: 1 +--- !u!20 &941021723 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 941021721} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &941021724 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 941021721} + m_LocalRotation: {x: 0.21736304, y: -0, z: -0, w: 0.97609085} + m_LocalPosition: {x: 0, y: 9.15, z: -27.5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 25.108, y: 0, z: 0} +--- !u!1 &996484657 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 996484661} + - component: {fileID: 996484660} + - component: {fileID: 996484659} + - component: {fileID: 996484658} + m_Layer: 0 + m_Name: Boundary center + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &996484658 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 996484657} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &996484659 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 996484657} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &996484660 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 996484657} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &996484661 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 996484657} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1206022453 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1206022457} + - component: {fileID: 1206022456} + - component: {fileID: 1206022455} + - component: {fileID: 1206022454} + m_Layer: 0 + m_Name: Boundary top right + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &1206022454 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206022453} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1206022455 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206022453} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1206022456 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206022453} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1206022457 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206022453} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 10, y: 10, z: 10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1211923374 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1211923376} + - component: {fileID: 1211923375} + - component: {fileID: 1211923377} + - component: {fileID: 1211923378} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1211923375 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1211923374} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3} + m_Name: + m_EditorClassIdentifier: + DontDestroy: 0 + RunInBackground: 1 + LogLevel: 1 + NetworkConfig: + ProtocolVersion: 0 + NetworkTransport: {fileID: 1674777073} + RegisteredScenes: + - MultiprocessTestingScene + - SampleScene + AllowRuntimeSceneChanges: 0 + PlayerPrefab: {fileID: 4700706668509470175, guid: 7eeaaf9e50c0afc4dab93584a54fb0d6, + type: 3} + NetworkPrefabs: + - Override: 0 + Prefab: {fileID: 9115731988109684252, guid: c2851feb7276442cc86a6f2d1d69ea11, + type: 3} + SourcePrefabToOverride: {fileID: 0} + SourceHashToOverride: 0 + OverridingTargetPrefab: {fileID: 0} + ReceiveTickrate: 64 + NetworkTickIntervalSec: 0.05 + MaxReceiveEventsPerTickRate: -1 + EventTickrate: 64 + ClientConnectionBufferTimeout: 10 + ConnectionApproval: 0 + ConnectionData: + EnableTimeResync: 0 + TimeResyncInterval: 30 + EnableNetworkVariable: 1 + EnsureNetworkVariableLengthSafety: 0 + EnableSceneManagement: 1 + ForceSamePrefabs: 1 + RecycleNetworkIds: 1 + NetworkIdRecycleDelay: 120 + RpcHashSize: 0 + LoadSceneTimeOut: 120 + EnableMessageBuffering: 1 + MessageBufferTimeout: 20 + EnableNetworkLogs: 1 +--- !u!4 &1211923376 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1211923374} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1674777072} + - {fileID: 2027640072} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1211923377 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1211923374} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 068bf11ceb1344667af4cc40950f44f4, type: 3} + m_Name: + m_EditorClassIdentifier: + referencedPrefab: {fileID: 5637023994061915634, guid: b0952a471c5a147cb92f6afcdb648f8a, + type: 3} +--- !u!114 &1211923378 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1211923374} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 55d1c75ce242745ac98f7e7aca6d2d19, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1274245423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1274245425} + - component: {fileID: 1274245424} + - component: {fileID: 1274245426} + m_Layer: 0 + m_Name: TestCoordinator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1274245424 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1274245423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} + m_Name: + m_EditorClassIdentifier: + GlobalObjectIdHash: 2217825759 + AlwaysReplicateAsRoot: 0 + DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 +--- !u!4 &1274245425 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1274245423} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 10, y: 10, z: 10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1274245426 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1274245423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ef1240e0784f84eadb77fe822e2e03c7, type: 3} + m_Name: + m_EditorClassIdentifier: + isRegistering: 0 + hasRegistered: 0 +--- !u!1 &1674777071 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1674777072} + - component: {fileID: 1674777073} + m_Layer: 0 + m_Name: UNET + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1674777072 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1674777071} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1211923376} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1674777073 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1674777071} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b84c2d8dfe509a34fb59e2b81f8e1319, type: 3} + m_Name: + m_EditorClassIdentifier: + MessageBufferSize: 50000 + MaxConnections: 100 + MaxSentMessageQueueSize: 50000 + ConnectAddress: 127.0.0.1 + ConnectPort: 7777 + ServerListenPort: 7777 + ServerWebsocketListenPort: 8887 + SupportWebsocket: 0 + Channels: [] + UseMLAPIRelay: 0 + MLAPIRelayAddress: 184.72.104.138 + MLAPIRelayPort: 8888 + MessageSendMode: 0 +--- !u!1 &2027640071 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2027640072} + - component: {fileID: 2027640073} + m_Layer: 0 + m_Name: UTP + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2027640072 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2027640071} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1211923376} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2027640073 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2027640071} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fc5ef7b69296d69458910681f29471e6, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + Address: 127.0.0.1 diff --git a/testproject/Assets/Scenes/MultiprocessTestingScene.unity.meta b/testproject/Assets/Scenes/MultiprocessTestingScene.unity.meta new file mode 100644 index 0000000000..5a9d45d780 --- /dev/null +++ b/testproject/Assets/Scenes/MultiprocessTestingScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 76743cb7b342c49279327834918a9c6e +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs new file mode 100644 index 0000000000..8babc0bf17 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.TestTools; + +namespace MLAPI.MultiprocessRuntimeTests +{ + public class MultiprocessTestsAttribute : CategoryAttribute + { + public const string multiprocessCategoryName = "Multiprocess"; + public MultiprocessTestsAttribute() : base(multiprocessCategoryName){} + } + + [MultiprocessTests] + public abstract class BaseMultiprocessTests + { + + protected virtual bool m_IsPerformanceTest => true; + + private bool ShouldIgnoreTests => m_IsPerformanceTest && Application.isEditor; + + protected abstract int NbWorkers { get; } + + [OneTimeSetUp] + public virtual void SetupTestFixture() + { + if (ShouldIgnoreTests) + { + Assert.Ignore("Ignoring tests that shouldn't run from unity editor. Performance tests should be run from remote test execution on device (this can be ran using the \"run selected tests (your platform)\" button"); + } + + SceneManager.LoadScene(BuildMultiprocessTestPlayer.mainSceneName, LoadSceneMode.Single); + SceneManager.sceneLoaded += OnSceneLoaded; + + for (int i = 0; i < NbWorkers; i++) + { + MultiprocessOrchestration.StartWorkerNode(); // will automatically start built player as clients + } + } + + private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) + { + SceneManager.sceneLoaded -= OnSceneLoaded; + NetworkManager.Singleton.StartHost(); + } + + [UnitySetUp] + public virtual IEnumerator Setup() + { + yield return new WaitUntil(() => NetworkManager.Singleton != null && NetworkManager.Singleton.IsServer); + + var startTime = Time.time; + while (NetworkManager.Singleton.ConnectedClients.Count <= NbWorkers) + { + yield return new WaitForSeconds(0.2f); + + if (Time.time - startTime > TestCoordinator.maxWaitTimeout) + { + throw new Exception($"waiting too long to see clients to connect, got {NetworkManager.Singleton.ConnectedClients.Count - 1} clients, but was expecting {NbWorkers}, failing"); + } + } + TestCoordinator.Instance.KeepAliveClientRpc(); + } + + [TearDown] + public virtual void Teardown() + { + if (!ShouldIgnoreTests) + { + TestCoordinator.Instance.TestRunTeardown(); + } + } + + [OneTimeTearDown] + public virtual void TeardownSuite() + { + if (!ShouldIgnoreTests) + { + TestCoordinator.Instance.CloseRemoteClientRpc(); + NetworkManager.Singleton.StopHost(); + } + } + } +} + diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs.meta new file mode 100644 index 0000000000..6b52bd9e90 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f77e60aa394b9419784b6c46618fb553 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs new file mode 100644 index 0000000000..4c22ca1d21 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using System.Linq; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +namespace MLAPI.MultiprocessRuntimeTests +{ + [TestFixture(1)] + [TestFixture(2)] + public class TestCoordinatorTests : BaseMultiprocessTests + { + private int m_NbWorkers; + protected override int NbWorkers => m_NbWorkers; + + protected override bool m_IsPerformanceTest => false; + + public TestCoordinatorTests(int nbWorkers) + { + m_NbWorkers = nbWorkers; + } + + private static void ExecuteSimpleCoordinatorTest() + { + TestCoordinator.Instance.WriteTestResultsServerRpc(float.PositiveInfinity); + } + + private static void ExecuteWithArgs(byte[] args) + { + TestCoordinator.Instance.WriteTestResultsServerRpc(args[0]); + } + + [UnityTest] + public IEnumerator CheckTestCoordinator() + { + // Sanity check for TestCoordinator + // Call the method + TestCoordinator.Instance.InvokeFromMethodActionRpc(ExecuteSimpleCoordinatorTest); + + var nbResults = 0; + for (int i = 0; i < NbWorkers; i++) // wait and test for the two clients + { + yield return new WaitUntil(TestCoordinator.ResultIsSet()); + + var (clientId, result) = TestCoordinator.ConsumeCurrentResult().Take(1).Single(); + Assert.Greater(result, 0f); + nbResults++; + } + Assert.That(nbResults, Is.EqualTo(NbWorkers)); + } + + [UnityTest] + public IEnumerator CheckTestCoordinatorWithArgs() + { + TestCoordinator.Instance.InvokeFromMethodActionRpc(ExecuteWithArgs, 99); + var nbResults = 0; + + for (int i = 0; i < NbWorkers; i++) // wait and test for the two clients + { + yield return new WaitUntil(TestCoordinator.ResultIsSet()); + + var (clientId, result) = TestCoordinator.ConsumeCurrentResult().Take(1).Single(); + Assert.That(result, Is.EqualTo(99)); + nbResults++; + } + Assert.That(nbResults, Is.EqualTo(NbWorkers)); + } + } +} diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs.meta new file mode 100644 index 0000000000..104be914d0 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f5e62651568514685a0b50d623fa8a96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/com.unity.multiplayer.mlapi.multiprocessruntime.asmdef b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/com.unity.multiplayer.mlapi.multiprocessruntime.asmdef new file mode 100644 index 0000000000..43f80edd04 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/com.unity.multiplayer.mlapi.multiprocessruntime.asmdef @@ -0,0 +1,25 @@ +{ + "name": "Unity.Multiplayer.MLAPI.MultiprocessRuntime", + "rootNamespace": "", + "references": [ + "Unity.Multiplayer.MLAPI.Runtime", + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", + "ScriptsForAutomatedTesting", + "Unity.PerformanceTesting", + "MultiprocessTestsHelpers" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/com.unity.multiplayer.mlapi.multiprocessruntime.asmdef.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/com.unity.multiplayer.mlapi.multiprocessruntime.asmdef.meta new file mode 100644 index 0000000000..a06b37d08b --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/com.unity.multiplayer.mlapi.multiprocessruntime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 66273ab9e01074f7da305fe84e13da47 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From efb083cec872a82a42e5ca51e48c721ea9afced2 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 16:37:21 -0400 Subject: [PATCH 03/40] adding fixed testcoordinator --- .../MultiprocessRuntime/TestCoordinator.cs | 337 ++++++++++++++++++ .../TestCoordinator.cs.meta | 11 + 2 files changed, 348 insertions(+) create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs.meta diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs new file mode 100644 index 0000000000..6602faade7 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -0,0 +1,337 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using MLAPI; +using MLAPI.Configuration; +using MLAPI.Logging; +using MLAPI.Messaging; +using NUnit.Framework; +using NUnit.Framework.Interfaces; +using UnityEngine; +using UnityEngine.TestTools; +using Debug = UnityEngine.Debug; + +/// +/// TestCoordinator +/// Used for coordinating multiprocess end to end tests. Used to call RPCs on other nodes and gather results +/// This is needed to coordinate server and client execution steps. The current remote player test runner hardcodes test +/// to run in a bootstrap scene before launching the player and doesn't call each tests individually. There's not opportunity +/// to coordinate test execution between client and server with that model. +/// The only per tests communication already existing is to get the results per test as they are running +/// With this test coordinator, it's not possible to start a main test node with the test runner and have that server start other worker nodes +/// on which to execute client tests. We use MLAPI as both a test framework and as the target of our performance tests. +/// +[RequireComponent(typeof(NetworkObject))] +public class TestCoordinator : NetworkBehaviour +{ + public const int perTestTimeout = 5 * 60; // seconds + + public const float maxWaitTimeout = 20; + private const char k_MethodFullNameSplitChar = '@'; + + + private bool m_ShouldShutdown; + private float m_TimeSinceLastConnected; + private float m_TimeSinceLastKeepAlive; + + public static TestCoordinator Instance; + + private Dictionary> m_TestResultsLocal = new Dictionary>(); // this isn't super efficient, but since it's used for signaling around the tests, shouldn't be too bad + private Dictionary m_ClientIsFinished = new Dictionary(); + + public static Dictionary>.KeyCollection AllClientIdsWithResults => Instance.m_TestResultsLocal.Keys; + public static List AllClientIdExceptMine => NetworkManager.Singleton.ConnectedClients.Keys.ToList().FindAll(client => client != NetworkManager.Singleton.LocalClientId); + + private void Awake() + { + if (Instance != null) + { + Debug.LogError("Multiple test coordinator! destroying self"); + Destroy(gameObject); + return; + } + + Instance = this; + } + + public void Start() + { + bool isClient = Environment.GetCommandLineArgs().Any(value => value == MultiprocessOrchestration.isWorkerArg); + if (isClient) + { + Debug.Log("starting MLAPI client"); + NetworkManager.Singleton.StartClient(); + } + + NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback; + + ExecuteStepInContext.InitializeAllSteps(); + } + + public void Update() + { + if (Time.time - m_TimeSinceLastKeepAlive > perTestTimeout) + { + QuitApplication(); + Assert.Fail("Stayed idle too long"); + } + if ((IsServer && NetworkManager.Singleton.IsListening) || (IsClient && NetworkManager.Singleton.IsConnectedClient)) + { + m_TimeSinceLastConnected = Time.time; + } + else if (Time.time - m_TimeSinceLastConnected > maxWaitTimeout || m_ShouldShutdown) + { + // Make sure we don't have zombie processes + Debug.Log($"quitting application, shouldShutdown set to {m_ShouldShutdown}, is listening {NetworkManager.Singleton.IsListening}, is connected client {NetworkManager.Singleton.IsConnectedClient}"); + if (!m_ShouldShutdown) + { + QuitApplication(); + Assert.Fail($"something wrong happened, was not connected for {Time.time - m_TimeSinceLastConnected} seconds"); + } + } + } + + private static void QuitApplication() + { +#if UNITY_EDITOR + UnityEditor.EditorApplication.isPlaying = false; +#else + Application.Quit(); +#endif + } + + public void TestRunTeardown() + { + m_TestResultsLocal.Clear(); + } + + public void OnDestroy() + { + if (NetworkObject != null && NetworkManager != null) + { + NetworkManager.OnClientDisconnectCallback -= OnClientDisconnectCallback; + } + } + + private static void OnClientDisconnectCallback(ulong clientId) + { + if (clientId == NetworkManager.Singleton.ServerClientId || clientId == NetworkManager.Singleton.LocalClientId) + { + // if disconnect callback is for me or for server, quit, we're done here + Debug.Log($"received disconnect from {clientId}, quitting"); + QuitApplication(); + } + } + + private static string GetMethodInfo(Action method) + { + return $"{method.Method.DeclaringType.FullName}{k_MethodFullNameSplitChar}{method.Method.Name}"; + } + + private static string GetMethodInfo(Action method) + { + return $"{method.Method.DeclaringType.FullName}{k_MethodFullNameSplitChar}{method.Method.Name}"; + } + + public static IEnumerable<(ulong clientId, float result)> ConsumeCurrentResult() + { + foreach (var kv in Instance.m_TestResultsLocal) + { + while (kv.Value.Count > 0) + { + var toReturn = (kv.Key, kv.Value[0]); + kv.Value.RemoveAt(0); + yield return toReturn; + } + } + } + + public static IEnumerable ConsumeCurrentResult(ulong clientID) + { + var allResults = Instance.m_TestResultsLocal[clientID]; + while (allResults.Count > 0) + { + var toReturn = allResults[0]; + allResults.RemoveAt(0); + yield return toReturn; + } + } + + public static float PeekLatestResult(ulong clientId) + { + if (Instance.m_TestResultsLocal.ContainsKey(clientId) && Instance.m_TestResultsLocal[clientId].Count > 0) + { + return Instance.m_TestResultsLocal[clientId].Last(); + } + + return float.NaN; + } + + /// + /// Returns appropriate lambda according to parameters + /// Includes time check to make sure this times out + /// + /// + /// + /// + public static Func ResultIsSet(bool useTimeoutException = true) + { + var startWaitTime = Time.time; + return () => + { + if (Time.time - startWaitTime > maxWaitTimeout) + { + if (useTimeoutException) + { + throw new Exception($"timeout while waiting for results, didn't get results for {Time.time - startWaitTime} seconds"); + } + + return true; + } + + foreach (var clientIdAndTestResultList in Instance.m_TestResultsLocal) + { + if (clientIdAndTestResultList.Value.Count > 0) + { + return true; + } + } + + return false; + }; + } + + public static Func ConsumeClientIsFinished(ulong clientId, bool useTimeoutException = true) + { + var startWaitTime = Time.time; + return () => + { + if (Time.time - startWaitTime > maxWaitTimeout) + { + if (useTimeoutException) + { + throw new Exception($"timeout while waiting for client finished, didn't get results for {Time.time - startWaitTime} seconds"); + } + else + { + return true; + } + } + + if (Instance.m_ClientIsFinished.ContainsKey(clientId) && Instance.m_ClientIsFinished[clientId]) + { + Instance.m_ClientIsFinished[clientId] = false; // consume + return true; + } + + return false; + }; + } + + [ServerRpc(RequireOwnership = false)] + public void ClientFinishedServerRpc(ServerRpcParams p = default) + { + // signal from clients to the server to say the client is done with it's task + m_ClientIsFinished[p.Receive.SenderClientId] = true; + } + + public void InvokeFromMethodActionRpc(Action methodInfo, params byte[] args) + { + var methodInfoString = GetMethodInfo(methodInfo); + InvokeFromMethodNameClientRpc(methodInfoString, args, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = AllClientIdExceptMine.ToArray() } }); + } + + public void InvokeFromMethodActionRpc(Action methodInfo) + { + var methodInfoString = GetMethodInfo(methodInfo); + InvokeFromMethodNameClientRpc(methodInfoString, null, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = AllClientIdExceptMine.ToArray() } }); + } + + [ClientRpc] + public void TriggerActionIDClientRpc(string actionID, byte[] args, ClientRpcParams clientRpcParams = default) + { + Debug.Log($"received RPC from server, client side triggering action ID {actionID}"); + try + { + ExecuteStepInContext.allActions[actionID].Invoke(args); + } + catch (Exception e) + { + WriteErrorServerRpc(e.Message); + throw; + } + } + + [ClientRpc] + public void InvokeFromMethodNameClientRpc(string methodInfoString, byte[] args, ClientRpcParams clientRpcParams = default) + { + try + { + var split = methodInfoString.Split(k_MethodFullNameSplitChar); + var (classToExecute, staticMethodToExecute) = (split[0], split[1]); + + var foundType = Type.GetType(classToExecute); + if (foundType == null) + { + throw new Exception($"couldn't find {classToExecute}"); + } + + var foundMethod = foundType.GetMethod(staticMethodToExecute, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + if (foundMethod == null) + { + throw new Exception($"couldn't find method {staticMethodToExecute}"); + } + + foundMethod.Invoke(null, args != null ? new object[] { args } : null); + } + catch (Exception e) + { + WriteErrorServerRpc(e.Message); + throw; + } + } + + [ClientRpc] + public void CloseRemoteClientRpc() + { + try + { + NetworkManager.Singleton.StopClient(); + m_ShouldShutdown = true; // wait until isConnectedClient is false to run Application Quit in next update + Debug.Log("Quitting player cleanly"); + Application.Quit(); + } + catch (Exception e) + { + WriteErrorServerRpc(e.Message); + throw; + } + } + + [ClientRpc] + public void KeepAliveClientRpc() + { + m_TimeSinceLastKeepAlive = Time.time; + } + + [ServerRpc(RequireOwnership = false)] + public void WriteTestResultsServerRpc(float result, ServerRpcParams receiveParams = default) + { + var senderId = receiveParams.Receive.SenderClientId; + if (!m_TestResultsLocal.ContainsKey(senderId)) + { + m_TestResultsLocal[senderId] = new List(); + } + + m_TestResultsLocal[senderId].Add(result); + } + + [ServerRpc(RequireOwnership = false)] + public void WriteErrorServerRpc(string errorMessage, ServerRpcParams receiveParams = default) + { + Debug.LogError($"Got Exception client side {errorMessage}, from client {receiveParams.Receive.SenderClientId}"); + } +} diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs.meta new file mode 100644 index 0000000000..f8c2a3c472 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef1240e0784f84eadb77fe822e2e03c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 4ea4d4ca720bb0b733872f4eefd5db950a73561f Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 16:42:25 -0400 Subject: [PATCH 04/40] adding missing change --- testproject/ProjectSettings/EditorBuildSettings.asset | 3 +++ 1 file changed, 3 insertions(+) diff --git a/testproject/ProjectSettings/EditorBuildSettings.asset b/testproject/ProjectSettings/EditorBuildSettings.asset index 0f1a066d92..da26d6d0c7 100644 --- a/testproject/ProjectSettings/EditorBuildSettings.asset +++ b/testproject/ProjectSettings/EditorBuildSettings.asset @@ -41,4 +41,7 @@ EditorBuildSettings: - enabled: 1 path: Assets/Tests/Manual/NetworkSceneManagerCallbacks/SceneWeAreSwitchingFrom.unity guid: 073bd2111475c0643be45b7abe6a97ad + - enabled: 1 + path: Assets/Scenes/MultiprocessTestingScene.unity + guid: 76743cb7b342c49279327834918a9c6e m_configObjects: {} From ea7cdcf98c2ed4bebe4fdb13dec02f091e32676a Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 16:49:07 -0400 Subject: [PATCH 05/40] moving execute step in context to this branch from test/multiprocess-testing/wip --- .../ExecuteStepInContext.cs | 290 ++++++++++++++++++ .../ExecuteStepInContext.cs.meta | 11 + .../ExecuteStepInContextTests.cs | 226 ++++++++++++++ .../ExecuteStepInContextTests.cs.meta | 11 + .../Helpers/CallbackComponent.cs | 24 ++ .../Helpers/CallbackComponent.cs.meta | 11 + 6 files changed, 573 insertions(+) create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs.meta create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs.meta create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/CallbackComponent.cs create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/CallbackComponent.cs.meta diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs new file mode 100644 index 0000000000..a13417ab40 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs @@ -0,0 +1,290 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using MLAPI; +using MLAPI.Messaging; +using NUnit.Framework; +using NUnit.Framework.Interfaces; +using UnityEngine; +using UnityEngine.TestTools; +using Debug = UnityEngine.Debug; + +/// +/// Allows for context based delegate execution. +/// Can specify where you want that lambda executed (client side? server side?) and it'll automatically wait for the end +/// of a clientRPC server side and vice versa. +/// todo this could be used as an in-game tool too? for protocols that require a lot of back and forth? +/// +public class ExecuteStepInContext : CustomYieldInstruction +{ + public enum StepExecutionContext + { + Server, + Clients + } + + [AttributeUsage(AttributeTargets.Method)] + public class MultiprocessContextBasedTestAttribute : NUnitAttribute, IOuterUnityTestAction + { + public IEnumerator BeforeTest(ITest test) + { + yield return new WaitUntil(() => TestCoordinator.Instance != null && hasRegistered); + } + + public IEnumerator AfterTest(ITest test) + { + yield break; + } + } + + private StepExecutionContext m_ActionContext; + private Action m_StepToExecute; + private string m_CurrentActionID; + + // as a remote worker, I store all available actions so I can execute them when triggered from RPCs + public static Dictionary allActions = new Dictionary(); + private static Dictionary s_MethodIDCounter = new Dictionary(); + + private NetworkManager m_NetworkManager; + private bool m_IsRegistering; + private List> m_RemoteIsFinishedChecks = new List>(); + private Func m_AdditionalIsFinishedWaiter; + + private bool m_WaitMultipleUpdates; + private bool m_IgnoreTimeoutException; + + private float m_StartTime; + private bool isTimingOut => Time.time - m_StartTime > TestCoordinator.maxWaitTimeout; + private bool ShouldExecuteLocally => (m_ActionContext == StepExecutionContext.Server && m_NetworkManager.IsServer) || (m_ActionContext == StepExecutionContext.Clients && !m_NetworkManager.IsServer); + + public static bool isRegistering; + public static bool hasRegistered; + private static List m_AllClientTestInstances = new List(); // to keep an instance for each tests, so captured context in each step is kept + + /// + /// This MUST be called at the beginning of each test in order to use context based steps. + /// Assumes this is called from same callsite as ExecuteInContext (and assumes this is called from IEnumerator). + /// This relies on the name to be unique for each generated IEnumerator state machines + /// + public static void InitContextSteps() + { + var callerMethod = new StackFrame(1).GetMethod(); + var methodIdentifier = GetMethodIdentifier(callerMethod.DeclaringType.FullName); // since this is called from IEnumerator, this should be a generated class + s_MethodIDCounter[methodIdentifier] = 0; + } + + private static string GetMethodIdentifier(string callerTypeName) + { + var info = callerTypeName; + return info; + } + + internal static void InitializeAllSteps() + { + // registering magically all context based steps + isRegistering = true; + var registeredMethods = typeof(TestCoordinator).Assembly.GetTypes().SelectMany(t => t.GetMethods()) + .Where(m => m.GetCustomAttributes(typeof(ExecuteStepInContext.MultiprocessContextBasedTestAttribute), true).Length > 0) + .ToArray(); + HashSet typesWithContextMethods = new HashSet(); + foreach (var method in registeredMethods) + { + typesWithContextMethods.Add(method.ReflectedType); + } + + if (registeredMethods.Length == 0) + { + throw new Exception("Couldn't find any registered methods for multiprocess testing. Is TestCoordinator in same assembly as test methods?"); + } + + object[] GetParameterValuesToPass(ParameterInfo[] parameterInfo) + { + object[] parametersToReturn = new object[parameterInfo.Length]; + for (int i = 0; i < parameterInfo.Length; i++) + { + var paramType = parameterInfo[i].GetType(); + object defaultObj = null; + if (paramType.IsValueType) + { + defaultObj = Activator.CreateInstance(paramType); + } + + parametersToReturn[i] = defaultObj; + } + + return parametersToReturn; + } + + foreach (var contextType in typesWithContextMethods) + { + var allConstructors = contextType.GetConstructors(); + if (allConstructors.Length > 1) + { + throw new NotImplementedException("Case not implemented where test has more than one contructor"); + } + + var instance = Activator.CreateInstance(contextType, allConstructors.Length > 0 ? GetParameterValuesToPass(allConstructors[0].GetParameters()) : null); + m_AllClientTestInstances.Add(instance); // keeping that instance so tests can use captured local attributes + + List typeMethodsWithContextSteps = new List(); + foreach (var method in contextType.GetMethods()) + { + if (method.GetCustomAttributes(typeof(ExecuteStepInContext.MultiprocessContextBasedTestAttribute), true).Length > 0) + { + typeMethodsWithContextSteps.Add(method); + } + } + + foreach (var method in typeMethodsWithContextSteps) + { + var parametersToPass = GetParameterValuesToPass(method.GetParameters()); + var enumerator = (IEnumerator)method.Invoke(instance, parametersToPass.ToArray()); + while (enumerator.MoveNext()) { } + } + } + + isRegistering = false; + hasRegistered = true; + } + + /// + /// Executes an action with the specified context. This allows writing tests all in the same sequential flow, + /// making it more readable. This allows not having to jump between static client methods and test method + /// + /// context to use. for example, should execute client side? server side? + /// action to execute + /// waits for timeout and just finishes step execution silently + /// parameters to pass to action + /// + /// waits multiple frames before allowing the execution to continue. This means ClientFinishedServerRpc must be called manually + /// + public ExecuteStepInContext(StepExecutionContext actionContext, Action stepToExecute, bool ignoreTimeoutException = false, byte[] paramToPass = default, NetworkManager networkManager = null, bool waitMultipleUpdates = false, Func additionalIsFinishedWaiter = null) + { + m_StartTime = Time.time; + m_IsRegistering = isRegistering; + m_ActionContext = actionContext; + m_StepToExecute = stepToExecute; + m_WaitMultipleUpdates = waitMultipleUpdates; + m_IgnoreTimeoutException = ignoreTimeoutException; + if (additionalIsFinishedWaiter != null) + { + m_AdditionalIsFinishedWaiter = additionalIsFinishedWaiter; + + // m_IsFinishedChecks.Add(additionalIsFinishedWaiter); + } + + if (networkManager == null) + { + networkManager = NetworkManager.Singleton; + } + + m_NetworkManager = networkManager; // todo test using this for multiinstance tests too? + + var callerMethod = new StackFrame(1).GetMethod(); // one skip frame for current method + + var methodId = GetMethodIdentifier(callerMethod.DeclaringType.FullName); // assumes called from IEnumerator MoveNext, which should be the case since we're a CustomYieldInstruction + if (!s_MethodIDCounter.ContainsKey(methodId)) + { + s_MethodIDCounter[methodId] = 0; + } + + string currentActionID = $"{methodId}-{s_MethodIDCounter[methodId]++}"; + m_CurrentActionID = currentActionID; + + if (m_IsRegistering) + { + Assert.That(allActions, Does.Not.Contain(currentActionID)); // sanity check + allActions[currentActionID] = this; + } + else + { + if (ShouldExecuteLocally) + { + m_StepToExecute.Invoke(paramToPass); + } + else + { + if (networkManager.IsServer) + { + TestCoordinator.Instance.TriggerActionIDClientRpc(currentActionID, paramToPass, + clientRpcParams: new ClientRpcParams + { + Send = new ClientRpcSendParams { TargetClientIds = TestCoordinator.AllClientIdExceptMine.ToArray() } + }); + foreach (var clientId in TestCoordinator.AllClientIdExceptMine) + { + m_RemoteIsFinishedChecks.Add(TestCoordinator.ConsumeClientIsFinished(clientId)); + } + } + else + { + throw new NotImplementedException(); + } + } + } + } + + public void Invoke(byte[] args) + { + m_StepToExecute.Invoke(args); + if (!m_WaitMultipleUpdates) + { + if (!m_NetworkManager.IsServer) + { + TestCoordinator.Instance.ClientFinishedServerRpc(); + } + else + { + throw new NotImplementedException("todo implement"); + } + } + } + + public override bool keepWaiting + { + get + { + if (isTimingOut) + { + if (m_IgnoreTimeoutException) + { + Debug.LogWarning($"Timeout ignored for action ID {m_CurrentActionID}"); + return false; + } + + throw new Exception($"timeout for Context Step with action ID {m_CurrentActionID}"); + } + + if (m_AdditionalIsFinishedWaiter != null) + { + var isFinished = m_AdditionalIsFinishedWaiter.Invoke(); + if (!isFinished) + { + return true; + } + } + + if (m_IsRegistering || ShouldExecuteLocally || m_RemoteIsFinishedChecks == null) + { + return false; + } + + for (int i = m_RemoteIsFinishedChecks.Count - 1; i >= 0; i--) + { + if (m_RemoteIsFinishedChecks[i].Invoke()) + { + m_RemoteIsFinishedChecks.RemoveAt(i); + } + else + { + return true; + } + } + + return false; + } + } +} diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs.meta new file mode 100644 index 0000000000..2b5f013d83 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ff1efc1d00c64914905497db918aadc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs new file mode 100644 index 0000000000..9ddaf1d0e5 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections; +using System.Text.RegularExpressions; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; +using static ExecuteStepInContext; + +namespace MLAPI.MultiprocessRuntimeTests +{ + /// + /// Smoke tests for ExecuteStepInContext, to make sure it's working properly before being used in other tests + /// + [TestFixture(1)] + [TestFixture(2)] + public class ExecuteStepInContextTests : BaseMultiprocessTests + { + private int m_NbWorkersToTest; + public ExecuteStepInContextTests(int nbWorkersToTest) + { + m_NbWorkersToTest = nbWorkersToTest; + } + protected override int NbWorkers => m_NbWorkersToTest; + protected override bool m_IsPerformanceTest => false; + + [UnityTest, MultiprocessContextBasedTest] + public IEnumerator TestWithParameters([Values(1, 2, 3)] int a) + { + InitContextSteps(); + + yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => + { + Assert.Less(a, 4); + Assert.Greater(a, 0); + }); + yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => + { + var clientA = BitConverter.ToInt32(bytes, 0); + Assert.True(!NetworkManager.Singleton.IsServer); + Assert.Less(clientA, 4); + Assert.Greater(clientA, 0); + }, paramToPass: BitConverter.GetBytes(a)); + } + + [UnityTest, MultiprocessContextBasedTest] + [TestCase(1, 2, ExpectedResult = null)] + [TestCase(2, 3, ExpectedResult = null)] + [TestCase(3, 4, ExpectedResult = null)] + public IEnumerator TestWithParameters(int a, int b) + { + InitContextSteps(); + + yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => + { + Assert.Less(a, 4); + Assert.Greater(a, 0); + Assert.Less(b, 5); + Assert.Greater(b, 1); + }); + yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => + { + var clientB = BitConverter.ToInt32(bytes, 0); + Assert.True(!NetworkManager.Singleton.IsServer); + Assert.Less(clientB, 5); + Assert.Greater(clientB, 1); + }, paramToPass: BitConverter.GetBytes(b)); + } + + [UnityTest, MultiprocessContextBasedTest] + public IEnumerator TestExceptionClientSide() + { + InitContextSteps(); + + const string exceptionMessageToTest = "This is an exception for TestCoordinator that's expected"; + yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => + { + throw new Exception(exceptionMessageToTest); + }, ignoreTimeoutException: true); + yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => + { + for (int i = 0; i < m_NbWorkersToTest; i++) + { + LogAssert.Expect(LogType.Error, new Regex($".*{exceptionMessageToTest}.*")); + } + }); + + const string exceptionUpdateMessageToTest = "This is an exception for update loop client side that's expected"; + yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => + { + void Update(float __) + { + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= Update; + throw new Exception(exceptionUpdateMessageToTest); + } + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += Update; + + }, ignoreTimeoutException: true); + yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => + { + for (int i = 0; i < m_NbWorkersToTest; i++) + { + LogAssert.Expect(LogType.Error, new Regex($".*{exceptionUpdateMessageToTest}.*")); + } + }); + } + + [UnityTest, MultiprocessContextBasedTest] + public IEnumerator ContextTestWithAdditionalWait() + { + InitContextSteps(); + + const int maxValue = 10; + yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => + { + int count = 0; + + void Update(float __) + { + TestCoordinator.Instance.WriteTestResultsServerRpc(count++); + if (count > maxValue) + { + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= Update; + } + } + + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += Update; + }, additionalIsFinishedWaiter: () => + { + int nbFinished = 0; + for (int i = 0; i < m_NbWorkersToTest; i++) + { + if (TestCoordinator.PeekLatestResult(TestCoordinator.AllClientIdExceptMine[i]) == maxValue) + { + nbFinished++; + } + } + return nbFinished == m_NbWorkersToTest; + }); + yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => + { + Assert.That(TestCoordinator.AllClientIdExceptMine.Count, Is.EqualTo(m_NbWorkersToTest)); + foreach (var clientID in TestCoordinator.AllClientIdExceptMine) + { + var current = 0; + foreach (var res in TestCoordinator.ConsumeCurrentResult(clientID)) + { + Assert.That(res, Is.EqualTo(current++)); + } + Assert.That(current - 1, Is.EqualTo(maxValue)); + } + }); + } + + [UnityTest, MultiprocessContextBasedTest] + public IEnumerator TestExecuteInContext() + { + InitContextSteps(); + + int stepCountExecuted = 0; + yield return new ExecuteStepInContext(StepExecutionContext.Server, args => + { + stepCountExecuted++; + int count = BitConverter.ToInt32(args, 0); + Assert.That(count, Is.EqualTo(1)); + }, paramToPass: BitConverter.GetBytes(1)); + + yield return new ExecuteStepInContext(StepExecutionContext.Clients, args => + { + int count = BitConverter.ToInt32(args, 0); + Assert.That(count, Is.EqualTo(2)); + TestCoordinator.Instance.WriteTestResultsServerRpc(12345); +#if UNITY_EDITOR + Assert.Fail("Should not be here!! This should only execute on client!!"); +#endif + }, paramToPass: BitConverter.GetBytes(2)); + + yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => + { + stepCountExecuted++; + int resultCountFromWorkers = 0; + foreach (var res in TestCoordinator.ConsumeCurrentResult()) + { + resultCountFromWorkers++; + Assert.AreEqual(12345, res.result); + } + + Assert.That(resultCountFromWorkers, Is.EqualTo(NbWorkers)); + }); + + const int timeToWait = 4; + yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => + { + void Update(float __) + { + if (Time.time > timeToWait) + { + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= Update; + TestCoordinator.Instance.WriteTestResultsServerRpc(Time.time); + + TestCoordinator.Instance.ClientFinishedServerRpc(); // since finishOnInvoke is false, we need to do this manually + } + } + + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += Update; + }, waitMultipleUpdates: true); // waits multiple frames before allowing the next action to continue. + + yield return new ExecuteStepInContext(StepExecutionContext.Server, args => + { + stepCountExecuted++; + int count = 0; + foreach (var res in TestCoordinator.ConsumeCurrentResult()) + { + count++; + Assert.GreaterOrEqual(res.result, timeToWait); + } + + Assert.Greater(count, 0); + }); + + if (!isRegistering) + { + Assert.AreEqual(3, stepCountExecuted); + } + } + } +} diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs.meta new file mode 100644 index 0000000000..3f89ca9cb5 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80b877babc0ce4b0d8cf31e73216d49a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/CallbackComponent.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/CallbackComponent.cs new file mode 100644 index 0000000000..80ecc0dcbd --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/CallbackComponent.cs @@ -0,0 +1,24 @@ +using System; +using UnityEngine; + +/// +/// Component who's purpose is to expose callbacks to code tests +/// +public class CallbackComponent : MonoBehaviour +{ + public Action OnUpdate; + + // Update is called once per frame + private void Update() + { + try + { + OnUpdate?.Invoke(Time.deltaTime); + } + catch (Exception e) + { + TestCoordinator.Instance.WriteErrorServerRpc(e.Message); + throw; + } + } +} diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/CallbackComponent.cs.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/CallbackComponent.cs.meta new file mode 100644 index 0000000000..7347e89e7b --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/CallbackComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 55d1c75ce242745ac98f7e7aca6d2d19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 5803269e30a3fb26307d851ea7d574a1b261de26 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 17:35:28 -0400 Subject: [PATCH 06/40] taking changes from wip branch --- .../Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs index 8babc0bf17..d49d2f857d 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs @@ -24,7 +24,7 @@ public abstract class BaseMultiprocessTests protected abstract int NbWorkers { get; } [OneTimeSetUp] - public virtual void SetupTestFixture() + public virtual void SetupTestSuite() { if (ShouldIgnoreTests) { From c804d641f1e8c54a986386e1c0d429597f876b68 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 18:07:28 -0400 Subject: [PATCH 07/40] commenting out ExecuteStepInContext for better PR clarity --- .../Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index 6602faade7..92078a3c98 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -68,7 +68,7 @@ public void Start() NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback; - ExecuteStepInContext.InitializeAllSteps(); + // ExecuteStepInContext.InitializeAllSteps(); } public void Update() @@ -256,7 +256,7 @@ public void TriggerActionIDClientRpc(string actionID, byte[] args, ClientRpcPara Debug.Log($"received RPC from server, client side triggering action ID {actionID}"); try { - ExecuteStepInContext.allActions[actionID].Invoke(args); + // ExecuteStepInContext.allActions[actionID].Invoke(args); } catch (Exception e) { From 5a1d2ef5f7332af398e7a64538fbd1a99b7db9bf Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 18:08:30 -0400 Subject: [PATCH 08/40] uncommenting here, this is where they should really be --- .../Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index 92078a3c98..6602faade7 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -68,7 +68,7 @@ public void Start() NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback; - // ExecuteStepInContext.InitializeAllSteps(); + ExecuteStepInContext.InitializeAllSteps(); } public void Update() @@ -256,7 +256,7 @@ public void TriggerActionIDClientRpc(string actionID, byte[] args, ClientRpcPara Debug.Log($"received RPC from server, client side triggering action ID {actionID}"); try { - // ExecuteStepInContext.allActions[actionID].Invoke(args); + ExecuteStepInContext.allActions[actionID].Invoke(args); } catch (Exception e) { From 23e435aa5d15d8b5919edd161b76fa11ed646fca Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 19:36:49 -0400 Subject: [PATCH 09/40] cleanup --- .../MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index b7917a266b..1b7d2b24e1 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -80,12 +80,11 @@ public static void DeleteBuild() /// public static bool Build(bool isDebug = false) { - // Save standalone build path to file + // Save standalone build path to file so we can read it from standalone tests (that are not running from editor) var f = File.CreateText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.buildInfoFileName)); f.Write(buildPath); f.Close(); - // var buildPath = Application.streamingAssetsPath; // deleting so we don't end up testing on outdated builds if there's a build failure DeleteBuild(); From c38a957ecba73423c0a8088105164424f7375dd6 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 19:41:09 -0400 Subject: [PATCH 10/40] better name --- .../MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 1b7d2b24e1..3e9d4d82d5 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -20,7 +20,7 @@ public class BuildMultiprocessTestPlayer : MonoBehaviour #if UNITY_EDITOR [MenuItem(multiprocessBaseMenuName+"/Build Test Player #t")] - public static void BuildNoExecute() + public static void BuildNoDebug() { var success = Build(); if (!success) From 60b7d43ac7a4aa2dfbd10b3b584af7483cdc8c44 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Sun, 27 Jun 2021 19:55:22 -0400 Subject: [PATCH 11/40] removing comment and putting better name --- .../MultiprocessRuntime/ExecuteStepInContext.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs index a13417ab40..6df0b129ce 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs @@ -50,7 +50,7 @@ public IEnumerator AfterTest(ITest test) private NetworkManager m_NetworkManager; private bool m_IsRegistering; - private List> m_RemoteIsFinishedChecks = new List>(); + private List> m_ClientIsFinishedChecks = new List>(); private Func m_AdditionalIsFinishedWaiter; private bool m_WaitMultipleUpdates; @@ -169,11 +169,10 @@ public ExecuteStepInContext(StepExecutionContext actionContext, Action s m_StepToExecute = stepToExecute; m_WaitMultipleUpdates = waitMultipleUpdates; m_IgnoreTimeoutException = ignoreTimeoutException; + if (additionalIsFinishedWaiter != null) { m_AdditionalIsFinishedWaiter = additionalIsFinishedWaiter; - - // m_IsFinishedChecks.Add(additionalIsFinishedWaiter); } if (networkManager == null) @@ -216,7 +215,7 @@ public ExecuteStepInContext(StepExecutionContext actionContext, Action s }); foreach (var clientId in TestCoordinator.AllClientIdExceptMine) { - m_RemoteIsFinishedChecks.Add(TestCoordinator.ConsumeClientIsFinished(clientId)); + m_ClientIsFinishedChecks.Add(TestCoordinator.ConsumeClientIsFinished(clientId)); } } else @@ -267,16 +266,16 @@ public override bool keepWaiting } } - if (m_IsRegistering || ShouldExecuteLocally || m_RemoteIsFinishedChecks == null) + if (m_IsRegistering || ShouldExecuteLocally || m_ClientIsFinishedChecks == null) { return false; } - for (int i = m_RemoteIsFinishedChecks.Count - 1; i >= 0; i--) + for (int i = m_ClientIsFinishedChecks.Count - 1; i >= 0; i--) { - if (m_RemoteIsFinishedChecks[i].Invoke()) + if (m_ClientIsFinishedChecks[i].Invoke()) { - m_RemoteIsFinishedChecks.RemoveAt(i); + m_ClientIsFinishedChecks.RemoveAt(i); } else { From b1656ae5e159e447633a3ae1289d5c2ac5913a88 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Mon, 5 Jul 2021 18:30:54 -0400 Subject: [PATCH 12/40] consistent naming --- .../Helpers/BuildMultiprocessTestPlayer.cs | 27 +++++++++---------- .../Helpers/MultiprocessOrchestration.cs | 8 +++--- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 3e9d4d82d5..94bc5a7dcf 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -12,14 +12,13 @@ /// public class BuildMultiprocessTestPlayer : MonoBehaviour { - public const string multiprocessBaseMenuName = "MLAPI Multiprocess Test"; - public const string BuildAndExecuteMenuName = multiprocessBaseMenuName + "/Build - Execute multiprocess tests #%t"; - public static string buildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTestBuild"); - public const string mainSceneName = "MultiprocessTestingScene"; - + public const string BuildAndExecuteMenuName = k_MultiprocessBaseMenuName + "/Build - Execute multiprocess tests #%t"; + private const string k_MultiprocessBaseMenuName = "MLAPI Multiprocess Test"; + private const string k_MainSceneName = "MultiprocessTestingScene"; + private static string s_BuildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTestBuild"); #if UNITY_EDITOR - [MenuItem(multiprocessBaseMenuName+"/Build Test Player #t")] + [MenuItem(k_MultiprocessBaseMenuName+"/Build Test Player #t")] public static void BuildNoDebug() { var success = Build(); @@ -29,7 +28,7 @@ public static void BuildNoDebug() } } - [MenuItem(multiprocessBaseMenuName+"/Build Test Player in debug mode")] + [MenuItem(k_MultiprocessBaseMenuName+"/Build Test Player in debug mode")] public static void BuildDebug() { var success = Build(true); @@ -39,14 +38,14 @@ public static void BuildDebug() } } - [MenuItem(multiprocessBaseMenuName+"/Delete Test Build")] + [MenuItem(k_MultiprocessBaseMenuName+"/Delete Test Build")] public static void DeleteBuild() { switch (Application.platform) { case RuntimePlatform.WindowsPlayer: case RuntimePlatform.WindowsEditor: - var exePath = $"{buildPath}.exe"; + var exePath = $"{s_BuildPath}.exe"; if (File.Exists(exePath)) { File.Delete(exePath); @@ -58,7 +57,7 @@ public static void DeleteBuild() break; case RuntimePlatform.OSXPlayer: case RuntimePlatform.OSXEditor: - var toDelete = buildPath + ".app"; + var toDelete = s_BuildPath + ".app"; if (Directory.Exists(toDelete)) { Directory.Delete(toDelete, recursive: true); @@ -81,8 +80,8 @@ public static void DeleteBuild() public static bool Build(bool isDebug = false) { // Save standalone build path to file so we can read it from standalone tests (that are not running from editor) - var f = File.CreateText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.buildInfoFileName)); - f.Write(buildPath); + var f = File.CreateText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.BuildInfoFileName)); + f.Write(s_BuildPath); f.Close(); // deleting so we don't end up testing on outdated builds if there's a build failure @@ -98,7 +97,7 @@ public static bool Build(bool isDebug = false) // will have more connection permission popups when launching though } - var buildPathToUse = buildPath; + var buildPathToUse = s_BuildPath; if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor) { buildPathToUse += ".exe"; @@ -106,7 +105,7 @@ public static bool Build(bool isDebug = false) buildOptions &= ~BuildOptions.AutoRunPlayer; var buildReport = BuildPipeline.BuildPlayer( - new[] { $"Assets/Scenes/{mainSceneName}.unity" }, + new[] { $"Assets/Scenes/{k_MainSceneName}.unity" }, buildPathToUse, EditorUserBuildSettings.activeBuildTarget, buildOptions); diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs index 7f9f84d82c..7977f9db57 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs @@ -8,8 +8,8 @@ public class MultiprocessOrchestration { - public const string buildInfoFileName = "buildInfo.txt"; - public const string isWorkerArg = "-isWorker"; + public const string BuildInfoFileName = "buildInfo.txt"; + public const string IsWorkerArg = "-isWorker"; public static void StartWorkerNode() { @@ -19,7 +19,7 @@ public static void StartWorkerNode() string buildInstructions = $"You probably didn't generate your build. Please make sure you build a player using the '{BuildMultiprocessTestPlayer.BuildAndExecuteMenuName}' menu"; try { - var buildInfo = File.ReadAllText(Path.Combine(Application.streamingAssetsPath, buildInfoFileName)); + var buildInfo = File.ReadAllText(Path.Combine(Application.streamingAssetsPath, BuildInfoFileName)); switch (Application.platform) { case RuntimePlatform.OSXPlayer: @@ -42,7 +42,7 @@ public static void StartWorkerNode() workerNode.StartInfo.UseShellExecute = false; workerNode.StartInfo.RedirectStandardError = true; workerNode.StartInfo.RedirectStandardOutput = true; - workerNode.StartInfo.Arguments = $"{isWorkerArg} -popupwindow -screen-width 100 -screen-height 100"; + workerNode.StartInfo.Arguments = $"{IsWorkerArg} -popupwindow -screen-width 100 -screen-height 100"; // workerNode.StartInfo.Arguments += " -deepprofiling"; // enable for deep profiling try { From 4ddcd259990a080eeef2072d0e444272c3156fdb Mon Sep 17 00:00:00 2001 From: Sam Bellomo <71790295+SamuelBellomo@users.noreply.github.com> Date: Mon, 5 Jul 2021 18:54:54 -0400 Subject: [PATCH 13/40] Apply suggestions from code review Fixed some typos Co-authored-by: Matt Walsh <69258106+mattwalsh-unity@users.noreply.github.com> --- .../Helpers/BuildMultiprocessTestPlayer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 3e9d4d82d5..f7125cbc25 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -53,7 +53,7 @@ public static void DeleteBuild() } else { - Debug.Log($"exe {exePath} doesn't exists"); + Debug.Log($"exe {exePath} doesn't exist"); } break; case RuntimePlatform.OSXPlayer: @@ -65,7 +65,7 @@ public static void DeleteBuild() } else { - Debug.Log($"directory {toDelete} doesn't exists"); + Debug.Log($"directory {toDelete} doesn't exist"); } break; default: From 55e6853dcc81ed82ef666f818554521bd1090305 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Mon, 5 Jul 2021 18:55:36 -0400 Subject: [PATCH 14/40] Applying suggestions --- .../Helpers/BuildMultiprocessTestPlayer.cs | 6 ++---- .../Helpers/MultiprocessOrchestration.cs | 5 ++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 94bc5a7dcf..88918f9950 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -10,7 +10,7 @@ /// This is needed as Unity throws "An abnormal situation has occurred: the PlayerLoop internal function has been called recursively. Please contact Customer Support with a sample project so that we can reproduce the problem and troubleshoot it." /// when trying to build from Setup() steps in tests. /// -public class BuildMultiprocessTestPlayer : MonoBehaviour +public static class BuildMultiprocessTestPlayer { public const string BuildAndExecuteMenuName = k_MultiprocessBaseMenuName + "/Build - Execute multiprocess tests #%t"; private const string k_MultiprocessBaseMenuName = "MLAPI Multiprocess Test"; @@ -80,9 +80,7 @@ public static void DeleteBuild() public static bool Build(bool isDebug = false) { // Save standalone build path to file so we can read it from standalone tests (that are not running from editor) - var f = File.CreateText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.BuildInfoFileName)); - f.Write(s_BuildPath); - f.Close(); + File.WriteAllText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.BuildInfoFileName), s_BuildPath); // deleting so we don't end up testing on outdated builds if there's a build failure DeleteBuild(); diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs index 7977f9db57..31487b675b 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs @@ -16,6 +16,8 @@ public static void StartWorkerNode() var workerNode = new Process(); //TODO this should be replaced eventually by proper orchestration for all supported platforms + // Starting new local processes is a solution to help run perf tests locally. CI should have multi machine orchestration to + // run performance tests with more realistic conditions. string buildInstructions = $"You probably didn't generate your build. Please make sure you build a player using the '{BuildMultiprocessTestPlayer.BuildAndExecuteMenuName}' menu"; try { @@ -36,7 +38,8 @@ public static void StartWorkerNode() } catch (FileNotFoundException) { - throw new Exception($"Couldn't find build info file. {buildInstructions}"); + Debug.LogError($"Couldn't find build info file. {buildInstructions}"); + throw; } workerNode.StartInfo.UseShellExecute = false; From 17c7e7d9247ff435e7a50fe9fcf140089ffcfa36 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Mon, 5 Jul 2021 19:02:28 -0400 Subject: [PATCH 15/40] naming --- .../Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index 92078a3c98..9b6a8de724 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -43,7 +43,7 @@ public class TestCoordinator : NetworkBehaviour private Dictionary m_ClientIsFinished = new Dictionary(); public static Dictionary>.KeyCollection AllClientIdsWithResults => Instance.m_TestResultsLocal.Keys; - public static List AllClientIdExceptMine => NetworkManager.Singleton.ConnectedClients.Keys.ToList().FindAll(client => client != NetworkManager.Singleton.LocalClientId); + public static List AllClientIdsExceptMine => NetworkManager.Singleton.ConnectedClients.Keys.ToList().FindAll(client => client != NetworkManager.Singleton.LocalClientId); private void Awake() { @@ -241,13 +241,13 @@ public void ClientFinishedServerRpc(ServerRpcParams p = default) public void InvokeFromMethodActionRpc(Action methodInfo, params byte[] args) { var methodInfoString = GetMethodInfo(methodInfo); - InvokeFromMethodNameClientRpc(methodInfoString, args, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = AllClientIdExceptMine.ToArray() } }); + InvokeFromMethodNameClientRpc(methodInfoString, args, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = AllClientIdsExceptMine.ToArray() } }); } public void InvokeFromMethodActionRpc(Action methodInfo) { var methodInfoString = GetMethodInfo(methodInfo); - InvokeFromMethodNameClientRpc(methodInfoString, null, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = AllClientIdExceptMine.ToArray() } }); + InvokeFromMethodNameClientRpc(methodInfoString, null, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = AllClientIdsExceptMine.ToArray() } }); } [ClientRpc] From 72217122102a728f54f3cafc6e24c29faf169d99 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Mon, 5 Jul 2021 19:04:41 -0400 Subject: [PATCH 16/40] should be kept public for following PR --- .../Helpers/BuildMultiprocessTestPlayer.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 4a4023870f..0c017f18d7 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -12,13 +12,13 @@ /// public static class BuildMultiprocessTestPlayer { - public const string BuildAndExecuteMenuName = k_MultiprocessBaseMenuName + "/Build - Execute multiprocess tests #%t"; - private const string k_MultiprocessBaseMenuName = "MLAPI Multiprocess Test"; - private const string k_MainSceneName = "MultiprocessTestingScene"; - private static string s_BuildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTestBuild"); + public const string MultiprocessBaseMenuName = "MLAPI Multiprocess Test"; + public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build - Execute multiprocess tests #%t"; + public const string MainSceneName = "MultiprocessTestingScene"; + public static string BuildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTestBuild"); #if UNITY_EDITOR - [MenuItem(k_MultiprocessBaseMenuName+"/Build Test Player #t")] + [MenuItem(MultiprocessBaseMenuName+"/Build Test Player #t")] public static void BuildNoDebug() { var success = Build(); @@ -28,7 +28,7 @@ public static void BuildNoDebug() } } - [MenuItem(k_MultiprocessBaseMenuName+"/Build Test Player in debug mode")] + [MenuItem(MultiprocessBaseMenuName+"/Build Test Player in debug mode")] public static void BuildDebug() { var success = Build(true); @@ -38,14 +38,14 @@ public static void BuildDebug() } } - [MenuItem(k_MultiprocessBaseMenuName+"/Delete Test Build")] + [MenuItem(MultiprocessBaseMenuName+"/Delete Test Build")] public static void DeleteBuild() { switch (Application.platform) { case RuntimePlatform.WindowsPlayer: case RuntimePlatform.WindowsEditor: - var exePath = $"{s_BuildPath}.exe"; + var exePath = $"{BuildPath}.exe"; if (File.Exists(exePath)) { File.Delete(exePath); @@ -57,7 +57,7 @@ public static void DeleteBuild() break; case RuntimePlatform.OSXPlayer: case RuntimePlatform.OSXEditor: - var toDelete = s_BuildPath + ".app"; + var toDelete = BuildPath + ".app"; if (Directory.Exists(toDelete)) { Directory.Delete(toDelete, recursive: true); @@ -80,7 +80,7 @@ public static void DeleteBuild() public static bool Build(bool isDebug = false) { // Save standalone build path to file so we can read it from standalone tests (that are not running from editor) - File.WriteAllText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.BuildInfoFileName), s_BuildPath); + File.WriteAllText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.BuildInfoFileName), BuildPath); // deleting so we don't end up testing on outdated builds if there's a build failure DeleteBuild(); @@ -95,7 +95,7 @@ public static bool Build(bool isDebug = false) // will have more connection permission popups when launching though } - var buildPathToUse = s_BuildPath; + var buildPathToUse = BuildPath; if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor) { buildPathToUse += ".exe"; @@ -103,7 +103,7 @@ public static bool Build(bool isDebug = false) buildOptions &= ~BuildOptions.AutoRunPlayer; var buildReport = BuildPipeline.BuildPlayer( - new[] { $"Assets/Scenes/{k_MainSceneName}.unity" }, + new[] { $"Assets/Scenes/{MainSceneName}.unity" }, buildPathToUse, EditorUserBuildSettings.activeBuildTarget, buildOptions); From 4ff120694d7b6a84e363d156ac0aff4aad5da13f Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Mon, 5 Jul 2021 19:05:51 -0400 Subject: [PATCH 17/40] apply rename --- .../Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs | 2 +- .../Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs index d49d2f857d..501920e9a8 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs @@ -31,7 +31,7 @@ public virtual void SetupTestSuite() Assert.Ignore("Ignoring tests that shouldn't run from unity editor. Performance tests should be run from remote test execution on device (this can be ran using the \"run selected tests (your platform)\" button"); } - SceneManager.LoadScene(BuildMultiprocessTestPlayer.mainSceneName, LoadSceneMode.Single); + SceneManager.LoadScene(BuildMultiprocessTestPlayer.MainSceneName, LoadSceneMode.Single); SceneManager.sceneLoaded += OnSceneLoaded; for (int i = 0; i < NbWorkers; i++) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index 9b6a8de724..221e97f2a6 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -59,7 +59,7 @@ private void Awake() public void Start() { - bool isClient = Environment.GetCommandLineArgs().Any(value => value == MultiprocessOrchestration.isWorkerArg); + bool isClient = Environment.GetCommandLineArgs().Any(value => value == MultiprocessOrchestration.IsWorkerArg); if (isClient) { Debug.Log("starting MLAPI client"); From 5888f18853774000a5e397c199350bd22275b6f0 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Mon, 5 Jul 2021 19:07:41 -0400 Subject: [PATCH 18/40] rename --- .../Runtime/MultiprocessRuntime/ExecuteStepInContext.cs | 4 ++-- .../MultiprocessRuntime/ExecuteStepInContextTests.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs index 6df0b129ce..ec3f198045 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs @@ -211,9 +211,9 @@ public ExecuteStepInContext(StepExecutionContext actionContext, Action s TestCoordinator.Instance.TriggerActionIDClientRpc(currentActionID, paramToPass, clientRpcParams: new ClientRpcParams { - Send = new ClientRpcSendParams { TargetClientIds = TestCoordinator.AllClientIdExceptMine.ToArray() } + Send = new ClientRpcSendParams { TargetClientIds = TestCoordinator.AllClientIdsExceptMine.ToArray() } }); - foreach (var clientId in TestCoordinator.AllClientIdExceptMine) + foreach (var clientId in TestCoordinator.AllClientIdsExceptMine) { m_ClientIsFinishedChecks.Add(TestCoordinator.ConsumeClientIsFinished(clientId)); } diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs index 9ddaf1d0e5..e63c088c73 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs @@ -129,7 +129,7 @@ void Update(float __) int nbFinished = 0; for (int i = 0; i < m_NbWorkersToTest; i++) { - if (TestCoordinator.PeekLatestResult(TestCoordinator.AllClientIdExceptMine[i]) == maxValue) + if (TestCoordinator.PeekLatestResult(TestCoordinator.AllClientIdsExceptMine[i]) == maxValue) { nbFinished++; } @@ -138,8 +138,8 @@ void Update(float __) }); yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => { - Assert.That(TestCoordinator.AllClientIdExceptMine.Count, Is.EqualTo(m_NbWorkersToTest)); - foreach (var clientID in TestCoordinator.AllClientIdExceptMine) + Assert.That(TestCoordinator.AllClientIdsExceptMine.Count, Is.EqualTo(m_NbWorkersToTest)); + foreach (var clientID in TestCoordinator.AllClientIdsExceptMine) { var current = 0; foreach (var res in TestCoordinator.ConsumeCurrentResult(clientID)) From eeae93cc098e6c4c9ebbcf1191d1edf94f9aa774 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Mon, 5 Jul 2021 19:50:27 -0400 Subject: [PATCH 19/40] using proper list --- .../Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index 221e97f2a6..ae5bcb8518 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -42,7 +42,7 @@ public class TestCoordinator : NetworkBehaviour private Dictionary> m_TestResultsLocal = new Dictionary>(); // this isn't super efficient, but since it's used for signaling around the tests, shouldn't be too bad private Dictionary m_ClientIsFinished = new Dictionary(); - public static Dictionary>.KeyCollection AllClientIdsWithResults => Instance.m_TestResultsLocal.Keys; + public static List AllClientIdsWithResults => Instance.m_TestResultsLocal.Keys.ToList(); public static List AllClientIdsExceptMine => NetworkManager.Singleton.ConnectedClients.Keys.ToList().FindAll(client => client != NetworkManager.Singleton.LocalClientId); private void Awake() From 520c20d449fef6fd85b8b7ced6f458755a564664 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Mon, 5 Jul 2021 19:55:01 -0400 Subject: [PATCH 20/40] better exception --- .../Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index ae5bcb8518..7cf323fb73 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -282,7 +282,7 @@ public void InvokeFromMethodNameClientRpc(string methodInfoString, byte[] args, var foundMethod = foundType.GetMethod(staticMethodToExecute, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (foundMethod == null) { - throw new Exception($"couldn't find method {staticMethodToExecute}"); + throw new MissingMethodException($"couldn't find method {staticMethodToExecute}"); } foundMethod.Invoke(null, args != null ? new object[] { args } : null); From 988574771256188509978db2ab51b6e01d23a415 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Mon, 5 Jul 2021 21:10:32 -0400 Subject: [PATCH 21/40] fix for unused method better comments adding tests to make sure things don't break --- .../ExecuteStepInContext.cs | 12 ++++---- .../ExecuteStepInContextTests.cs | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs index ec3f198045..fedba34887 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs @@ -66,20 +66,20 @@ public IEnumerator AfterTest(ITest test) /// /// This MUST be called at the beginning of each test in order to use context based steps. - /// Assumes this is called from same callsite as ExecuteInContext (and assumes this is called from IEnumerator). + /// Assumes this is called from same callsite as ExecuteStepInContext (and assumes this is called from IEnumerator, the method full name is unique + /// even with the same method name and different parameters). /// This relies on the name to be unique for each generated IEnumerator state machines /// public static void InitContextSteps() { var callerMethod = new StackFrame(1).GetMethod(); - var methodIdentifier = GetMethodIdentifier(callerMethod.DeclaringType.FullName); // since this is called from IEnumerator, this should be a generated class + var methodIdentifier = GetMethodIdentifier(callerMethod); // since this is called from IEnumerator, this should be a generated class, making it unique s_MethodIDCounter[methodIdentifier] = 0; } - private static string GetMethodIdentifier(string callerTypeName) + private static string GetMethodIdentifier(MethodBase callerMethod) { - var info = callerTypeName; - return info; + return callerMethod.DeclaringType.FullName; } internal static void InitializeAllSteps() @@ -184,7 +184,7 @@ public ExecuteStepInContext(StepExecutionContext actionContext, Action s var callerMethod = new StackFrame(1).GetMethod(); // one skip frame for current method - var methodId = GetMethodIdentifier(callerMethod.DeclaringType.FullName); // assumes called from IEnumerator MoveNext, which should be the case since we're a CustomYieldInstruction + var methodId = GetMethodIdentifier(callerMethod); // assumes called from IEnumerator MoveNext, which should be the case since we're a CustomYieldInstruction. This will return a generated class name which should be unique if (!s_MethodIDCounter.ContainsKey(methodId)) { s_MethodIDCounter[methodId] = 0; diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs index e63c088c73..be6d869e75 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs @@ -23,6 +23,36 @@ public ExecuteStepInContextTests(int nbWorkersToTest) protected override int NbWorkers => m_NbWorkersToTest; protected override bool m_IsPerformanceTest => false; + [UnityTest, MultiprocessContextBasedTest] + public IEnumerator TestWithSameName([Values(1)]int a) + { + // ExecuteStepInContext bases itself on method name to identify steps. We need to make sure that methods with + // same names, but different signatures behave correctly + InitContextSteps(); + yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => + { + Assert.That(a, Is.EqualTo(1)); + }); + yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => + { + Assert.That(BitConverter.ToInt32(bytes, 0), Is.EqualTo(1)); + }, paramToPass: BitConverter.GetBytes(a)); + } + + [UnityTest, MultiprocessContextBasedTest] + public IEnumerator TestWithSameName([Values(2)]int a, [Values(3)]int b) + { + InitContextSteps(); + yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => + { + Assert.That(b, Is.EqualTo(3)); + }); + yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => + { + Assert.That(BitConverter.ToInt32(bytes, 0), Is.EqualTo(3)); + }, paramToPass: BitConverter.GetBytes(b)); + } + [UnityTest, MultiprocessContextBasedTest] public IEnumerator TestWithParameters([Values(1, 2, 3)] int a) { From f6309e9cf78b1c962bdc6925d1f5cb0bb7fcb7e7 Mon Sep 17 00:00:00 2001 From: "M. Fatih MAR" Date: Tue, 6 Jul 2021 15:08:22 +0100 Subject: [PATCH 22/40] fix/cleanup asmdefs again --- ...nity.multiplayer.mlapi.runtimetests.asmdef | 6 ++++-- .../Runtime/testproject.runtimetests.asmdef | 20 +++++-------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Tests/Runtime/com.unity.multiplayer.mlapi.runtimetests.asmdef b/com.unity.multiplayer.mlapi/Tests/Runtime/com.unity.multiplayer.mlapi.runtimetests.asmdef index da062e7cb9..6f899c67cc 100644 --- a/com.unity.multiplayer.mlapi/Tests/Runtime/com.unity.multiplayer.mlapi.runtimetests.asmdef +++ b/com.unity.multiplayer.mlapi/Tests/Runtime/com.unity.multiplayer.mlapi.runtimetests.asmdef @@ -8,6 +8,8 @@ "optionalUnityReferences": [ "TestAssemblies" ], - "includePlatforms": [], - "excludePlatforms": [] + "defineConstraints": [ + "UNITY_INCLUDE_TESTS", + "UNITY_EDITOR" + ] } \ No newline at end of file diff --git a/testproject/Assets/Tests/Runtime/testproject.runtimetests.asmdef b/testproject/Assets/Tests/Runtime/testproject.runtimetests.asmdef index 45c640863c..abe114e619 100644 --- a/testproject/Assets/Tests/Runtime/testproject.runtimetests.asmdef +++ b/testproject/Assets/Tests/Runtime/testproject.runtimetests.asmdef @@ -1,25 +1,15 @@ { "name": "TestProject.RuntimeTests", - "rootNamespace": "", "references": [ - "Unity.Multiplayer.MLAPI.Runtime", - "Unity.Multiplayer.MLAPI.RuntimeTests", "TestProject.ManualTests", - "UnityEngine.TestRunner", - "UnityEditor.TestRunner" + "Unity.Multiplayer.MLAPI.Runtime", + "Unity.Multiplayer.MLAPI.RuntimeTests" ], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": true, - "precompiledReferences": [ - "nunit.framework.dll" + "optionalUnityReferences": [ + "TestAssemblies" ], - "autoReferenced": false, "defineConstraints": [ "UNITY_INCLUDE_TESTS", "UNITY_EDITOR" - ], - "versionDefines": [], - "noEngineReferences": false + ] } \ No newline at end of file From cd809ec13ee5a3566d010b8b5963400465f589f5 Mon Sep 17 00:00:00 2001 From: Sam Bellomo <71790295+SamuelBellomo@users.noreply.github.com> Date: Tue, 6 Jul 2021 14:07:36 -0400 Subject: [PATCH 23/40] Apply suggestions from code review Co-authored-by: M. Fatih MAR --- .../MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs index 31487b675b..c5eb6f9893 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs @@ -33,7 +33,7 @@ public static void StartWorkerNode() workerNode.StartInfo.FileName = $"{buildInfo}.exe"; break; default: - throw new NotImplementedException("StartWorkerNode: Current platform not supported"); + throw new NotImplementedException($"{nameof(StartWorkerNode)}: Current platform is not supported"); } } catch (FileNotFoundException) @@ -52,7 +52,7 @@ public static void StartWorkerNode() var newProcessStarted = workerNode.Start(); if (!newProcessStarted) { - throw new Exception("Process not started!"); + throw new Exception("Failed to start process!"); } } catch (Win32Exception e) From 29e05bb500a4a1737a3ad6c6fac08d1cb462a6b0 Mon Sep 17 00:00:00 2001 From: "M. Fatih MAR" Date: Thu, 8 Jul 2021 10:06:34 +0100 Subject: [PATCH 24/40] no longer ignore '[Ss]treamingAssets/buildInfo.txt' --- testproject/.gitignore | 3 --- testproject/Assets/Scenes.meta | 8 ++++++++ testproject/Assets/Tests/Runtime/MultiprocessRuntime.meta | 8 ++++++++ .../Assets/Tests/Runtime/MultiprocessRuntime/Helpers.meta | 8 ++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 testproject/Assets/Scenes.meta create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime.meta create mode 100644 testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers.meta diff --git a/testproject/.gitignore b/testproject/.gitignore index aee9c94cdb..acbbe841e6 100644 --- a/testproject/.gitignore +++ b/testproject/.gitignore @@ -70,7 +70,4 @@ crashlytics-build.properties /[Aa]ssets/[Ss]treamingAssets/aa.meta /[Aa]ssets/[Ss]treamingAssets/aa/* -/[Aa]ssets/[Ss]treamingAssets/buildInfo.txt -/[Aa]ssets/[Ss]treamingAssets/buildInfo.txt.meta - InitTestScene* diff --git a/testproject/Assets/Scenes.meta b/testproject/Assets/Scenes.meta new file mode 100644 index 0000000000..3b475ec820 --- /dev/null +++ b/testproject/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e6274e6e608eb41f2ace27f3a117474d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime.meta new file mode 100644 index 0000000000..6e70f368f6 --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f415999c439ee4394bfb822a0fa30051 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers.meta b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers.meta new file mode 100644 index 0000000000..24050f230a --- /dev/null +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9c9a4d019af9478d9fcebc1ba79d771 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From ed2519c1f0ff8966ba23c8d880f5e0352f5f5d98 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 10:16:10 -0400 Subject: [PATCH 25/40] PR suggestions --- .../Helpers/BuildMultiprocessTestPlayer.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 0c017f18d7..69d0323f3f 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -13,28 +13,28 @@ public static class BuildMultiprocessTestPlayer { public const string MultiprocessBaseMenuName = "MLAPI Multiprocess Test"; - public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build - Execute multiprocess tests #%t"; + public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build Test Player #t"; public const string MainSceneName = "MultiprocessTestingScene"; public static string BuildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTestBuild"); #if UNITY_EDITOR - [MenuItem(MultiprocessBaseMenuName+"/Build Test Player #t")] + [MenuItem(BuildAndExecuteMenuName)] public static void BuildNoDebug() { - var success = Build(); - if (!success) + var report = BuildPlayer(); + if (report.summary.result != BuildResult.Succeeded) { - throw new Exception("Build failed!"); + throw new Exception($"Build failed! {report.summary.totalErrors} errors, {report.summary}"); } } - [MenuItem(MultiprocessBaseMenuName+"/Build Test Player in debug mode")] + [MenuItem(MultiprocessBaseMenuName + "/Build Test Player in debug mode")] public static void BuildDebug() { - var success = Build(true); - if (!success) + var report = BuildPlayer(true); + if (report.summary.result != BuildResult.Succeeded) { - throw new Exception("Build failed!"); + throw new Exception($"Build failed! {report.summary.totalErrors} errors, {report.summary}"); } } @@ -77,7 +77,7 @@ public static void DeleteBuild() /// reporting. We only want to main node to do that, worker nodes should be dumb /// /// - public static bool Build(bool isDebug = false) + public static BuildReport BuildPlayer(bool isDebug = false) { // Save standalone build path to file so we can read it from standalone tests (that are not running from editor) File.WriteAllText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.BuildInfoFileName), BuildPath); @@ -108,7 +108,7 @@ public static bool Build(bool isDebug = false) EditorUserBuildSettings.activeBuildTarget, buildOptions); - return buildReport.summary.result == BuildResult.Succeeded; + return buildReport; } #endif } From b08561a2cef3d8c01f1f2744f42ef528ba72c5fd Mon Sep 17 00:00:00 2001 From: Sam Bellomo <71790295+SamuelBellomo@users.noreply.github.com> Date: Thu, 8 Jul 2021 11:00:24 -0400 Subject: [PATCH 26/40] changing root menu Co-authored-by: M. Fatih MAR --- .../MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 0c017f18d7..34e680c80d 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -12,7 +12,7 @@ /// public static class BuildMultiprocessTestPlayer { - public const string MultiprocessBaseMenuName = "MLAPI Multiprocess Test"; + public const string MultiprocessBaseMenuName = "MLAPI/Multiprocess Test"; public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build - Execute multiprocess tests #%t"; public const string MainSceneName = "MultiprocessTestingScene"; public static string BuildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTestBuild"); From 1c9fb6cd007051e935b5fa0c487f06840246e489 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 12:01:18 -0400 Subject: [PATCH 27/40] # --- .../MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 69d0323f3f..fad39655a7 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -77,7 +77,7 @@ public static void DeleteBuild() /// reporting. We only want to main node to do that, worker nodes should be dumb /// /// - public static BuildReport BuildPlayer(bool isDebug = false) + private static BuildReport BuildPlayer(bool isDebug = false) { // Save standalone build path to file so we can read it from standalone tests (that are not running from editor) File.WriteAllText(Path.Combine(Application.streamingAssetsPath, MultiprocessOrchestration.BuildInfoFileName), BuildPath); From c6d3b4a61ad9eaae1faf28ad0d6e70d511b7bdf6 Mon Sep 17 00:00:00 2001 From: Sam Bellomo <71790295+SamuelBellomo@users.noreply.github.com> Date: Thu, 8 Jul 2021 14:27:36 -0400 Subject: [PATCH 28/40] rename test scene Co-authored-by: M. Fatih MAR --- .../MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 34e680c80d..0904a7485a 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -14,7 +14,7 @@ public static class BuildMultiprocessTestPlayer { public const string MultiprocessBaseMenuName = "MLAPI/Multiprocess Test"; public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build - Execute multiprocess tests #%t"; - public const string MainSceneName = "MultiprocessTestingScene"; + public const string MainSceneName = "MultiprocessTestScene"; public static string BuildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTestBuild"); #if UNITY_EDITOR From 2aa372b5d4cbe03fb0363740cfb0f0965c0e2242 Mon Sep 17 00:00:00 2001 From: Sam Bellomo <71790295+SamuelBellomo@users.noreply.github.com> Date: Thu, 8 Jul 2021 14:30:28 -0400 Subject: [PATCH 29/40] Update testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs Co-authored-by: M. Fatih MAR --- .../Helpers/BuildMultiprocessTestPlayer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 0904a7485a..365e0b3408 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -57,14 +57,14 @@ public static void DeleteBuild() break; case RuntimePlatform.OSXPlayer: case RuntimePlatform.OSXEditor: - var toDelete = BuildPath + ".app"; - if (Directory.Exists(toDelete)) + var appPath = BuildPath + ".app"; + if (Directory.Exists(appPath)) { - Directory.Delete(toDelete, recursive: true); + Directory.Delete(appPath, recursive: true); } else { - Debug.Log($"directory {toDelete} doesn't exist"); + Debug.Log($"[{nameof(BuildMultiprocessTestPlayer)}] MacOS build does not exist ({appPath})"); } break; default: From 484700f01e6b9f0490ddbe870ecc2cf19982e099 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 14:33:20 -0400 Subject: [PATCH 30/40] rename for test scene --- ...MultiprocessTestingScene.unity => MultiprocessTestScene.unity} | 0 ...ssTestingScene.unity.meta => MultiprocessTestScene.unity.meta} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename testproject/Assets/Scenes/{MultiprocessTestingScene.unity => MultiprocessTestScene.unity} (100%) rename testproject/Assets/Scenes/{MultiprocessTestingScene.unity.meta => MultiprocessTestScene.unity.meta} (100%) diff --git a/testproject/Assets/Scenes/MultiprocessTestingScene.unity b/testproject/Assets/Scenes/MultiprocessTestScene.unity similarity index 100% rename from testproject/Assets/Scenes/MultiprocessTestingScene.unity rename to testproject/Assets/Scenes/MultiprocessTestScene.unity diff --git a/testproject/Assets/Scenes/MultiprocessTestingScene.unity.meta b/testproject/Assets/Scenes/MultiprocessTestScene.unity.meta similarity index 100% rename from testproject/Assets/Scenes/MultiprocessTestingScene.unity.meta rename to testproject/Assets/Scenes/MultiprocessTestScene.unity.meta From cba7b19d11daeef64ad3a48cdc479945dbe85079 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 14:37:56 -0400 Subject: [PATCH 31/40] proper rename for scene --- testproject/Assets/Scenes/MultiprocessTestScene.unity | 2 +- testproject/ProjectSettings/EditorBuildSettings.asset | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testproject/Assets/Scenes/MultiprocessTestScene.unity b/testproject/Assets/Scenes/MultiprocessTestScene.unity index 65e0b7ee89..d4a6e985ce 100644 --- a/testproject/Assets/Scenes/MultiprocessTestScene.unity +++ b/testproject/Assets/Scenes/MultiprocessTestScene.unity @@ -683,7 +683,7 @@ MonoBehaviour: ProtocolVersion: 0 NetworkTransport: {fileID: 1674777073} RegisteredScenes: - - MultiprocessTestingScene + - MultiprocessTestScene - SampleScene AllowRuntimeSceneChanges: 0 PlayerPrefab: {fileID: 4700706668509470175, guid: 7eeaaf9e50c0afc4dab93584a54fb0d6, diff --git a/testproject/ProjectSettings/EditorBuildSettings.asset b/testproject/ProjectSettings/EditorBuildSettings.asset index c8f83681c4..0aad2d2bec 100644 --- a/testproject/ProjectSettings/EditorBuildSettings.asset +++ b/testproject/ProjectSettings/EditorBuildSettings.asset @@ -45,6 +45,6 @@ EditorBuildSettings: path: Assets/Tests/Manual/NetworkAnimatorTests/NetworkAnimatorEnhancement.unity guid: f88da8bb8d07e11418eaad6524d5cc12 - enabled: 1 - path: Assets/Scenes/MultiprocessTestingScene.unity + path: Assets/Scenes/MultiprocessTestScene.unity guid: 76743cb7b342c49279327834918a9c6e m_configObjects: {} From 90fffe4ba7edbac100c605946d09aa6070210def Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 15:00:53 -0400 Subject: [PATCH 32/40] # --- .../Helpers/BuildMultiprocessTestPlayer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 2d14b4b44e..a6c5378122 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -15,7 +15,7 @@ public static class BuildMultiprocessTestPlayer public const string MultiprocessBaseMenuName = "MLAPI/Multiprocess Test"; public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build Test Player #t"; public const string MainSceneName = "MultiprocessTestScene"; - public static string BuildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTestBuild"); + public static string BuildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTests/MultiprocessTestBuild"); #if UNITY_EDITOR [MenuItem(BuildAndExecuteMenuName)] @@ -24,7 +24,7 @@ public static void BuildNoDebug() var report = BuildPlayer(); if (report.summary.result != BuildResult.Succeeded) { - throw new Exception($"Build failed! {report.summary.totalErrors} errors, {report.summary}"); + throw new Exception($"Build failed! {report.summary.totalErrors} errors"); } } @@ -34,7 +34,7 @@ public static void BuildDebug() var report = BuildPlayer(true); if (report.summary.result != BuildResult.Succeeded) { - throw new Exception($"Build failed! {report.summary.totalErrors} errors, {report.summary}"); + throw new Exception($"Build failed! {report.summary.totalErrors} errors"); } } From 2c915e92a9ca644db6af7cfa94abade02529b576 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 15:16:56 -0400 Subject: [PATCH 33/40] simpler flow --- .../Helpers/BuildMultiprocessTestPlayer.cs | 38 +++++-------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index a6c5378122..a9b3d7ecf5 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -15,7 +15,8 @@ public static class BuildMultiprocessTestPlayer public const string MultiprocessBaseMenuName = "MLAPI/Multiprocess Test"; public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build Test Player #t"; public const string MainSceneName = "MultiprocessTestScene"; - public static string BuildPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTests/MultiprocessTestBuild"); + public static string BuildPathDirectory => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTests"); + public static string BuildPath => Path.Combine(BuildPathDirectory, "/MultiprocessTestBuild"); #if UNITY_EDITOR [MenuItem(BuildAndExecuteMenuName)] @@ -38,37 +39,16 @@ public static void BuildDebug() } } - [MenuItem(MultiprocessBaseMenuName+"/Delete Test Build")] + [MenuItem(MultiprocessBaseMenuName + "/Delete Test Build")] public static void DeleteBuild() { - switch (Application.platform) + if (Directory.Exists(BuildPathDirectory)) { - case RuntimePlatform.WindowsPlayer: - case RuntimePlatform.WindowsEditor: - var exePath = $"{BuildPath}.exe"; - if (File.Exists(exePath)) - { - File.Delete(exePath); - } - else - { - Debug.Log($"exe {exePath} doesn't exist"); - } - break; - case RuntimePlatform.OSXPlayer: - case RuntimePlatform.OSXEditor: - var appPath = BuildPath + ".app"; - if (Directory.Exists(appPath)) - { - Directory.Delete(appPath, recursive: true); - } - else - { - Debug.Log($"[{nameof(BuildMultiprocessTestPlayer)}] MacOS build does not exist ({appPath})"); - } - break; - default: - throw new NotImplementedException(); + Directory.Delete(BuildPathDirectory, recursive: true); + } + else + { + Debug.Log($"[{nameof(BuildMultiprocessTestPlayer)}] build directory does not exist ({BuildPathDirectory}) not deleting anything"); } } From 9a3bd9b9b698955ad47384fe09d136965d2210ae Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 15:30:03 -0400 Subject: [PATCH 34/40] fixes --- .../Helpers/BuildMultiprocessTestPlayer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index a9b3d7ecf5..3449a4d658 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -15,8 +15,8 @@ public static class BuildMultiprocessTestPlayer public const string MultiprocessBaseMenuName = "MLAPI/Multiprocess Test"; public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build Test Player #t"; public const string MainSceneName = "MultiprocessTestScene"; - public static string BuildPathDirectory => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/MultiprocessTests"); - public static string BuildPath => Path.Combine(BuildPathDirectory, "/MultiprocessTestBuild"); + private static string BuildPathDirectory => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds","MultiprocessTests"); + public static string BuildPath => Path.Combine(BuildPathDirectory, "MultiprocessTestPlayer"); #if UNITY_EDITOR [MenuItem(BuildAndExecuteMenuName)] @@ -80,6 +80,7 @@ private static BuildReport BuildPlayer(bool isDebug = false) { buildPathToUse += ".exe"; } + Debug.Log($"Starting multiprocess player build using path {buildPathToUse}"); buildOptions &= ~BuildOptions.AutoRunPlayer; var buildReport = BuildPipeline.BuildPlayer( @@ -88,6 +89,7 @@ private static BuildReport BuildPlayer(bool isDebug = false) EditorUserBuildSettings.activeBuildTarget, buildOptions); + Debug.Log($"done building"); return buildReport; } #endif From 070f6afcd078bb6772b50218f341b9d606e4c2f3 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 21:58:18 -0400 Subject: [PATCH 35/40] formatting issues --- .../BaseMultiprocessTests.cs | 20 ++++++++++------- .../Helpers/BuildMultiprocessTestPlayer.cs | 2 +- .../Helpers/MultiprocessOrchestration.cs | 1 - .../MultiprocessRuntime/TestCoordinator.cs | 22 +++++++------------ .../TestCoordinatorTests.cs | 17 +++++++------- 5 files changed, 29 insertions(+), 33 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs index 501920e9a8..ace3f408dc 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs @@ -9,19 +9,22 @@ namespace MLAPI.MultiprocessRuntimeTests { public class MultiprocessTestsAttribute : CategoryAttribute { - public const string multiprocessCategoryName = "Multiprocess"; - public MultiprocessTestsAttribute() : base(multiprocessCategoryName){} + public const string MultiprocessCategoryName = "Multiprocess"; + public MultiprocessTestsAttribute() : base(MultiprocessCategoryName) { } } [MultiprocessTests] public abstract class BaseMultiprocessTests { - protected virtual bool m_IsPerformanceTest => true; private bool ShouldIgnoreTests => m_IsPerformanceTest && Application.isEditor; - protected abstract int NbWorkers { get; } + /// + /// Implement this to specify the amount of workers to spawn from your main test runner + /// TODO there's a good chance this will be refactored with something fancier once we start integrating with bokken + /// + protected abstract int WorkerCount { get; } [OneTimeSetUp] public virtual void SetupTestSuite() @@ -34,7 +37,7 @@ public virtual void SetupTestSuite() SceneManager.LoadScene(BuildMultiprocessTestPlayer.MainSceneName, LoadSceneMode.Single); SceneManager.sceneLoaded += OnSceneLoaded; - for (int i = 0; i < NbWorkers; i++) + for (int i = 0; i < WorkerCount; i++) { MultiprocessOrchestration.StartWorkerNode(); // will automatically start built player as clients } @@ -52,15 +55,16 @@ public virtual IEnumerator Setup() yield return new WaitUntil(() => NetworkManager.Singleton != null && NetworkManager.Singleton.IsServer); var startTime = Time.time; - while (NetworkManager.Singleton.ConnectedClients.Count <= NbWorkers) + while (NetworkManager.Singleton.ConnectedClients.Count <= WorkerCount) { yield return new WaitForSeconds(0.2f); - if (Time.time - startTime > TestCoordinator.maxWaitTimeout) + if (Time.time - startTime > TestCoordinator.MaxWaitTimeoutSec) { - throw new Exception($"waiting too long to see clients to connect, got {NetworkManager.Singleton.ConnectedClients.Count - 1} clients, but was expecting {NbWorkers}, failing"); + throw new Exception($"waiting too long to see clients to connect, got {NetworkManager.Singleton.ConnectedClients.Count - 1} clients, but was expecting {WorkerCount}, failing"); } } + TestCoordinator.Instance.KeepAliveClientRpc(); } diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs index 77f877a115..4bfc7ab20f 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs @@ -15,7 +15,7 @@ public static class BuildMultiprocessTestPlayer public const string MultiprocessBaseMenuName = "MLAPI/Multiprocess Test"; public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build Test Player #t"; public const string MainSceneName = "MultiprocessTestScene"; - private static string BuildPathDirectory => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds","MultiprocessTests"); + private static string BuildPathDirectory => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds", "MultiprocessTests"); public static string BuildPath => Path.Combine(BuildPathDirectory, "MultiprocessTestPlayer"); #if UNITY_EDITOR diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs index 18196d7954..b09ee09914 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs @@ -2,7 +2,6 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; -using UnityEditor; using UnityEngine; using Debug = UnityEngine.Debug; diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index 7cf323fb73..61cbbbb234 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -1,17 +1,11 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Reflection; using MLAPI; -using MLAPI.Configuration; -using MLAPI.Logging; using MLAPI.Messaging; using NUnit.Framework; -using NUnit.Framework.Interfaces; using UnityEngine; -using UnityEngine.TestTools; using Debug = UnityEngine.Debug; /// @@ -27,12 +21,11 @@ [RequireComponent(typeof(NetworkObject))] public class TestCoordinator : NetworkBehaviour { - public const int perTestTimeout = 5 * 60; // seconds + public const int PerTestTimeoutSec = 5 * 60; // seconds - public const float maxWaitTimeout = 20; + public const float MaxWaitTimeoutSec = 20; private const char k_MethodFullNameSplitChar = '@'; - private bool m_ShouldShutdown; private float m_TimeSinceLastConnected; private float m_TimeSinceLastKeepAlive; @@ -49,7 +42,7 @@ private void Awake() { if (Instance != null) { - Debug.LogError("Multiple test coordinator! destroying self"); + Debug.LogError("Multiple test coordinator, destroying this instance"); Destroy(gameObject); return; } @@ -73,16 +66,17 @@ public void Start() public void Update() { - if (Time.time - m_TimeSinceLastKeepAlive > perTestTimeout) + if (Time.time - m_TimeSinceLastKeepAlive > PerTestTimeoutSec) { QuitApplication(); Assert.Fail("Stayed idle too long"); } + if ((IsServer && NetworkManager.Singleton.IsListening) || (IsClient && NetworkManager.Singleton.IsConnectedClient)) { m_TimeSinceLastConnected = Time.time; } - else if (Time.time - m_TimeSinceLastConnected > maxWaitTimeout || m_ShouldShutdown) + else if (Time.time - m_TimeSinceLastConnected > MaxWaitTimeoutSec || m_ShouldShutdown) { // Make sure we don't have zombie processes Debug.Log($"quitting application, shouldShutdown set to {m_ShouldShutdown}, is listening {NetworkManager.Singleton.IsListening}, is connected client {NetworkManager.Singleton.IsConnectedClient}"); @@ -182,7 +176,7 @@ public static Func ResultIsSet(bool useTimeoutException = true) var startWaitTime = Time.time; return () => { - if (Time.time - startWaitTime > maxWaitTimeout) + if (Time.time - startWaitTime > MaxWaitTimeoutSec) { if (useTimeoutException) { @@ -209,7 +203,7 @@ public static Func ConsumeClientIsFinished(ulong clientId, bool useTimeout var startWaitTime = Time.time; return () => { - if (Time.time - startWaitTime > maxWaitTimeout) + if (Time.time - startWaitTime > MaxWaitTimeoutSec) { if (useTimeoutException) { diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs index 4c22ca1d21..79d53ed053 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinatorTests.cs @@ -1,4 +1,3 @@ -using System; using System.Collections; using System.Linq; using NUnit.Framework; @@ -11,14 +10,14 @@ namespace MLAPI.MultiprocessRuntimeTests [TestFixture(2)] public class TestCoordinatorTests : BaseMultiprocessTests { - private int m_NbWorkers; - protected override int NbWorkers => m_NbWorkers; + private int m_WorkerCount; + protected override int WorkerCount => m_WorkerCount; protected override bool m_IsPerformanceTest => false; - public TestCoordinatorTests(int nbWorkers) + public TestCoordinatorTests(int workerCount) { - m_NbWorkers = nbWorkers; + m_WorkerCount = workerCount; } private static void ExecuteSimpleCoordinatorTest() @@ -39,7 +38,7 @@ public IEnumerator CheckTestCoordinator() TestCoordinator.Instance.InvokeFromMethodActionRpc(ExecuteSimpleCoordinatorTest); var nbResults = 0; - for (int i = 0; i < NbWorkers; i++) // wait and test for the two clients + for (int i = 0; i < WorkerCount; i++) // wait and test for the two clients { yield return new WaitUntil(TestCoordinator.ResultIsSet()); @@ -47,7 +46,7 @@ public IEnumerator CheckTestCoordinator() Assert.Greater(result, 0f); nbResults++; } - Assert.That(nbResults, Is.EqualTo(NbWorkers)); + Assert.That(nbResults, Is.EqualTo(WorkerCount)); } [UnityTest] @@ -56,7 +55,7 @@ public IEnumerator CheckTestCoordinatorWithArgs() TestCoordinator.Instance.InvokeFromMethodActionRpc(ExecuteWithArgs, 99); var nbResults = 0; - for (int i = 0; i < NbWorkers; i++) // wait and test for the two clients + for (int i = 0; i < WorkerCount; i++) // wait and test for the two clients { yield return new WaitUntil(TestCoordinator.ResultIsSet()); @@ -64,7 +63,7 @@ public IEnumerator CheckTestCoordinatorWithArgs() Assert.That(result, Is.EqualTo(99)); nbResults++; } - Assert.That(nbResults, Is.EqualTo(NbWorkers)); + Assert.That(nbResults, Is.EqualTo(WorkerCount)); } } } From 8f8f7ec549d8f5e398551aa33789fa969e518a8c Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 22:04:04 -0400 Subject: [PATCH 36/40] name fix --- .../Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs | 2 +- .../Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs index fedba34887..3cc40ffbfe 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs @@ -57,7 +57,7 @@ public IEnumerator AfterTest(ITest test) private bool m_IgnoreTimeoutException; private float m_StartTime; - private bool isTimingOut => Time.time - m_StartTime > TestCoordinator.maxWaitTimeout; + private bool isTimingOut => Time.time - m_StartTime > TestCoordinator.MaxWaitTimeoutSec; private bool ShouldExecuteLocally => (m_ActionContext == StepExecutionContext.Server && m_NetworkManager.IsServer) || (m_ActionContext == StepExecutionContext.Clients && !m_NetworkManager.IsServer); public static bool isRegistering; diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs index be6d869e75..3b56a3908f 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs @@ -20,7 +20,7 @@ public ExecuteStepInContextTests(int nbWorkersToTest) { m_NbWorkersToTest = nbWorkersToTest; } - protected override int NbWorkers => m_NbWorkersToTest; + protected override int WorkerCount => m_NbWorkersToTest; protected override bool m_IsPerformanceTest => false; [UnityTest, MultiprocessContextBasedTest] @@ -214,7 +214,7 @@ public IEnumerator TestExecuteInContext() Assert.AreEqual(12345, res.result); } - Assert.That(resultCountFromWorkers, Is.EqualTo(NbWorkers)); + Assert.That(resultCountFromWorkers, Is.EqualTo(WorkerCount)); }); const int timeToWait = 4; From 58975611f85eca2bd5e11be951d3f347166edb55 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 23:00:08 -0400 Subject: [PATCH 37/40] format update --- .../ExecuteStepInContext.cs | 70 +++++++++---------- .../ExecuteStepInContextTests.cs | 64 +++++++++-------- .../MultiprocessRuntime/TestCoordinator.cs | 8 +-- 3 files changed, 73 insertions(+), 69 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs index 3cc40ffbfe..5540ba3cdf 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContext.cs @@ -31,7 +31,7 @@ public class MultiprocessContextBasedTestAttribute : NUnitAttribute, IOuterUnity { public IEnumerator BeforeTest(ITest test) { - yield return new WaitUntil(() => TestCoordinator.Instance != null && hasRegistered); + yield return new WaitUntil(() => TestCoordinator.Instance != null && HasRegistered); } public IEnumerator AfterTest(ITest test) @@ -42,11 +42,11 @@ public IEnumerator AfterTest(ITest test) private StepExecutionContext m_ActionContext; private Action m_StepToExecute; - private string m_CurrentActionID; + private string m_CurrentActionId; // as a remote worker, I store all available actions so I can execute them when triggered from RPCs - public static Dictionary allActions = new Dictionary(); - private static Dictionary s_MethodIDCounter = new Dictionary(); + public static Dictionary AllActions = new Dictionary(); + private static Dictionary s_MethodIdCounter = new Dictionary(); private NetworkManager m_NetworkManager; private bool m_IsRegistering; @@ -58,11 +58,11 @@ public IEnumerator AfterTest(ITest test) private float m_StartTime; private bool isTimingOut => Time.time - m_StartTime > TestCoordinator.MaxWaitTimeoutSec; - private bool ShouldExecuteLocally => (m_ActionContext == StepExecutionContext.Server && m_NetworkManager.IsServer) || (m_ActionContext == StepExecutionContext.Clients && !m_NetworkManager.IsServer); + private bool shouldExecuteLocally => (m_ActionContext == StepExecutionContext.Server && m_NetworkManager.IsServer) || (m_ActionContext == StepExecutionContext.Clients && !m_NetworkManager.IsServer); - public static bool isRegistering; - public static bool hasRegistered; - private static List m_AllClientTestInstances = new List(); // to keep an instance for each tests, so captured context in each step is kept + public static bool IsRegistering; + public static bool HasRegistered; + private static List s_AllClientTestInstances = new List(); // to keep an instance for each tests, so captured context in each step is kept /// /// This MUST be called at the beginning of each test in order to use context based steps. @@ -70,11 +70,11 @@ public IEnumerator AfterTest(ITest test) /// even with the same method name and different parameters). /// This relies on the name to be unique for each generated IEnumerator state machines /// - public static void InitContextSteps() + public static void InitializeContextSteps() { var callerMethod = new StackFrame(1).GetMethod(); var methodIdentifier = GetMethodIdentifier(callerMethod); // since this is called from IEnumerator, this should be a generated class, making it unique - s_MethodIDCounter[methodIdentifier] = 0; + s_MethodIdCounter[methodIdentifier] = 0; } private static string GetMethodIdentifier(MethodBase callerMethod) @@ -85,11 +85,11 @@ private static string GetMethodIdentifier(MethodBase callerMethod) internal static void InitializeAllSteps() { // registering magically all context based steps - isRegistering = true; + IsRegistering = true; var registeredMethods = typeof(TestCoordinator).Assembly.GetTypes().SelectMany(t => t.GetMethods()) - .Where(m => m.GetCustomAttributes(typeof(ExecuteStepInContext.MultiprocessContextBasedTestAttribute), true).Length > 0) + .Where(m => m.GetCustomAttributes(typeof(MultiprocessContextBasedTestAttribute), true).Length > 0) .ToArray(); - HashSet typesWithContextMethods = new HashSet(); + var typesWithContextMethods = new HashSet(); foreach (var method in registeredMethods) { typesWithContextMethods.Add(method.ReflectedType); @@ -97,10 +97,10 @@ internal static void InitializeAllSteps() if (registeredMethods.Length == 0) { - throw new Exception("Couldn't find any registered methods for multiprocess testing. Is TestCoordinator in same assembly as test methods?"); + throw new Exception($"Couldn't find any registered methods for multiprocess testing. Is {nameof(TestCoordinator)} in same assembly as test methods?"); } - object[] GetParameterValuesToPass(ParameterInfo[] parameterInfo) + object[] GetParameterValuesToPassFunc(ParameterInfo[] parameterInfo) { object[] parametersToReturn = new object[parameterInfo.Length]; for (int i = 0; i < parameterInfo.Length; i++) @@ -123,16 +123,16 @@ object[] GetParameterValuesToPass(ParameterInfo[] parameterInfo) var allConstructors = contextType.GetConstructors(); if (allConstructors.Length > 1) { - throw new NotImplementedException("Case not implemented where test has more than one contructor"); + throw new NotImplementedException("Case not implemented where test has more than one constructor"); } - var instance = Activator.CreateInstance(contextType, allConstructors.Length > 0 ? GetParameterValuesToPass(allConstructors[0].GetParameters()) : null); - m_AllClientTestInstances.Add(instance); // keeping that instance so tests can use captured local attributes + var instance = Activator.CreateInstance(contextType, allConstructors.Length > 0 ? GetParameterValuesToPassFunc(allConstructors[0].GetParameters()) : null); + s_AllClientTestInstances.Add(instance); // keeping that instance so tests can use captured local attributes - List typeMethodsWithContextSteps = new List(); + var typeMethodsWithContextSteps = new List(); foreach (var method in contextType.GetMethods()) { - if (method.GetCustomAttributes(typeof(ExecuteStepInContext.MultiprocessContextBasedTestAttribute), true).Length > 0) + if (method.GetCustomAttributes(typeof(MultiprocessContextBasedTestAttribute), true).Length > 0) { typeMethodsWithContextSteps.Add(method); } @@ -140,14 +140,14 @@ object[] GetParameterValuesToPass(ParameterInfo[] parameterInfo) foreach (var method in typeMethodsWithContextSteps) { - var parametersToPass = GetParameterValuesToPass(method.GetParameters()); + var parametersToPass = GetParameterValuesToPassFunc(method.GetParameters()); var enumerator = (IEnumerator)method.Invoke(instance, parametersToPass.ToArray()); while (enumerator.MoveNext()) { } } } - isRegistering = false; - hasRegistered = true; + IsRegistering = false; + HasRegistered = true; } /// @@ -164,7 +164,7 @@ object[] GetParameterValuesToPass(ParameterInfo[] parameterInfo) public ExecuteStepInContext(StepExecutionContext actionContext, Action stepToExecute, bool ignoreTimeoutException = false, byte[] paramToPass = default, NetworkManager networkManager = null, bool waitMultipleUpdates = false, Func additionalIsFinishedWaiter = null) { m_StartTime = Time.time; - m_IsRegistering = isRegistering; + m_IsRegistering = IsRegistering; m_ActionContext = actionContext; m_StepToExecute = stepToExecute; m_WaitMultipleUpdates = waitMultipleUpdates; @@ -185,22 +185,22 @@ public ExecuteStepInContext(StepExecutionContext actionContext, Action s var callerMethod = new StackFrame(1).GetMethod(); // one skip frame for current method var methodId = GetMethodIdentifier(callerMethod); // assumes called from IEnumerator MoveNext, which should be the case since we're a CustomYieldInstruction. This will return a generated class name which should be unique - if (!s_MethodIDCounter.ContainsKey(methodId)) + if (!s_MethodIdCounter.ContainsKey(methodId)) { - s_MethodIDCounter[methodId] = 0; + s_MethodIdCounter[methodId] = 0; } - string currentActionID = $"{methodId}-{s_MethodIDCounter[methodId]++}"; - m_CurrentActionID = currentActionID; + string currentActionId = $"{methodId}-{s_MethodIdCounter[methodId]++}"; + m_CurrentActionId = currentActionId; if (m_IsRegistering) { - Assert.That(allActions, Does.Not.Contain(currentActionID)); // sanity check - allActions[currentActionID] = this; + Assert.That(AllActions, Does.Not.Contain(currentActionId)); // sanity check + AllActions[currentActionId] = this; } else { - if (ShouldExecuteLocally) + if (shouldExecuteLocally) { m_StepToExecute.Invoke(paramToPass); } @@ -208,7 +208,7 @@ public ExecuteStepInContext(StepExecutionContext actionContext, Action s { if (networkManager.IsServer) { - TestCoordinator.Instance.TriggerActionIDClientRpc(currentActionID, paramToPass, + TestCoordinator.Instance.TriggerActionIdClientRpc(currentActionId, paramToPass, clientRpcParams: new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = TestCoordinator.AllClientIdsExceptMine.ToArray() } @@ -250,11 +250,11 @@ public override bool keepWaiting { if (m_IgnoreTimeoutException) { - Debug.LogWarning($"Timeout ignored for action ID {m_CurrentActionID}"); + Debug.LogWarning($"Timeout ignored for action ID {m_CurrentActionId}"); return false; } - throw new Exception($"timeout for Context Step with action ID {m_CurrentActionID}"); + throw new Exception($"timeout for Context Step with action ID {m_CurrentActionId}"); } if (m_AdditionalIsFinishedWaiter != null) @@ -266,7 +266,7 @@ public override bool keepWaiting } } - if (m_IsRegistering || ShouldExecuteLocally || m_ClientIsFinishedChecks == null) + if (m_IsRegistering || shouldExecuteLocally || m_ClientIsFinishedChecks == null) { return false; } diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs index 3b56a3908f..d351cbb99d 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/ExecuteStepInContextTests.cs @@ -15,20 +15,22 @@ namespace MLAPI.MultiprocessRuntimeTests [TestFixture(2)] public class ExecuteStepInContextTests : BaseMultiprocessTests { - private int m_NbWorkersToTest; - public ExecuteStepInContextTests(int nbWorkersToTest) + private int m_WorkerCountToTest; + + public ExecuteStepInContextTests(int workerCountToTest) { - m_NbWorkersToTest = nbWorkersToTest; + m_WorkerCountToTest = workerCountToTest; } - protected override int WorkerCount => m_NbWorkersToTest; + + protected override int WorkerCount => m_WorkerCountToTest; protected override bool m_IsPerformanceTest => false; [UnityTest, MultiprocessContextBasedTest] - public IEnumerator TestWithSameName([Values(1)]int a) + public IEnumerator TestWithSameName([Values(1)] int a) { // ExecuteStepInContext bases itself on method name to identify steps. We need to make sure that methods with // same names, but different signatures behave correctly - InitContextSteps(); + InitializeContextSteps(); yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => { Assert.That(a, Is.EqualTo(1)); @@ -40,9 +42,9 @@ public IEnumerator TestWithSameName([Values(1)]int a) } [UnityTest, MultiprocessContextBasedTest] - public IEnumerator TestWithSameName([Values(2)]int a, [Values(3)]int b) + public IEnumerator TestWithSameName([Values(2)] int a, [Values(3)] int b) { - InitContextSteps(); + InitializeContextSteps(); yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => { Assert.That(b, Is.EqualTo(3)); @@ -56,7 +58,7 @@ public IEnumerator TestWithSameName([Values(2)]int a, [Values(3)]int b) [UnityTest, MultiprocessContextBasedTest] public IEnumerator TestWithParameters([Values(1, 2, 3)] int a) { - InitContextSteps(); + InitializeContextSteps(); yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => { @@ -78,7 +80,7 @@ public IEnumerator TestWithParameters([Values(1, 2, 3)] int a) [TestCase(3, 4, ExpectedResult = null)] public IEnumerator TestWithParameters(int a, int b) { - InitContextSteps(); + InitializeContextSteps(); yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => { @@ -99,7 +101,7 @@ public IEnumerator TestWithParameters(int a, int b) [UnityTest, MultiprocessContextBasedTest] public IEnumerator TestExceptionClientSide() { - InitContextSteps(); + InitializeContextSteps(); const string exceptionMessageToTest = "This is an exception for TestCoordinator that's expected"; yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => @@ -108,7 +110,7 @@ public IEnumerator TestExceptionClientSide() }, ignoreTimeoutException: true); yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => { - for (int i = 0; i < m_NbWorkersToTest; i++) + for (int i = 0; i < m_WorkerCountToTest; i++) { LogAssert.Expect(LogType.Error, new Regex($".*{exceptionMessageToTest}.*")); } @@ -117,17 +119,17 @@ public IEnumerator TestExceptionClientSide() const string exceptionUpdateMessageToTest = "This is an exception for update loop client side that's expected"; yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => { - void Update(float __) + void UpdateFunc(float _) { - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= Update; + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= UpdateFunc; throw new Exception(exceptionUpdateMessageToTest); } - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += Update; + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += UpdateFunc; }, ignoreTimeoutException: true); yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => { - for (int i = 0; i < m_NbWorkersToTest; i++) + for (int i = 0; i < m_WorkerCountToTest; i++) { LogAssert.Expect(LogType.Error, new Regex($".*{exceptionUpdateMessageToTest}.*")); } @@ -137,45 +139,47 @@ void Update(float __) [UnityTest, MultiprocessContextBasedTest] public IEnumerator ContextTestWithAdditionalWait() { - InitContextSteps(); + InitializeContextSteps(); const int maxValue = 10; yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => { int count = 0; - void Update(float __) + void UpdateFunc(float _) { TestCoordinator.Instance.WriteTestResultsServerRpc(count++); if (count > maxValue) { - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= Update; + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= UpdateFunc; } } - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += Update; + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += UpdateFunc; }, additionalIsFinishedWaiter: () => { int nbFinished = 0; - for (int i = 0; i < m_NbWorkersToTest; i++) + for (int i = 0; i < m_WorkerCountToTest; i++) { if (TestCoordinator.PeekLatestResult(TestCoordinator.AllClientIdsExceptMine[i]) == maxValue) { nbFinished++; } } - return nbFinished == m_NbWorkersToTest; + + return nbFinished == m_WorkerCountToTest; }); yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => { - Assert.That(TestCoordinator.AllClientIdsExceptMine.Count, Is.EqualTo(m_NbWorkersToTest)); - foreach (var clientID in TestCoordinator.AllClientIdsExceptMine) + Assert.That(TestCoordinator.AllClientIdsExceptMine.Count, Is.EqualTo(m_WorkerCountToTest)); + foreach (var clientId in TestCoordinator.AllClientIdsExceptMine) { var current = 0; - foreach (var res in TestCoordinator.ConsumeCurrentResult(clientID)) + foreach (var res in TestCoordinator.ConsumeCurrentResult(clientId)) { Assert.That(res, Is.EqualTo(current++)); } + Assert.That(current - 1, Is.EqualTo(maxValue)); } }); @@ -184,7 +188,7 @@ void Update(float __) [UnityTest, MultiprocessContextBasedTest] public IEnumerator TestExecuteInContext() { - InitContextSteps(); + InitializeContextSteps(); int stepCountExecuted = 0; yield return new ExecuteStepInContext(StepExecutionContext.Server, args => @@ -220,18 +224,18 @@ public IEnumerator TestExecuteInContext() const int timeToWait = 4; yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => { - void Update(float __) + void UpdateFunc(float _) { if (Time.time > timeToWait) { - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= Update; + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= UpdateFunc; TestCoordinator.Instance.WriteTestResultsServerRpc(Time.time); TestCoordinator.Instance.ClientFinishedServerRpc(); // since finishOnInvoke is false, we need to do this manually } } - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += Update; + NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += UpdateFunc; }, waitMultipleUpdates: true); // waits multiple frames before allowing the next action to continue. yield return new ExecuteStepInContext(StepExecutionContext.Server, args => @@ -247,7 +251,7 @@ void Update(float __) Assert.Greater(count, 0); }); - if (!isRegistering) + if (!IsRegistering) { Assert.AreEqual(3, stepCountExecuted); } diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index b8f11a8a0a..33396b0ec6 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -143,9 +143,9 @@ private static string GetMethodInfo(Action method) } } - public static IEnumerable ConsumeCurrentResult(ulong clientID) + public static IEnumerable ConsumeCurrentResult(ulong clientId) { - var allResults = Instance.m_TestResultsLocal[clientID]; + var allResults = Instance.m_TestResultsLocal[clientId]; while (allResults.Count > 0) { var toReturn = allResults[0]; @@ -245,9 +245,9 @@ public void InvokeFromMethodActionRpc(Action methodInfo) } [ClientRpc] - public void TriggerActionIDClientRpc(string actionID, byte[] args, ClientRpcParams clientRpcParams = default) + public void TriggerActionIdClientRpc(string actionId, byte[] args, ClientRpcParams clientRpcParams = default) { - Debug.Log($"received RPC from server, client side triggering action ID {actionID}"); + Debug.Log($"received RPC from server, client side triggering action ID {actionId}"); try { ExecuteStepInContext.allActions[actionID].Invoke(args); From e64b12e22b98c5579f0f8751e48df2ba4aece032 Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 23:01:41 -0400 Subject: [PATCH 38/40] name fix --- .../Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index 61cbbbb234..fc0efec2e1 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -250,7 +250,7 @@ public void TriggerActionIDClientRpc(string actionID, byte[] args, ClientRpcPara Debug.Log($"received RPC from server, client side triggering action ID {actionID}"); try { - // ExecuteStepInContext.allActions[actionID].Invoke(args); + //ExecuteStepInContext.AllActions[actionId].Invoke(args); } catch (Exception e) { From 750a3b52f99c0e92d915e2b7dfaa8939b6ec459b Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Thu, 8 Jul 2021 23:23:11 -0400 Subject: [PATCH 39/40] # --- .../Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs index 33396b0ec6..69d83f358f 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/TestCoordinator.cs @@ -250,7 +250,7 @@ public void TriggerActionIdClientRpc(string actionId, byte[] args, ClientRpcPara Debug.Log($"received RPC from server, client side triggering action ID {actionId}"); try { - ExecuteStepInContext.allActions[actionID].Invoke(args); + ExecuteStepInContext.AllActions[actionId].Invoke(args); } catch (Exception e) { From 50398b393a2f51ca447b52b7ae3453bfe1b16ffd Mon Sep 17 00:00:00 2001 From: Samuel Bellomo Date: Fri, 9 Jul 2021 15:22:32 -0400 Subject: [PATCH 40/40] fix for automation fail right now --- .../Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs | 2 +- .../Helpers/MultiprocessOrchestration.cs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs index ace3f408dc..f6b82d71db 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/BaseMultiprocessTests.cs @@ -18,7 +18,7 @@ public abstract class BaseMultiprocessTests { protected virtual bool m_IsPerformanceTest => true; - private bool ShouldIgnoreTests => m_IsPerformanceTest && Application.isEditor; + private bool ShouldIgnoreTests => m_IsPerformanceTest && Application.isEditor || MultiprocessOrchestration.IsUsingUTR(); // todo remove UTR check once we have proper automation /// /// Implement this to specify the amount of workers to spawn from your main test runner diff --git a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs index b09ee09914..6dec09b4cb 100644 --- a/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs +++ b/testproject/Assets/Tests/Runtime/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; +using System.Linq; using UnityEngine; using Debug = UnityEngine.Debug; @@ -60,4 +61,10 @@ public static void StartWorkerNode() throw; } } + + // todo remove this once we have proper automation + public static bool IsUsingUTR() + { + return Environment.GetCommandLineArgs().Contains("-automated"); + } }