119 lines
4.5 KiB
C#
119 lines
4.5 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using MCPForUnity.Editor.Helpers;
|
|
using MCPForUnity.Editor.Resources.Tests;
|
|
using MCPForUnity.Editor.Services;
|
|
using Newtonsoft.Json.Linq;
|
|
using UnityEditor.TestTools.TestRunner.Api;
|
|
|
|
namespace MCPForUnity.Editor.Tools
|
|
{
|
|
/// <summary>
|
|
/// Starts a Unity Test Runner run asynchronously and returns a job id immediately.
|
|
/// Use get_test_job(job_id) to poll status/results.
|
|
/// </summary>
|
|
[McpForUnityTool("run_tests", AutoRegister = false)]
|
|
public static class RunTests
|
|
{
|
|
public static Task<object> HandleCommand(JObject @params)
|
|
{
|
|
try
|
|
{
|
|
// Check for clear_stuck action first
|
|
if (ParamCoercion.CoerceBool(@params?["clear_stuck"], false))
|
|
{
|
|
bool wasCleared = TestJobManager.ClearStuckJob();
|
|
return Task.FromResult<object>(new SuccessResponse(
|
|
wasCleared ? "Stuck job cleared." : "No running job to clear.",
|
|
new { cleared = wasCleared }
|
|
));
|
|
}
|
|
|
|
string modeStr = @params?["mode"]?.ToString();
|
|
if (string.IsNullOrWhiteSpace(modeStr))
|
|
{
|
|
modeStr = "EditMode";
|
|
}
|
|
|
|
if (!ModeParser.TryParse(modeStr, out var parsedMode, out var parseError))
|
|
{
|
|
return Task.FromResult<object>(new ErrorResponse(parseError));
|
|
}
|
|
|
|
bool includeDetails = ParamCoercion.CoerceBool(@params?["includeDetails"], false);
|
|
bool includeFailedTests = ParamCoercion.CoerceBool(@params?["includeFailedTests"], false);
|
|
|
|
var filterOptions = GetFilterOptions(@params);
|
|
string jobId = TestJobManager.StartJob(parsedMode.Value, filterOptions);
|
|
|
|
return Task.FromResult<object>(new SuccessResponse("Test job started.", new
|
|
{
|
|
job_id = jobId,
|
|
status = "running",
|
|
mode = parsedMode.Value.ToString(),
|
|
include_details = includeDetails,
|
|
include_failed_tests = includeFailedTests
|
|
}));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Normalize the already-running case to a stable error token.
|
|
if (ex.Message != null && ex.Message.IndexOf("already in progress", StringComparison.OrdinalIgnoreCase) >= 0)
|
|
{
|
|
return Task.FromResult<object>(new ErrorResponse("tests_running", new { reason = "tests_running", retry_after_ms = 5000 }));
|
|
}
|
|
return Task.FromResult<object>(new ErrorResponse($"Failed to start test job: {ex.Message}"));
|
|
}
|
|
}
|
|
|
|
private static TestFilterOptions GetFilterOptions(JObject @params)
|
|
{
|
|
if (@params == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
string[] ParseStringArray(string key)
|
|
{
|
|
var token = @params[key];
|
|
if (token == null) return null;
|
|
if (token.Type == JTokenType.String)
|
|
{
|
|
var value = token.ToString();
|
|
return string.IsNullOrWhiteSpace(value) ? null : new[] { value };
|
|
}
|
|
if (token.Type == JTokenType.Array)
|
|
{
|
|
var array = token as JArray;
|
|
if (array == null || array.Count == 0) return null;
|
|
var values = array
|
|
.Values<string>()
|
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
|
.ToArray();
|
|
return values.Length > 0 ? values : null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
var testNames = ParseStringArray("testNames");
|
|
var groupNames = ParseStringArray("groupNames");
|
|
var categoryNames = ParseStringArray("categoryNames");
|
|
var assemblyNames = ParseStringArray("assemblyNames");
|
|
|
|
if (testNames == null && groupNames == null && categoryNames == null && assemblyNames == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new TestFilterOptions
|
|
{
|
|
TestNames = testNames,
|
|
GroupNames = groupNames,
|
|
CategoryNames = categoryNames,
|
|
AssemblyNames = assemblyNames
|
|
};
|
|
}
|
|
}
|
|
}
|