test
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.TestRunner.TestLaunchers;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal class Executer : IExecuter
|
||||
{
|
||||
internal IRunData runData = RunData.instance;
|
||||
|
||||
private ITestRunnerApi m_TestRunnerApi;
|
||||
private ISettingsBuilder m_SettingsBuilder;
|
||||
private Action<string, object[]> m_LogErrorFormat;
|
||||
private Action<Exception> m_LogException;
|
||||
private Action<string> m_LogMessage;
|
||||
private Action<int> m_ExitEditorApplication;
|
||||
private Func<bool> m_ScriptCompilationFailedCheck;
|
||||
private Func<bool> m_IsRunActive;
|
||||
|
||||
public Executer(ITestRunnerApi testRunnerApi, ISettingsBuilder settingsBuilder, Action<string, object[]> logErrorFormat, Action<Exception> logException, Action<string> logMessage, Action<int> exitEditorApplication, Func<bool> scriptCompilationFailedCheck, Func<bool> isRunActive)
|
||||
{
|
||||
m_TestRunnerApi = testRunnerApi;
|
||||
m_SettingsBuilder = settingsBuilder;
|
||||
m_LogErrorFormat = logErrorFormat;
|
||||
m_LogException = logException;
|
||||
m_LogMessage = logMessage;
|
||||
m_ExitEditorApplication = exitEditorApplication;
|
||||
m_ScriptCompilationFailedCheck = scriptCompilationFailedCheck;
|
||||
m_IsRunActive = isRunActive;
|
||||
}
|
||||
|
||||
public string InitializeAndExecuteRun(string[] commandLineArgs)
|
||||
{
|
||||
Api.ExecutionSettings executionSettings;
|
||||
try
|
||||
{
|
||||
executionSettings = m_SettingsBuilder.BuildApiExecutionSettings(commandLineArgs);
|
||||
if (executionSettings.targetPlatform.HasValue)
|
||||
RemotePlayerLogController.instance.SetBuildTarget(executionSettings.targetPlatform.Value);
|
||||
}
|
||||
catch (SetupException exception)
|
||||
{
|
||||
HandleSetupException(exception);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// It is important that the message starts with "Running tests for ", otherwise TestCleanConsole will fail.
|
||||
m_LogMessage($"Running tests for {executionSettings}");
|
||||
return m_TestRunnerApi.Execute(executionSettings);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
m_LogException(exception);
|
||||
ExitApplication(ReturnCodes.RunError, "Exception when starting test run.");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExitIfRunIsCompleted()
|
||||
{
|
||||
if (m_IsRunActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var runState = runData.RunState;
|
||||
var returnCode = s_StateReturnCodes[runState];
|
||||
var reason = s_StateMessages[runState] ?? runData.RunErrorMessage;
|
||||
ExitApplication(returnCode, reason);
|
||||
}
|
||||
|
||||
private void ExitApplication(ReturnCodes returnCode, string reason)
|
||||
{
|
||||
var returnCodeInt = (int)returnCode;
|
||||
|
||||
m_LogMessage($"Test run completed. Exiting with code {returnCodeInt} ({returnCode}). {reason}");
|
||||
|
||||
m_ExitEditorApplication(returnCodeInt);
|
||||
}
|
||||
|
||||
public ExecutionSettings BuildExecutionSettings(string[] commandLineArgs)
|
||||
{
|
||||
return m_SettingsBuilder.BuildExecutionSettings(commandLineArgs);
|
||||
}
|
||||
|
||||
internal enum ReturnCodes
|
||||
{
|
||||
Ok = 0,
|
||||
Failed = 2,
|
||||
RunError = 3,
|
||||
PlatformNotFoundReturnCode = 4
|
||||
}
|
||||
|
||||
public void SetUpCallbacks(ExecutionSettings executionSettings)
|
||||
{
|
||||
RemotePlayerLogController.instance.SetLogsDirectory(executionSettings.DeviceLogsDirectory);
|
||||
|
||||
var resultSavingCallback = ScriptableObject.CreateInstance<ResultsSavingCallbacks>();
|
||||
resultSavingCallback.m_ResultFilePath = executionSettings.TestResultsFile;
|
||||
|
||||
var logSavingCallback = ScriptableObject.CreateInstance<LogSavingCallbacks>();
|
||||
|
||||
TestRunnerApi.RegisterTestCallback(resultSavingCallback);
|
||||
TestRunnerApi.RegisterTestCallback(logSavingCallback);
|
||||
TestRunnerApi.RegisterTestCallback(new RunStateCallbacks());
|
||||
}
|
||||
|
||||
public void ExitOnCompileErrors()
|
||||
{
|
||||
if (m_ScriptCompilationFailedCheck())
|
||||
{
|
||||
var handling = s_ExceptionHandlingMapping.First(h => h.m_ExceptionType == SetupException.ExceptionType.ScriptCompilationFailed);
|
||||
m_LogErrorFormat(handling.m_Message, new object[0]);
|
||||
ExitApplication(handling.m_ReturnCode, handling.m_Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSetupException(SetupException exception)
|
||||
{
|
||||
ExceptionHandling handling = s_ExceptionHandlingMapping.FirstOrDefault(h => h.m_ExceptionType == exception.Type) ?? new ExceptionHandling(exception.Type, "Unknown command line test run error. " + exception.Type, ReturnCodes.RunError);
|
||||
m_LogErrorFormat(handling.m_Message, exception.Details);
|
||||
ExitApplication(handling.m_ReturnCode, handling.m_Message);
|
||||
}
|
||||
|
||||
private class ExceptionHandling
|
||||
{
|
||||
internal SetupException.ExceptionType m_ExceptionType;
|
||||
internal string m_Message;
|
||||
internal ReturnCodes m_ReturnCode;
|
||||
public ExceptionHandling(SetupException.ExceptionType exceptionType, string message, ReturnCodes returnCode)
|
||||
{
|
||||
m_ExceptionType = exceptionType;
|
||||
m_Message = message;
|
||||
m_ReturnCode = returnCode;
|
||||
}
|
||||
}
|
||||
|
||||
private static ExceptionHandling[] s_ExceptionHandlingMapping = {
|
||||
new ExceptionHandling(SetupException.ExceptionType.ScriptCompilationFailed, "Scripts had compilation errors.", ReturnCodes.RunError),
|
||||
new ExceptionHandling(SetupException.ExceptionType.PlatformNotFound, "Test platform not found ({0}).", ReturnCodes.PlatformNotFoundReturnCode),
|
||||
new ExceptionHandling(SetupException.ExceptionType.TestSettingsFileNotFound, "Test settings file not found at {0}.", ReturnCodes.RunError),
|
||||
new ExceptionHandling(SetupException.ExceptionType.OrderedTestListFileNotFound, "Ordered test list file not found at {0}.", ReturnCodes.RunError)
|
||||
};
|
||||
|
||||
private static IDictionary<TestRunState, string> s_StateMessages = new Dictionary<TestRunState, string>()
|
||||
{
|
||||
{TestRunState.NoCallbacksReceived, "No callbacks received."},
|
||||
{TestRunState.OneOrMoreTestsExecutedWithNoFailures, "Run completed."},
|
||||
{TestRunState.OneOrMoreTestsExecutedWithOneOrMoreFailed, "One or more tests failed."},
|
||||
{TestRunState.CompletedJobWithoutAnyTestsExecuted, "No tests were executed."},
|
||||
{TestRunState.RunError, null}
|
||||
};
|
||||
|
||||
private static IDictionary<TestRunState, ReturnCodes> s_StateReturnCodes = new Dictionary<TestRunState, ReturnCodes>()
|
||||
{
|
||||
{TestRunState.NoCallbacksReceived, ReturnCodes.RunError},
|
||||
{TestRunState.OneOrMoreTestsExecutedWithNoFailures, ReturnCodes.Ok},
|
||||
{TestRunState.OneOrMoreTestsExecutedWithOneOrMoreFailed, ReturnCodes.Failed},
|
||||
{TestRunState.CompletedJobWithoutAnyTestsExecuted, ReturnCodes.Ok},
|
||||
{TestRunState.RunError, ReturnCodes.RunError}
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 083c6a3a5426382449369ddc12b691d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
[Serializable]
|
||||
internal class ExecutionSettings
|
||||
{
|
||||
public string TestResultsFile;
|
||||
public string DeviceLogsDirectory;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3a75354f6ceac94ca15ca9d96593290
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,11 @@
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal interface IExecuter
|
||||
{
|
||||
string InitializeAndExecuteRun(string[] commandLineArgs);
|
||||
void ExitIfRunIsCompleted();
|
||||
ExecutionSettings BuildExecutionSettings(string[] commandLineArgs);
|
||||
void SetUpCallbacks(ExecutionSettings executionSettings);
|
||||
void ExitOnCompileErrors();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3297738ef11b478a8b7ee802953ae768
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,11 @@
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal interface IRunData
|
||||
{
|
||||
bool IsRunning { get; set; }
|
||||
ExecutionSettings ExecutionSettings { get; set; }
|
||||
string RunId { get; set; }
|
||||
TestRunState RunState { get; set; }
|
||||
string RunErrorMessage { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d56e34a052c646e39a3317c404303e5f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal interface ISettingsBuilder
|
||||
{
|
||||
Api.ExecutionSettings BuildApiExecutionSettings(string[] commandLineArgs);
|
||||
ExecutionSettings BuildExecutionSettings(string[] commandLineArgs);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a13cbeb2099aca47bb456f49845f86c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using UnityEditor.TestRunner.TestLaunchers;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
[Serializable]
|
||||
internal class LogSavingCallbacks : ScriptableObject, ICallbacks
|
||||
{
|
||||
public void RunStarted(ITestAdaptor testsToRun)
|
||||
{
|
||||
RemotePlayerLogController.instance.StartLogWriters();
|
||||
}
|
||||
|
||||
public virtual void RunFinished(ITestResultAdaptor testResults)
|
||||
{
|
||||
RemotePlayerLogController.instance.StopLogWriters();
|
||||
}
|
||||
|
||||
public void TestStarted(ITestAdaptor test)
|
||||
{
|
||||
}
|
||||
|
||||
public void TestFinished(ITestResultAdaptor result)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d20eedbe40f0ce41a4c4f633f225de8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor.DeploymentTargets;
|
||||
using UnityEditor.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal class LogWriter : IDisposable
|
||||
{
|
||||
private string m_LogsDirectory;
|
||||
private string m_DeviceID;
|
||||
private Dictionary<string, StreamWriter> m_LogStreams;
|
||||
private DeploymentTargetLogger m_Logger;
|
||||
|
||||
internal LogWriter(string logsDirectory, string deviceID, DeploymentTargetLogger logger)
|
||||
{
|
||||
m_LogStreams = new Dictionary<string, StreamWriter>();
|
||||
m_Logger = logger;
|
||||
m_LogsDirectory = logsDirectory;
|
||||
m_DeviceID = deviceID;
|
||||
|
||||
logger.logMessage += WriteLogToFile;
|
||||
}
|
||||
|
||||
private void WriteLogToFile(string id, string logLine)
|
||||
{
|
||||
StreamWriter logStream;
|
||||
var streamExists = m_LogStreams.TryGetValue(id, out logStream);
|
||||
if (!streamExists)
|
||||
{
|
||||
var filePath = GetLogFilePath(m_LogsDirectory, m_DeviceID, id);
|
||||
logStream = CreateLogFile(filePath);
|
||||
|
||||
m_LogStreams.Add(id, logStream);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (logLine != null)
|
||||
logStream.WriteLine(logLine);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Writing {id} log failed.");
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
m_Logger.Stop();
|
||||
foreach (var logStream in m_LogStreams)
|
||||
{
|
||||
logStream.Value.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
private StreamWriter CreateLogFile(string path)
|
||||
{
|
||||
Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, "Creating {0} device log: {1}", m_DeviceID, path);
|
||||
StreamWriter streamWriter = null;
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
streamWriter = File.CreateText(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Creating device log {path} file failed.");
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
|
||||
return streamWriter;
|
||||
}
|
||||
|
||||
private string GetLogFilePath(string lgosDirectory, string deviceID, string logID)
|
||||
{
|
||||
var fileName = "Device-" + deviceID + "-" + logID + ".txt";
|
||||
fileName = string.Join("_", fileName.Split(Path.GetInvalidFileNameChars()));
|
||||
return Paths.Combine(lgosDirectory, fileName);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05778dd1de4433d418793b6f3d3c18cf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEditor.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
[Serializable]
|
||||
internal class ResultsSavingCallbacks : ScriptableObject, ICallbacks
|
||||
{
|
||||
[SerializeField]
|
||||
public string m_ResultFilePath;
|
||||
|
||||
public ResultsSavingCallbacks()
|
||||
{
|
||||
m_ResultFilePath = GetDefaultResultFilePath();
|
||||
}
|
||||
|
||||
public void RunStarted(ITestAdaptor testsToRun)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void RunFinished(ITestResultAdaptor testResults)
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_ResultFilePath))
|
||||
{
|
||||
m_ResultFilePath = GetDefaultResultFilePath();
|
||||
}
|
||||
|
||||
TestRunnerApi.SaveResultToFile(testResults, m_ResultFilePath);
|
||||
}
|
||||
|
||||
public void TestStarted(ITestAdaptor test)
|
||||
{
|
||||
}
|
||||
|
||||
public void TestFinished(ITestResultAdaptor result)
|
||||
{
|
||||
}
|
||||
|
||||
private static string GetDefaultResultFilePath()
|
||||
{
|
||||
var fileName = "TestResults-" + DateTime.Now.Ticks + ".xml";
|
||||
var projectPath = Directory.GetCurrentDirectory();
|
||||
return Paths.Combine(projectPath, fileName);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef563c5a6ecf64d4193dc144cb7d472a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal class RunData : ScriptableSingleton<RunData>, IRunData
|
||||
{
|
||||
private bool isRunning;
|
||||
private ExecutionSettings executionSettings;
|
||||
private string runId;
|
||||
private TestRunState runState;
|
||||
private string runErrorMessage;
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
get { return isRunning; }
|
||||
set { isRunning = value; }
|
||||
}
|
||||
|
||||
public ExecutionSettings ExecutionSettings
|
||||
{
|
||||
get { return executionSettings; }
|
||||
set { executionSettings = value; }
|
||||
}
|
||||
|
||||
public string RunId
|
||||
{
|
||||
get { return runId; }
|
||||
set { runId = value; }
|
||||
}
|
||||
|
||||
public TestRunState RunState
|
||||
{
|
||||
get { return runState; }
|
||||
set { runState = value; }
|
||||
}
|
||||
|
||||
public string RunErrorMessage
|
||||
{
|
||||
get { return runErrorMessage; }
|
||||
set { runErrorMessage = value; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f8c1075884df0249b80e23a0598f9c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal class RunSettings : ITestRunSettings
|
||||
{
|
||||
private ITestSettings m_TestSettings;
|
||||
public RunSettings(ITestSettings testSettings)
|
||||
{
|
||||
m_TestSettings = testSettings;
|
||||
}
|
||||
|
||||
public void Apply()
|
||||
{
|
||||
if (m_TestSettings != null)
|
||||
{
|
||||
m_TestSettings.SetupProjectParameters();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_TestSettings != null)
|
||||
{
|
||||
m_TestSettings.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59d3f5586b341a74c84c8f72144a4568
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal class RunStateCallbacks : IErrorCallbacks
|
||||
{
|
||||
internal IRunData runData = RunData.instance;
|
||||
internal static bool preventExit;
|
||||
|
||||
public void RunFinished(ITestResultAdaptor testResults)
|
||||
{
|
||||
if (preventExit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (runData.RunState == TestRunState.NoCallbacksReceived)
|
||||
{
|
||||
runData.RunState = TestRunState.CompletedJobWithoutAnyTestsExecuted;
|
||||
}
|
||||
}
|
||||
|
||||
public void TestStarted(ITestAdaptor test)
|
||||
{
|
||||
if (!test.IsSuite && runData.RunState == TestRunState.NoCallbacksReceived)
|
||||
{
|
||||
runData.RunState = TestRunState.OneOrMoreTestsExecutedWithNoFailures;
|
||||
}
|
||||
}
|
||||
|
||||
public void TestFinished(ITestResultAdaptor result)
|
||||
{
|
||||
if (!result.Test.IsSuite && (result.TestStatus == TestStatus.Failed || result.TestStatus == TestStatus.Inconclusive))
|
||||
{
|
||||
runData.RunState = TestRunState.OneOrMoreTestsExecutedWithOneOrMoreFailed;
|
||||
}
|
||||
}
|
||||
|
||||
public void RunStarted(ITestAdaptor testsToRun)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnError(string message)
|
||||
{
|
||||
runData.RunState = TestRunState.RunError;
|
||||
runData.RunErrorMessage = message;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43db38ca7188900429bf8be95ebbe197
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor.TestRunner.CommandLineParser;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal class SettingsBuilder : ISettingsBuilder
|
||||
{
|
||||
private ITestSettingsDeserializer m_TestSettingsDeserializer;
|
||||
private Action<string> m_LogAction;
|
||||
private Action<string> m_LogWarningAction;
|
||||
internal Func<string, bool> fileExistsCheck = File.Exists;
|
||||
private Func<bool> m_ScriptCompilationFailedCheck;
|
||||
internal Func<string, string[]> readAllLines = filePath => File.ReadAllText(filePath).Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
public SettingsBuilder(ITestSettingsDeserializer testSettingsDeserializer, Action<string> logAction, Action<string> logWarningAction, Func<bool> scriptCompilationFailedCheck)
|
||||
{
|
||||
m_LogAction = logAction;
|
||||
m_LogWarningAction = logWarningAction;
|
||||
m_ScriptCompilationFailedCheck = scriptCompilationFailedCheck;
|
||||
m_TestSettingsDeserializer = testSettingsDeserializer;
|
||||
}
|
||||
|
||||
public Api.ExecutionSettings BuildApiExecutionSettings(string[] commandLineArgs)
|
||||
{
|
||||
var quit = false;
|
||||
string testPlatform = TestMode.EditMode.ToString();
|
||||
string[] testFilters = null;
|
||||
string[] testCategories = null;
|
||||
string testSettingsFilePath = null;
|
||||
int? playerHeartbeatTimeout = null;
|
||||
bool runSynchronously = false;
|
||||
string[] testAssemblyNames = null;
|
||||
string buildPlayerPath = string.Empty;
|
||||
string orderedTestListFilePath = null;
|
||||
int retry = 0;
|
||||
int repeat = 0;
|
||||
int randomOrderSeed = 0;
|
||||
|
||||
|
||||
var optionSet = new CommandLineOptionSet(
|
||||
new CommandLineOption("quit", () => { quit = true; }),
|
||||
new CommandLineOption("testPlatform", platform => { testPlatform = platform; }),
|
||||
new CommandLineOption("editorTestsFilter", filters => { testFilters = filters; }),
|
||||
new CommandLineOption("testFilter", filters => { testFilters = filters; }),
|
||||
new CommandLineOption("editorTestsCategories", catagories => { testCategories = catagories; }),
|
||||
new CommandLineOption("testCategory", catagories => { testCategories = catagories; }),
|
||||
new CommandLineOption("testSettingsFile", settingsFilePath => { testSettingsFilePath = settingsFilePath; }),
|
||||
new CommandLineOption("playerHeartbeatTimeout", timeout => { playerHeartbeatTimeout = int.Parse(timeout); }),
|
||||
new CommandLineOption("runSynchronously", () => { runSynchronously = true; }),
|
||||
new CommandLineOption("assemblyNames", assemblyNames => { testAssemblyNames = assemblyNames; }),
|
||||
new CommandLineOption("buildPlayerPath", buildPath => { buildPlayerPath = buildPath; }),
|
||||
new CommandLineOption("orderedTestListFile", filePath => { orderedTestListFilePath = filePath; }),
|
||||
new CommandLineOption("randomOrderSeed", seed => { randomOrderSeed = int.Parse(seed);}),
|
||||
new CommandLineOption("retry", n => { retry = int.Parse(n); }),
|
||||
new CommandLineOption("repeat", n => { repeat = int.Parse(n); })
|
||||
);
|
||||
optionSet.Parse(commandLineArgs);
|
||||
|
||||
DisplayQuitWarningIfQuitIsGiven(quit);
|
||||
|
||||
CheckForScriptCompilationErrors();
|
||||
|
||||
var testSettings = GetTestSettings(testSettingsFilePath);
|
||||
var filter = new Filter
|
||||
{
|
||||
testMode = testPlatform.ToLower() == "editmode" ? TestMode.EditMode : TestMode.PlayMode,
|
||||
groupNames = testFilters,
|
||||
categoryNames = testCategories,
|
||||
assemblyNames = testAssemblyNames
|
||||
};
|
||||
|
||||
var settings = new Api.ExecutionSettings
|
||||
{
|
||||
filters = new []{ filter },
|
||||
overloadTestRunSettings = new RunSettings(testSettings),
|
||||
ignoreTests = testSettings?.ignoreTests,
|
||||
featureFlags = testSettings?.featureFlags,
|
||||
targetPlatform = GetBuildTarget(testPlatform),
|
||||
runSynchronously = runSynchronously,
|
||||
playerSavePath = buildPlayerPath,
|
||||
orderedTestNames = GetOrderedTestList(orderedTestListFilePath),
|
||||
repeatCount = repeat,
|
||||
retryCount = retry,
|
||||
randomOrderSeed = randomOrderSeed
|
||||
};
|
||||
|
||||
if (playerHeartbeatTimeout != null)
|
||||
{
|
||||
settings.playerHeartbeatTimeout = playerHeartbeatTimeout.Value;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
public ExecutionSettings BuildExecutionSettings(string[] commandLineArgs)
|
||||
{
|
||||
string resultFilePath = null;
|
||||
string deviceLogsDirectory = null;
|
||||
|
||||
var optionSet = new CommandLineOptionSet(
|
||||
new CommandLineOption("editorTestsResultFile", filePath => { resultFilePath = filePath; }),
|
||||
new CommandLineOption("testResults", filePath => { resultFilePath = filePath; }),
|
||||
new CommandLineOption("deviceLogs", dirPath => { deviceLogsDirectory = dirPath; })
|
||||
);
|
||||
optionSet.Parse(commandLineArgs);
|
||||
|
||||
return new ExecutionSettings
|
||||
{
|
||||
TestResultsFile = resultFilePath,
|
||||
DeviceLogsDirectory = deviceLogsDirectory
|
||||
};
|
||||
}
|
||||
|
||||
private void DisplayQuitWarningIfQuitIsGiven(bool quitIsGiven)
|
||||
{
|
||||
if (quitIsGiven)
|
||||
{
|
||||
m_LogWarningAction("Running tests from command line arguments will not work when \"quit\" is specified.");
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckForScriptCompilationErrors()
|
||||
{
|
||||
if (m_ScriptCompilationFailedCheck())
|
||||
{
|
||||
throw new SetupException(SetupException.ExceptionType.ScriptCompilationFailed);
|
||||
}
|
||||
}
|
||||
|
||||
private ITestSettings GetTestSettings(string testSettingsFilePath)
|
||||
{
|
||||
ITestSettings testSettings = null;
|
||||
if (!string.IsNullOrEmpty(testSettingsFilePath))
|
||||
{
|
||||
if (!fileExistsCheck(testSettingsFilePath))
|
||||
{
|
||||
throw new SetupException(SetupException.ExceptionType.TestSettingsFileNotFound, testSettingsFilePath);
|
||||
}
|
||||
|
||||
testSettings = m_TestSettingsDeserializer.GetSettingsFromJsonFile(testSettingsFilePath);
|
||||
}
|
||||
return testSettings;
|
||||
}
|
||||
|
||||
private string[] GetOrderedTestList(string orderedTestListFilePath)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(orderedTestListFilePath))
|
||||
{
|
||||
if (!fileExistsCheck(orderedTestListFilePath))
|
||||
{
|
||||
throw new SetupException(SetupException.ExceptionType.OrderedTestListFileNotFound, orderedTestListFilePath);
|
||||
}
|
||||
|
||||
return readAllLines(orderedTestListFilePath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static BuildTarget? GetBuildTarget(string testPlatform)
|
||||
{
|
||||
var testPlatformLower = testPlatform.ToLower();
|
||||
if (testPlatformLower == "editmode" || testPlatformLower == "playmode" || testPlatformLower == "editor" ||
|
||||
string.IsNullOrEmpty(testPlatformLower))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return (BuildTarget)Enum.Parse(typeof(BuildTarget), testPlatform, true);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
throw new SetupException(SetupException.ExceptionType.PlatformNotFound, testPlatform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7468a027a77337478e133b40b42b4f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal class SetupException : Exception
|
||||
{
|
||||
public ExceptionType Type { get; }
|
||||
public object[] Details { get; }
|
||||
|
||||
public SetupException(ExceptionType type, params object[] details)
|
||||
{
|
||||
Type = type;
|
||||
Details = details;
|
||||
}
|
||||
|
||||
public enum ExceptionType
|
||||
{
|
||||
ScriptCompilationFailed,
|
||||
PlatformNotFound,
|
||||
TestSettingsFileNotFound,
|
||||
OrderedTestListFileNotFound,
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63572993f2104574099a48392460b211
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using UnityEditor.TestRunner.CommandLineParser;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal class TestStarter
|
||||
{
|
||||
[InitializeOnLoadMethod]
|
||||
internal static void Initialize()
|
||||
{
|
||||
new TestStarter().Init();
|
||||
}
|
||||
|
||||
internal Action<EditorApplication.CallbackFunction> registerEditorUpdateCallback = action =>
|
||||
{
|
||||
EditorApplication.update += action;
|
||||
};
|
||||
internal Action<EditorApplication.CallbackFunction> unregisterEditorUpdateCallback = action =>
|
||||
{
|
||||
EditorApplication.update -= action;
|
||||
};
|
||||
internal Func<bool> isCompiling = () => EditorApplication.isCompiling;
|
||||
internal IRunData runData = RunData.instance;
|
||||
internal Func<string[]> GetCommandLineArgs = Environment.GetCommandLineArgs;
|
||||
|
||||
internal void Init()
|
||||
{
|
||||
if (!ShouldRunTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCompiling())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
executer.ExitOnCompileErrors();
|
||||
|
||||
if (runData.IsRunning)
|
||||
{
|
||||
executer.SetUpCallbacks(runData.ExecutionSettings);
|
||||
registerEditorUpdateCallback(executer.ExitIfRunIsCompleted);
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute the test run on the next editor update to allow other framework components
|
||||
// (the TestJobDataHolder.ResumeRunningJobs method in particular) to register themselves
|
||||
// or modify the test run environment using InitializeOnLoad and InitializeOnLoadMethod calls
|
||||
registerEditorUpdateCallback(InitializeAndExecuteRun);
|
||||
}
|
||||
|
||||
internal void InitializeAndExecuteRun()
|
||||
{
|
||||
unregisterEditorUpdateCallback(InitializeAndExecuteRun);
|
||||
|
||||
runData.IsRunning = true;
|
||||
var commandLineArgs = GetCommandLineArgs();
|
||||
runData.ExecutionSettings = executer.BuildExecutionSettings(commandLineArgs);
|
||||
executer.SetUpCallbacks(runData.ExecutionSettings);
|
||||
runData.RunState = default;
|
||||
runData.RunId = executer.InitializeAndExecuteRun(commandLineArgs);
|
||||
registerEditorUpdateCallback(executer.ExitIfRunIsCompleted);
|
||||
}
|
||||
|
||||
private bool ShouldRunTests()
|
||||
{
|
||||
var shouldRunTests = false;
|
||||
var optionSet = new CommandLineOptionSet(
|
||||
new CommandLineOption("runTests", () => { shouldRunTests = true; }),
|
||||
new CommandLineOption("runEditorTests", () => { shouldRunTests = true; })
|
||||
);
|
||||
optionSet.Parse(GetCommandLineArgs());
|
||||
return shouldRunTests;
|
||||
}
|
||||
|
||||
internal IExecuter m_Executer;
|
||||
private IExecuter executer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Executer == null)
|
||||
{
|
||||
Func<bool> compilationCheck = () => EditorUtility.scriptCompilationFailed;
|
||||
Action<string> actionLogger = msg => { Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, msg); };
|
||||
var apiSettingsBuilder = new SettingsBuilder(new TestSettingsDeserializer(() => new TestSettings()), actionLogger, Debug.LogWarning, compilationCheck);
|
||||
m_Executer = new Executer(ScriptableObject.CreateInstance<TestRunnerApi>(), apiSettingsBuilder, Debug.LogErrorFormat, Debug.LogException, Debug.Log, EditorApplication.Exit, compilationCheck, TestRunnerApi.IsRunActive);
|
||||
}
|
||||
|
||||
return m_Executer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d616d1a494edd144b262cf6cd5e5fda
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,26 @@
|
||||
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
|
||||
{
|
||||
internal enum TestRunState
|
||||
{
|
||||
/// <summary>
|
||||
/// When the test run has started, but no callbacks from the test runner api have yet been received.
|
||||
/// </summary>
|
||||
NoCallbacksReceived,
|
||||
/// <summary>
|
||||
/// When at least one test started event have been fired for a test node.
|
||||
/// </summary>
|
||||
OneOrMoreTestsExecutedWithNoFailures,
|
||||
/// <summary>
|
||||
/// When at least one test finished event have been fired for a test node and the status is failed.
|
||||
/// </summary>
|
||||
OneOrMoreTestsExecutedWithOneOrMoreFailed,
|
||||
/// <summary>
|
||||
/// When the test job in the test runner api have completed, but no test started events for test nodes has happened. E.g. if there are no valid tests in the project.
|
||||
/// </summary>
|
||||
CompletedJobWithoutAnyTestsExecuted,
|
||||
/// <summary>
|
||||
/// When the test runner api has raised an error during the run.
|
||||
/// </summary>
|
||||
RunError
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 317f06562c344e22991ba4117cf7b71c
|
||||
timeCreated: 1582809279
|
Reference in New Issue
Block a user