| File: WorkflowScripts\LabelerPredictPullsWorkflowTests.cs | Web Access |
| Project: src\tests\Infrastructure.Tests\Infrastructure.Tests.csproj (Infrastructure.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; using Aspire.TestUtilities; using Xunit; namespace Infrastructure.Tests; /// <summary> /// Behavioral tests for .github/workflows/labeler-predict-pulls.js. /// </summary> public sealed class LabelerPredictPullsWorkflowTests : IDisposable { private static readonly JsonSerializerOptions s_jsonOptions = new(JsonSerializerDefaults.Web); private readonly TemporaryWorkspace _workspace; private readonly string _repoRoot = RepoRoot.Path; private readonly string _harnessPath; private readonly ITestOutputHelper _output; public LabelerPredictPullsWorkflowTests(ITestOutputHelper output) { _output = output; _workspace = TemporaryWorkspace.Create(output); _harnessPath = Path.Combine( _repoRoot, "tests", "Infrastructure.Tests", "WorkflowScripts", "labeler-predict-pulls.harness.js"); } public void Dispose() => _workspace.Dispose(); [Theory] [InlineData("Copilot")] [InlineData("copilot[bot]")] [InlineData("copilot-swe-agent")] [InlineData("copilot-swe-agent[bot]")] [InlineData("github-copilot[bot]")] [RequiresTools(["node"])] public async Task UnassignedCopilotPullRequestGetsNeedsAssigneeLabel(string author) { var result = await RunScriptAsync(PullRequest(author)); Assert.Equal(["needs-assignee"], result.Labels); Assert.Equal(["pulls.get", "addLabels"], result.Calls); } [Fact] [RequiresTools(["node"])] public async Task AssignedCopilotPullRequestLosesNeedsAssigneeLabel() { var result = await RunScriptAsync( PullRequest( author: "Copilot", assignees: [new { login = "octocat", type = "User" }], labels: [new { name = "needs-assignee" }])); Assert.Empty(result.Labels); Assert.Equal(["pulls.get", "removeLabel"], result.Calls); } [Fact] [RequiresTools(["node"])] public async Task BotAssignedCopilotPullRequestGetsNeedsAssigneeLabel() { var result = await RunScriptAsync( PullRequest( author: "Copilot", assignees: [new { login = "dependabot[bot]", type = "Bot" }])); Assert.Equal(["needs-assignee"], result.Labels); Assert.Equal(["pulls.get", "addLabels"], result.Calls); } [Fact] [RequiresTools(["node"])] public async Task ConcurrentPullRequestLabelRemovalIsIdempotent() { var result = await RunScriptAsync( PullRequest( author: "Copilot", assignees: [new { login = "octocat", type = "User" }], labels: [new { name = "needs-assignee" }]), removeLabelNotFound: true); Assert.Empty(result.Labels); Assert.Equal(["pulls.get", "removeLabel"], result.Calls); } [Fact] [RequiresTools(["node"])] public async Task ClosedCopilotPullRequestLosesNeedsAssigneeLabel() { var result = await RunScriptAsync( PullRequest( author: "Copilot", state: "closed", labels: [new { name = "needs-assignee" }])); Assert.Empty(result.Labels); Assert.Equal(["pulls.get", "removeLabel"], result.Calls); } [Fact] [RequiresTools(["node"])] public async Task NonCopilotPullRequestIsUnchanged() { var result = await RunScriptAsync(PullRequest(author: "outside-contributor")); Assert.Empty(result.Labels); Assert.Equal(["pulls.get"], result.Calls); } private static object PullRequest( string author, string state = "open", object[]? assignees = null, object[]? labels = null) => new { user = new { login = author }, state, assignees = assignees ?? [], labels = labels ?? [], }; private async Task<ScriptResult> RunScriptAsync( object pullRequest, bool removeLabelNotFound = false) { var requestPath = Path.Combine(_workspace.Path, $"{Guid.NewGuid():N}.json"); var outputPath = Path.Combine(_workspace.Path, $"{Guid.NewGuid():N}.result.json"); await File.WriteAllTextAsync( requestPath, JsonSerializer.Serialize( new { pullRequest, removeLabelNotFound, }, s_jsonOptions)); using var command = new NodeCommand(_output, "labeler-predict-pulls"); command.WithWorkingDirectory(_repoRoot); var result = await command.ExecuteScriptAsync(_harnessPath, requestPath, outputPath); Assert.Equal(0, result.ExitCode); var response = JsonSerializer.Deserialize<HarnessResponse>( await File.ReadAllTextAsync(outputPath), s_jsonOptions); Assert.NotNull(response); return response.Result; } private sealed record HarnessResponse(ScriptResult Result); private sealed record ScriptResult(string[] Labels, string[] Calls); }