GlobalGameJame/Library/PackageCache/com.unity.test-framework@1.1.9/UnityEditor.TestRunner/TestLaunchers/PlayerLauncher.cs

207 lines
9.1 KiB
C#
Raw Normal View History

2020-01-31 15:10:04 +00:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using NUnit.Framework.Internal.Filters;
using UnityEditor;
using UnityEditor.TestRunner.TestLaunchers;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TestRunner.Utils;
using UnityEngine.TestTools.TestRunner;
using UnityEngine.TestTools.TestRunner.Callbacks;
namespace UnityEditor.TestTools.TestRunner
{
internal class TestLaunchFailedException : Exception
{
public TestLaunchFailedException() {}
public TestLaunchFailedException(string message) : base(message) {}
}
[Serializable]
internal class PlayerLauncher : RuntimeTestLauncherBase
{
private readonly PlaymodeTestsControllerSettings m_Settings;
private readonly BuildTarget m_TargetPlatform;
private ITestRunSettings m_OverloadTestRunSettings;
private string m_SceneName;
private int m_HeartbeatTimeout;
public PlayerLauncher(PlaymodeTestsControllerSettings settings, BuildTarget? targetPlatform, ITestRunSettings overloadTestRunSettings, int heartbeatTimeout)
{
m_Settings = settings;
m_TargetPlatform = targetPlatform ?? EditorUserBuildSettings.activeBuildTarget;
m_OverloadTestRunSettings = overloadTestRunSettings;
m_HeartbeatTimeout = heartbeatTimeout;
}
protected override RuntimePlatform? TestTargetPlatform
{
get { return BuildTargetConverter.TryConvertToRuntimePlatform(m_TargetPlatform); }
}
public override void Run()
{
var editorConnectionTestCollector = RemoteTestRunController.instance;
editorConnectionTestCollector.hideFlags = HideFlags.HideAndDontSave;
editorConnectionTestCollector.Init(m_TargetPlatform, m_HeartbeatTimeout);
var remotePlayerLogController = RemotePlayerLogController.instance;
remotePlayerLogController.hideFlags = HideFlags.HideAndDontSave;
using (var settings = new PlayerLauncherContextSettings(m_OverloadTestRunSettings))
{
m_SceneName = CreateSceneName();
var scene = PrepareScene(m_SceneName);
string scenePath = scene.path;
var filter = m_Settings.BuildNUnitFilter();
var runner = LoadTests(filter);
var exceptionThrown = ExecutePreBuildSetupMethods(runner.LoadedTest, filter);
if (exceptionThrown)
{
ReopenOriginalScene(m_Settings.originalScene);
AssetDatabase.DeleteAsset(m_SceneName);
CallbacksDelegator.instance.RunFailed("Run Failed: One or more errors in a prebuild setup. See the editor log for details.");
return;
}
var playerBuildOptions = GetBuildOptions(scenePath);
var success = BuildAndRunPlayer(playerBuildOptions);
editorConnectionTestCollector.PostBuildAction();
ExecutePostBuildCleanupMethods(runner.LoadedTest, filter);
ReopenOriginalScene(m_Settings.originalScene);
AssetDatabase.DeleteAsset(m_SceneName);
if (!success)
{
ScriptableObject.DestroyImmediate(editorConnectionTestCollector);
Debug.LogError("Player build failed");
throw new TestLaunchFailedException("Player build failed");
}
editorConnectionTestCollector.PostSuccessfulBuildAction();
}
}
public Scene PrepareScene(string sceneName)
{
var scene = CreateBootstrapScene(sceneName, runner =>
{
runner.AddEventHandlerMonoBehaviour<PlayModeRunnerCallback>();
runner.settings = m_Settings;
runner.AddEventHandlerMonoBehaviour<RemoteTestResultSender>();
runner.AddEventHandlerScriptableObject<TestRunCallbackListener>();
});
return scene;
}
private static bool BuildAndRunPlayer(PlayerLauncherBuildOptions buildOptions)
{
Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, "Building player with following options:\n{0}", buildOptions);
// Android has to be in listen mode to establish player connection
if (buildOptions.BuildPlayerOptions.target == BuildTarget.Android)
{
buildOptions.BuildPlayerOptions.options &= ~BuildOptions.ConnectToHost;
}
// For now, so does Lumin
if (buildOptions.BuildPlayerOptions.target == BuildTarget.Lumin)
{
buildOptions.BuildPlayerOptions.options &= ~BuildOptions.ConnectToHost;
}
var result = BuildPipeline.BuildPlayer(buildOptions.BuildPlayerOptions);
if (result.summary.result != Build.Reporting.BuildResult.Succeeded)
Debug.LogError(result.SummarizeErrors());
return result.summary.result == Build.Reporting.BuildResult.Succeeded;
}
private PlayerLauncherBuildOptions GetBuildOptions(string scenePath)
{
var buildOptions = new BuildPlayerOptions();
var reduceBuildLocationPathLength = false;
//Some platforms hit MAX_PATH limits during the build process, in these cases minimize the path length
if ((m_TargetPlatform == BuildTarget.WSAPlayer) || (m_TargetPlatform == BuildTarget.XboxOne))
{
reduceBuildLocationPathLength = true;
}
var scenes = new List<string>() { scenePath };
scenes.AddRange(EditorBuildSettings.scenes.Select(x => x.path));
buildOptions.scenes = scenes.ToArray();
buildOptions.options |= BuildOptions.AutoRunPlayer | BuildOptions.Development | BuildOptions.ConnectToHost | BuildOptions.IncludeTestAssemblies | BuildOptions.StrictMode;
buildOptions.target = m_TargetPlatform;
if (EditorUserBuildSettings.waitForPlayerConnection)
buildOptions.options |= BuildOptions.WaitForPlayerConnection;
var buildTargetGroup = EditorUserBuildSettings.activeBuildTargetGroup;
//Check if Lz4 is supported for the current buildtargetgroup and enable it if need be
if (PostprocessBuildPlayer.SupportsLz4Compression(buildTargetGroup, m_TargetPlatform))
{
if (EditorUserBuildSettings.GetCompressionType(buildTargetGroup) == Compression.Lz4)
buildOptions.options |= BuildOptions.CompressWithLz4;
else if (EditorUserBuildSettings.GetCompressionType(buildTargetGroup) == Compression.Lz4HC)
buildOptions.options |= BuildOptions.CompressWithLz4HC;
}
var uniqueTempPathInProject = FileUtil.GetUniqueTempPathInProject();
var playerDirectoryName = reduceBuildLocationPathLength ? "PwT" : "PlayerWithTests";
if (reduceBuildLocationPathLength)
{
uniqueTempPathInProject = Path.GetTempFileName();
File.Delete(uniqueTempPathInProject);
Directory.CreateDirectory(uniqueTempPathInProject);
}
var tempPath = Path.GetFullPath(uniqueTempPathInProject);
var buildLocation = Path.Combine(tempPath, playerDirectoryName);
// iOS builds create a folder with Xcode project instead of an executable, therefore no executable name is added
if (m_TargetPlatform == BuildTarget.iOS)
{
buildOptions.locationPathName = buildLocation;
}
else
{
string extensionForBuildTarget = PostprocessBuildPlayer.GetExtensionForBuildTarget(buildTargetGroup, buildOptions.target, buildOptions.options);
var playerExecutableName = "PlayerWithTests";
playerExecutableName += string.Format(".{0}", extensionForBuildTarget);
buildOptions.locationPathName = Path.Combine(buildLocation, playerExecutableName);
}
return new PlayerLauncherBuildOptions
{
BuildPlayerOptions = ModifyBuildOptions(buildOptions),
PlayerDirectory = buildLocation,
};
}
private BuildPlayerOptions ModifyBuildOptions(BuildPlayerOptions buildOptions)
{
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(x => x.GetReferencedAssemblies().Any(z => z.Name == "UnityEngine.TestRunner")).ToArray();
var attributes = allAssemblies.SelectMany(assembly => assembly.GetCustomAttributes(typeof(TestPlayerBuildModifierAttribute), true).OfType<TestPlayerBuildModifierAttribute>()).ToArray();
var modifiers = attributes.Select(attribute => attribute.ConstructModifier()).ToArray();
foreach (var modifier in modifiers)
{
buildOptions = modifier.ModifyOptions(buildOptions);
}
return buildOptions;
}
}
}