From 3ed80b7c10336b4fff5c7c38fc0ec00814a6c3c7 Mon Sep 17 00:00:00 2001 From: Tingluo Huang Date: Mon, 9 Dec 2019 16:11:00 -0500 Subject: [PATCH] Fix L0 tests, add/update runner release yaml. (#214) --- .github/workflows/release.yml | 184 +++++ azure-pipelines-release.yml | 22 +- src/Runner.Common/Tracing.cs | 7 + src/Runner.Worker/DiagnosticLogManager.cs | 12 +- src/Runner.Worker/JobExtension.cs | 20 +- src/Runner.Worker/JobRunner.cs | 2 +- src/Test/L0/ProcessInvokerL0.cs | 88 +- src/Test/L0/Worker/ActionManagerL0.cs | 368 ++------- src/Test/L0/Worker/JobExtensionL0.cs | 597 ++++++------- src/Test/L0/Worker/JobRunnerL0.cs | 59 -- src/Test/L0/Worker/StepsRunnerL0.cs | 827 +++++++++---------- src/Test/L0/Worker/TaskCommandExtensionL0.cs | 181 ---- 12 files changed, 995 insertions(+), 1372 deletions(-) create mode 100644 .github/workflows/release.yml delete mode 100644 src/Test/L0/Worker/TaskCommandExtensionL0.cs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..f4912f09a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,184 @@ +name: Runner CD + +on: + push: + paths: + - src/runnerversion_block # Change this to src/runnerversion when we are ready. + +jobs: + build: + strategy: + matrix: + runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ] + include: + - runtime: linux-x64 + os: ubuntu-latest + devScript: ./dev.sh + + - runtime: linux-arm64 + os: ubuntu-latest + devScript: ./dev.sh + + - runtime: linux-arm + os: ubuntu-latest + devScript: ./dev.sh + + - runtime: osx-x64 + os: macOS-latest + devScript: ./dev.sh + + - runtime: win-x64 + os: windows-latest + devScript: ./dev + + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v1 + + # Build runner layout + - name: Build & Layout Release + run: | + ${{ matrix.devScript }} layout Release ${{ matrix.runtime }} + working-directory: src + + # Run tests + - name: L0 + run: | + ${{ matrix.devScript }} test + working-directory: src + if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm' + + # Create runner package tar.gz/zip + - name: Package Release + if: github.event_name != 'pull_request' + run: | + ${{ matrix.devScript }} package Release + working-directory: src + + # Upload runner package tar.gz/zip as artifact. + # Since each package name is unique, so we don't need to put ${{matrix}} info into artifact name + - name: Publish Artifact + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v1 + with: + name: runner-packages + path: _package + + release: + needs: build + runs-on: linux-latest + steps: + + # Download runner package tar.gz/zip produced by 'build' job + - name: Download Artifact + uses: actions/download-artifact@v1 + with: + name: runner-packages + + # Create ReleaseNote file + - name: Create ReleaseNote + id: releaseNote + uses: actions/github-script@0.3.0 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const fs = require('fs'); + // Get runner version from ./src/runnerVersion file + const versionContent = await github.repos.getContents({ + owner: '${{ github.event.repository.owner.name }}', + repo: '${{ github.event.repository.name }}', + path: 'src/runnerversion' + ref: ${{ github.sha }} + }) + const runnerVersion = Buffer.from(versionContent.data.content, 'base64').toString() + console.log("Runner Version ' + runnerVersion) + core.setOutput('version', runnerVersion); + + // Query GitHub release ensure version is bumped + const latestRelease = await github.repos.getLatestRelease({ + owner: '${{ github.event.repository.owner.name }}', + repo: '${{ github.event.repository.name }}' + }) + console.log(latestRelease.name) + const latestReleaseVersion = latestRelease.name.substring(1) + const vLatest = latestReleaseVersion.split('.') + const vNew = runnerVersion.split('.') + let versionBumped = true + for (let i = 0; i < 3; ++i) { + var v1 = parseInt(vLatest[i], 10); + var v2 = parseInt(vNew[i], 10); + if (v2 > v1) { + console.log(runnerVersion + " > " + latestReleaseVersion + "(Latest)") + break + } + + if (v1 > v2) { + versionBumped = false + core.setFailed(runnerVersion + " < " + latestReleaseVersion + "(Latest)") + break + } + } + + // Generate release note + if (versionBumped) { + const releaseNoteContent = await github.repos.getContents({ + owner: '${{ github.event.repository.owner.name }}', + repo: '${{ github.event.repository.name }}', + path: 'releaseNote.md' + ref: ${{ github.sha }} + }) + const releaseNote = Buffer.from(releaseNoteContent.data.content, 'base64').toString().replace("", runnerVersion) + console.log(releaseNote) + core.setOutput('note', releaseNote); + } + + # Create GitHub release + - uses: actions/create-release@v1 + id: createRelease + name: Create ${{ steps.releaseNote.outputs.version }} Runner Release + with: + tag_name: "v${{ steps.releaseNote.outputs.version }}" + release_name: "v${{ steps.releaseNote.outputs.version }}" + body: ${{ steps.releaseNote.outputs.note }} + prerelease: true + + # Upload release assets + - name: Upload Release Asset (win-x64) + uses: actions/upload-release-asset@v1.0.1 + with: + upload_url: ${{ steps.createRelease.outputs.upload_url }} + asset_path: ./actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip + asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip + asset_content_type: application/octet-stream + + - name: Upload Release Asset (linux-x64) + uses: actions/upload-release-asset@v1.0.1 + with: + upload_url: ${{ steps.createRelease.outputs.upload_url }} + asset_path: ./actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.zip + asset_name: actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.zip + asset_content_type: application/octet-stream + + - name: Upload Release Asset (mac-x64) + uses: actions/upload-release-asset@v1.0.1 + with: + upload_url: ${{ steps.createRelease.outputs.upload_url }} + asset_path: ./actions-runner-mac-x64-${{ steps.releaseNote.outputs.version }}.zip + asset_name: actions-runner-mac-x64-${{ steps.releaseNote.outputs.version }}.zip + asset_content_type: application/octet-stream + + - name: Upload Release Asset (linux-arm) + uses: actions/upload-release-asset@v1.0.1 + with: + upload_url: ${{ steps.createRelease.outputs.upload_url }} + asset_path: ./actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}.zip + asset_name: actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}.zip + asset_content_type: application/octet-stream + + - name: Upload Release Asset (linux-arm64) + uses: actions/upload-release-asset@v1.0.1 + with: + upload_url: ${{ steps.createRelease.outputs.upload_url }} + asset_path: ./actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.zip + asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.zip + asset_content_type: application/octet-stream \ No newline at end of file diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 7e3f06b59..12c181481 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -221,15 +221,17 @@ stages: $releaseCreated = Invoke-RestMethod @releaseParams Write-Host $releaseCreated $releaseId = $releaseCreated.id - $assets = [System.IO.File]::ReadAllText("$(Build.SourcesDirectory)\assets.json").Replace("","$(ReleaseAgentVersion)") - $assetsParams = @{ - Uri = "https://uploads.github.com/repos/actions/runner/releases/$releaseId/assets?name=assets.json" - Method = 'POST'; - Headers = @{ - Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("github:$(GithubToken)")); - } - ContentType = 'application/octet-stream'; - Body = [system.Text.Encoding]::UTF8.GetBytes($assets) + Get-ChildItem -LiteralPath "$(System.ArtifactsDirectory)/runners" | ForEach-Object { + Write-Host "Uploading $_ as GitHub release assets" + $assetsParams = @{ + Uri = "https://uploads.github.com/repos/actions/runner/releases/$releaseId/assets?name=$($_.Name)" + Method = 'POST'; + Headers = @{ + Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("github:$(GithubToken)")); + } + ContentType = 'application/octet-stream'; + Body = [System.IO.File]::ReadAllBytes($_.FullName) + } + Invoke-RestMethod @assetsParams } - Invoke-RestMethod @assetsParams displayName: Create agent release on Github diff --git a/src/Runner.Common/Tracing.cs b/src/Runner.Common/Tracing.cs index 713ed1dc0..b72070103 100644 --- a/src/Runner.Common/Tracing.cs +++ b/src/Runner.Common/Tracing.cs @@ -50,6 +50,13 @@ namespace GitHub.Runner.Common public void Error(Exception exception) { Trace(TraceEventType.Error, exception.ToString()); + var innerEx = exception.InnerException; + while (innerEx != null) + { + Trace(TraceEventType.Error, "#####################################################"); + Trace(TraceEventType.Error, innerEx.ToString()); + innerEx = innerEx.InnerException; + } } // Do not remove the non-format overload. diff --git a/src/Runner.Worker/DiagnosticLogManager.cs b/src/Runner.Worker/DiagnosticLogManager.cs index 809cecdee..45443f856 100644 --- a/src/Runner.Worker/DiagnosticLogManager.cs +++ b/src/Runner.Worker/DiagnosticLogManager.cs @@ -15,7 +15,7 @@ namespace GitHub.Runner.Worker [ServiceLocator(Default = typeof(DiagnosticLogManager))] public interface IDiagnosticLogManager : IRunnerService { - Task UploadDiagnosticLogsAsync(IExecutionContext executionContext, + void UploadDiagnosticLogs(IExecutionContext executionContext, IExecutionContext parentContext, Pipelines.AgentJobRequestMessage message, DateTime jobStartTimeUtc); @@ -31,12 +31,10 @@ namespace GitHub.Runner.Worker public sealed class DiagnosticLogManager : RunnerService, IDiagnosticLogManager { private static string DateTimeFormat = "yyyyMMdd-HHmmss"; -#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously (method has async logic on only certain platforms) - public async Task UploadDiagnosticLogsAsync(IExecutionContext executionContext, -#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - IExecutionContext parentContext, - Pipelines.AgentJobRequestMessage message, - DateTime jobStartTimeUtc) + public void UploadDiagnosticLogs(IExecutionContext executionContext, + IExecutionContext parentContext, + Pipelines.AgentJobRequestMessage message, + DateTime jobStartTimeUtc) { executionContext.Debug("Starting diagnostic file upload."); diff --git a/src/Runner.Worker/JobExtension.cs b/src/Runner.Worker/JobExtension.cs index 0dfeac736..11834b8f3 100644 --- a/src/Runner.Worker/JobExtension.cs +++ b/src/Runner.Worker/JobExtension.cs @@ -19,7 +19,7 @@ namespace GitHub.Runner.Worker public interface IJobExtension : IRunnerService { Task> InitializeJob(IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message); - Task FinalizeJob(IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message, DateTime jobStartTimeUtc); + void FinalizeJob(IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message, DateTime jobStartTimeUtc); } public sealed class JobExtension : RunnerService, IJobExtension @@ -42,7 +42,6 @@ namespace GitHub.Runner.Worker List preJobSteps = new List(); List jobSteps = new List(); - List postJobSteps = new List(); using (var register = jobContext.CancellationToken.Register(() => { context.CancelToken(); })) { try @@ -231,7 +230,7 @@ namespace GitHub.Runner.Worker } } - public async Task FinalizeJob(IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message, DateTime jobStartTimeUtc) + public void FinalizeJob(IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message, DateTime jobStartTimeUtc) { Trace.Entering(); ArgUtil.NotNull(jobContext, nameof(jobContext)); @@ -245,19 +244,6 @@ namespace GitHub.Runner.Worker context.Start(); context.Debug("Starting: Complete job"); - // Wait for agent log plugin process exits - // var logPlugin = HostContext.GetService(); - // try - // { - // await logPlugin.WaitAsync(context); - // } - // catch (Exception ex) - // { - // // Log and ignore the error from log plugin finalization. - // Trace.Error($"Caught exception from log plugin finalization: {ex}"); - // context.Output(ex.Message); - // } - if (context.Variables.GetBoolean(Constants.Variables.Actions.RunnerDebug) ?? false) { Trace.Info("Support log upload starting."); @@ -267,7 +253,7 @@ namespace GitHub.Runner.Worker try { - await diagnosticLogManager.UploadDiagnosticLogsAsync(executionContext: context, parentContext: jobContext, message: message, jobStartTimeUtc: jobStartTimeUtc); + diagnosticLogManager.UploadDiagnosticLogs(executionContext: context, parentContext: jobContext, message: message, jobStartTimeUtc: jobStartTimeUtc); Trace.Info("Support log upload complete."); context.Output("Completed runner diagnostic log upload"); diff --git a/src/Runner.Worker/JobRunner.cs b/src/Runner.Worker/JobRunner.cs index 632aa2484..3998232bb 100644 --- a/src/Runner.Worker/JobRunner.cs +++ b/src/Runner.Worker/JobRunner.cs @@ -179,7 +179,7 @@ namespace GitHub.Runner.Worker finally { Trace.Info("Finalize job."); - await jobExtension.FinalizeJob(jobContext, message, jobStartTimeUtc); + jobExtension.FinalizeJob(jobContext, message, jobStartTimeUtc); } Trace.Info($"Job result after all job steps finish: {jobContext.Result ?? TaskResult.Succeeded}"); diff --git a/src/Test/L0/ProcessInvokerL0.cs b/src/Test/L0/ProcessInvokerL0.cs index f986d6e50..735a35dc2 100644 --- a/src/Test/L0/ProcessInvokerL0.cs +++ b/src/Test/L0/ProcessInvokerL0.cs @@ -13,50 +13,50 @@ namespace GitHub.Runner.Common.Tests { public sealed class ProcessInvokerL0 { -// #if OS_WINDOWS -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Common")] -// public async Task DefaultsToCurrentSystemOemEncoding() -// { -// // This test verifies that the additional code pages encoding provider is registered. -// // By default, only Unicode encodings, ASCII, and code page 28591 are supported. An -// // additional provider must be registered to support the full set of encodings that -// // were included in Full .NET prior to 4.6. -// // -// // For example, on an en-US box, this is required for loading the encoding for the -// // default console output code page '437'. Without loading the correct encoding for -// // code page IBM437, some characters cannot be translated correctly, e.g. write 'ç' -// // from powershell.exe. -// using (TestHostContext hc = new TestHostContext(this)) -// { -// Tracing trace = hc.GetTrace(); -// var processInvoker = new ProcessInvokerWrapper(); -// processInvoker.Initialize(hc); -// var stdout = new List(); -// var stderr = new List(); -// processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => -// { -// stdout.Add(e.Data); -// }; -// processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => -// { -// stderr.Add(e.Data); -// }; -// await processInvoker.ExecuteAsync( -// workingDirectory: "", -// fileName: "powershell.exe", -// arguments: $@"-NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ""Write-Host 'From STDOUT ''ç''' ; Write-Error 'From STDERR ''ç'''""", -// environment: null, -// requireExitCodeZero: false, -// cancellationToken: CancellationToken.None); -// Assert.Equal(1, stdout.Count); -// Assert.Equal("From STDOUT 'ç'", stdout[0]); -// Assert.True(stderr.Count > 0); -// Assert.True(stderr[0].Contains("From STDERR 'ç'")); -// } -// } -// #endif +#if OS_WINDOWS + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public async Task DefaultsToCurrentSystemOemEncoding() + { + // This test verifies that the additional code pages encoding provider is registered. + // By default, only Unicode encodings, ASCII, and code page 28591 are supported. An + // additional provider must be registered to support the full set of encodings that + // were included in Full .NET prior to 4.6. + // + // For example, on an en-US box, this is required for loading the encoding for the + // default console output code page '437'. Without loading the correct encoding for + // code page IBM437, some characters cannot be translated correctly, e.g. write 'ç' + // from powershell.exe. + using (TestHostContext hc = new TestHostContext(this)) + { + Tracing trace = hc.GetTrace(); + var processInvoker = new ProcessInvokerWrapper(); + processInvoker.Initialize(hc); + var stdout = new List(); + var stderr = new List(); + processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => + { + stdout.Add(e.Data); + }; + processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => + { + stderr.Add(e.Data); + }; + await processInvoker.ExecuteAsync( + workingDirectory: "", + fileName: "powershell.exe", + arguments: $@"-NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ""Write-Host 'From STDOUT ''ç''' ; Write-Error 'From STDERR ''ç'''""", + environment: null, + requireExitCodeZero: false, + cancellationToken: CancellationToken.None); + Assert.Equal(1, stdout.Count); + Assert.Equal("From STDOUT 'ç'", stdout[0]); + Assert.True(stderr.Count > 0); + Assert.True(stderr[0].Contains("From STDERR 'ç'")); + } + } +#endif [Fact] [Trait("Level", "L0")] diff --git a/src/Test/L0/Worker/ActionManagerL0.cs b/src/Test/L0/Worker/ActionManagerL0.cs index 046b9c6bf..38bc0494c 100644 --- a/src/Test/L0/Worker/ActionManagerL0.cs +++ b/src/Test/L0/Worker/ActionManagerL0.cs @@ -29,130 +29,6 @@ namespace GitHub.Runner.Common.Tests.Worker private ActionManager _actionManager; private string _workFolder; - // //Test how exceptions are propagated to the caller. - // [Fact] - // [Trait("Level", "L0")] - // [Trait("Category", "Worker")] - // public async void RetryNetworkException() - // { - // try - // { - // // Arrange. - // Setup(); - // var pingTask = new Pipelines.TaskStep() - // { - // Enabled = true, - // Reference = new Pipelines.TaskStepDefinitionReference() - // { - // Name = "Ping", - // Version = "0.1.1", - // Id = Guid.NewGuid() - // } - // }; - - // var pingVersion = new TaskVersion(pingTask.Reference.Version); - // Exception expectedException = new System.Net.Http.HttpRequestException("simulated network error"); - // _taskServer - // .Setup(x => x.GetTaskContentZipAsync(It.IsAny(), It.IsAny(), It.IsAny())) - // .Returns((Guid taskId, TaskVersion taskVersion, CancellationToken token) => - // { - // throw expectedException; - // }); - - // var tasks = new List(new Pipelines.TaskStep[] { pingTask }); - - // //Act - // Exception actualException = null; - // try - // { - // await _actionManager.DownloadAsync(_ec.Object, tasks); - // } - // catch (Exception ex) - // { - // actualException = ex; - // } - - // //Assert - // //verify task completed in less than 2sec and it is in failed state state - // Assert.Equal(expectedException, actualException); - - // //assert download was invoked 3 times, because we retry on task download - // _taskServer - // .Verify(x => x.GetTaskContentZipAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(3)); - - // //see if the task.json was not downloaded - // Assert.Equal( - // 0, - // Directory.GetFiles(_hc.GetDirectory(WellKnownDirectory.Tasks), "*", SearchOption.AllDirectories).Length); - // } - // finally - // { - // Teardown(); - // } - // } - - // //Test how exceptions are propagated to the caller. - // [Fact] - // [Trait("Level", "L0")] - // [Trait("Category", "Worker")] - // public async void RetryStreamException() - // { - // try - // { - // // Arrange. - // Setup(); - // var pingTask = new Pipelines.TaskStep() - // { - // Enabled = true, - // Reference = new Pipelines.TaskStepDefinitionReference() - // { - // Name = "Ping", - // Version = "0.1.1", - // Id = Guid.NewGuid() - // } - // }; - - // var pingVersion = new TaskVersion(pingTask.Reference.Version); - // Exception expectedException = new System.Net.Http.HttpRequestException("simulated network error"); - // _taskServer - // .Setup(x => x.GetTaskContentZipAsync(It.IsAny(), It.IsAny(), It.IsAny())) - // .Returns((Guid taskId, TaskVersion taskVersion, CancellationToken token) => - // { - // return Task.FromResult(new ExceptionStream()); - // }); - - // var tasks = new List(new Pipelines.TaskStep[] { pingTask }); - - // //Act - // Exception actualException = null; - // try - // { - // await _actionManager.DownloadAsync(_ec.Object, tasks); - // } - // catch (Exception ex) - // { - // actualException = ex; - // } - - // //Assert - // //verify task completed in less than 2sec and it is in failed state state - // Assert.Equal("NotImplementedException", actualException.GetType().Name); - - // //assert download was invoked 3 times, because we retry on task download - // _taskServer - // .Verify(x => x.GetTaskContentZipAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(3)); - - // //see if the task.json was not downloaded - // Assert.Equal( - // 0, - // Directory.GetFiles(_hc.GetDirectory(WellKnownDirectory.Tasks), "*", SearchOption.AllDirectories).Length); - // } - // finally - // { - // Teardown(); - // } - // } - #if OS_LINUX [Fact] [Trait("Level", "L0")] @@ -233,31 +109,17 @@ namespace GitHub.Runner.Common.Tests.Worker } } -/* [Fact] [Trait("Level", "L0")] [Trait("Category", "Worker")] - public async void PrepareActions_SkipDownloadActionFromGraphWhenCache() + public async void PrepareActions_AlwaysClearActionsCache() { try { //Arrange Setup(); var actionId = Guid.NewGuid(); - var actions = new List - { - new Pipelines.ActionStep() - { - Name = "action", - Id = actionId, - Reference = new Pipelines.RepositoryPathReference() - { - Name = "notexist/no", - Ref = "notexist", - RepositoryType = "GitHub" - } - } - }; + var actions = new List(); var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "notexist/no", "notexist.completed"); Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); @@ -267,13 +129,15 @@ namespace GitHub.Runner.Common.Tests.Worker //Act await _actionManager.PrepareActionsAsync(_ec.Object, actions); + + // Make sure _actions folder get deleted + Assert.False(Directory.Exists(_hc.GetDirectory(WellKnownDirectory.Actions))); } finally { Teardown(); } } -*/ [Fact] [Trait("Level", "L0")] @@ -300,7 +164,9 @@ namespace GitHub.Runner.Common.Tests.Worker }; //Act - await _actionManager.PrepareActionsAsync(_ec.Object, actions); + var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions); + + Assert.True(steps.Count == 0); } finally { @@ -308,7 +174,6 @@ namespace GitHub.Runner.Common.Tests.Worker } } -/* #if OS_LINUX [Fact] [Trait("Level", "L0")] @@ -328,24 +193,20 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId, Reference = new Pipelines.RepositoryPathReference() { - Name = "actions/test", - Ref = "master", + Name = "TingluoHuang/runner_L0", + Ref = "repositoryactionwithdockerfile", RepositoryType = "GitHub" } } }; - var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "actions/test", "master.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "master")); - File.WriteAllText(Path.Combine(Path.GetDirectoryName(watermarkFile), "master", "Dockerfile"), "Fake Dockerfile"); + var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfile"); //Act var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions); Assert.Equal((steps[0].Data as ContainerSetupInfo).StepIds[0], actionId); - Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory, Path.Combine(Path.GetDirectoryName(watermarkFile), "master")); - Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(Path.GetDirectoryName(watermarkFile), "master", "Dockerfile")); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory, actionDir); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(actionDir, "Dockerfile")); } finally { @@ -371,26 +232,22 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId, Reference = new Pipelines.RepositoryPathReference() { - Name = "actions/test", - Ref = "master", + Name = "TingluoHuang/runner_L0", + Ref = "repositoryactionwithdockerfileinrelativepath", Path = "images/cli", RepositoryType = "GitHub" } } }; - var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "actions/test", "master.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "master/images/cli")); - File.WriteAllText(Path.Combine(Path.GetDirectoryName(watermarkFile), "master/images/cli/Dockerfile"), "Fake Dockerfile"); + var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfileinrelativepath"); //Act var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions); Assert.Equal((steps[0].Data as ContainerSetupInfo).StepIds[0], actionId); - Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory, Path.Combine(Path.GetDirectoryName(watermarkFile), "master")); - Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(Path.GetDirectoryName(watermarkFile), "master", "images/cli", "Dockerfile")); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory, actionDir); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(actionDir, "images/cli", "Dockerfile")); } finally { @@ -416,26 +273,20 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId, Reference = new Pipelines.RepositoryPathReference() { - Name = "notexist/no", - Ref = "notexist", + Name = "TingluoHuang/runner_L0", + Ref = "repositoryactionwithdockerfileinrelativepath", RepositoryType = "GitHub" } } }; - var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "notexist/no", "notexist.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist")); - File.Copy(Path.Combine(Environment.GetEnvironmentVariable("GITHUB_RUNNER_SRC_DIR"), "Test", TestDataFolderName, "dockerfileaction.yml"), Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "action.yml")); - File.WriteAllText(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist/Dockerfile"), "Fake Dockerfile"); - + var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfileinrelativepath"); //Act var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions); Assert.Equal((steps[0].Data as ContainerSetupInfo).StepIds[0], actionId); - Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory, Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist")); - Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "Dockerfile")); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory, actionDir); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(actionDir, "Dockerfile")); } finally { @@ -461,27 +312,21 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId, Reference = new Pipelines.RepositoryPathReference() { - Name = "notexist/no", - Ref = "notexist", + Name = "TingluoHuang/runner_L0", + Ref = "RepositoryActionWithActionfile_DockerfileRelativePath", RepositoryType = "GitHub" } } }; - var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "notexist/no", "notexist.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist")); - File.Copy(Path.Combine(Environment.GetEnvironmentVariable("GITHUB_RUNNER_SRC_DIR"), "Test", TestDataFolderName, "dockerfilerelativeaction.yml"), Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "action.yml")); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "master/images")); - File.WriteAllText(Path.Combine(Path.GetDirectoryName(watermarkFile), "master/images/Dockerfile"), "Fake Dockerfile"); + var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "RepositoryActionWithActionfile_DockerfileRelativePath"); //Act var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions); Assert.Equal((steps[0].Data as ContainerSetupInfo).StepIds[0], actionId); - Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory, Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist")); - Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "images/Dockerfile")); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory, actionDir); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(actionDir, "images/Dockerfile")); } finally { @@ -507,18 +352,14 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId, Reference = new Pipelines.RepositoryPathReference() { - Name = "notexist/no", - Ref = "notexist", + Name = "TingluoHuang/runner_L0", + Ref = "RepositoryActionWithActionfile_DockerHubImage", RepositoryType = "GitHub" } } }; - var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "notexist/no", "notexist.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist")); - File.Copy(Path.Combine(Environment.GetEnvironmentVariable("GITHUB_RUNNER_SRC_DIR"), "Test", TestDataFolderName, "dockerhubaction.yml"), Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "action.yml")); + var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "RepositoryActionWithActionfile_DockerHubImage"); //Act var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions); @@ -550,25 +391,21 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId, Reference = new Pipelines.RepositoryPathReference() { - Name = "notexist/no", - Ref = "notexist", + Name = "TingluoHuang/runner_L0", + Ref = "repositoryactionwithactionfileanddockerfile", RepositoryType = "GitHub" } } }; - var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "notexist/no", "notexist.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist")); - File.Copy(Path.Combine(Environment.GetEnvironmentVariable("GITHUB_RUNNER_SRC_DIR"), "Test", TestDataFolderName, "dockerhubaction.yml"), Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "action.yml")); - File.WriteAllText(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "Dockerfile"), "Fake Dockerfile"); + var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithactionfileanddockerfile"); //Act var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions); Assert.Equal((steps[0].Data as ContainerSetupInfo).StepIds[0], actionId); - Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Image, "ubuntu:18.04"); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory, actionDir); + Assert.Equal((steps[0].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(actionDir, "Dockerfile")); } finally { @@ -628,8 +465,8 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId4, Reference = new Pipelines.RepositoryPathReference() { - Name = "notexist/no", - Ref = "notexist", + Name = "TingluoHuang/runner_L0", + Ref = "notpullorbuildimagesmultipletimes1", RepositoryType = "GitHub" } }, @@ -639,8 +476,8 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId5, Reference = new Pipelines.RepositoryPathReference() { - Name = "actions/test", - Ref = "master", + Name = "TingluoHuang/runner_L0", + Ref = "repositoryactionwithdockerfile", RepositoryType = "GitHub" } }, @@ -650,8 +487,8 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId6, Reference = new Pipelines.RepositoryPathReference() { - Name = "actions/test", - Ref = "release", + Name = "TingluoHuang/runner_L0", + Ref = "repositoryactionwithdockerfileinrelativepath", RepositoryType = "GitHub" } }, @@ -661,8 +498,8 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId7, Reference = new Pipelines.RepositoryPathReference() { - Name = "actions/test", - Ref = "release", + Name = "TingluoHuang/runner_L0", + Ref = "repositoryactionwithdockerfileinrelativepath", RepositoryType = "GitHub" } }, @@ -672,38 +509,14 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId8, Reference = new Pipelines.RepositoryPathReference() { - Name = "actions/test", - Ref = "master", + Name = "TingluoHuang/runner_L0", + Ref = "repositoryactionwithdockerfileinrelativepath", Path = "images/cli", RepositoryType = "GitHub" } } }; - var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "notexist/no", "notexist.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist")); - File.Copy(Path.Combine(Environment.GetEnvironmentVariable("GITHUB_RUNNER_SRC_DIR"), "Test", TestDataFolderName, "dockerhubaction.yml"), Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "action.yml")); - - watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "actions/test", "master.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "master")); - File.WriteAllText(Path.Combine(Path.GetDirectoryName(watermarkFile), "master", "Dockerfile"), "Fake Dockerfile"); - - watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "actions/test", "release.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "release")); - File.WriteAllText(Path.Combine(Path.GetDirectoryName(watermarkFile), "release", "Dockerfile"), "Fake Dockerfile"); - - watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "actions/test", "master.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "master/images/cli")); - File.WriteAllText(Path.Combine(Path.GetDirectoryName(watermarkFile), "master/images/cli/Dockerfile"), "Fake Dockerfile"); - //Act var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions); @@ -716,18 +529,22 @@ namespace GitHub.Runner.Common.Tests.Worker Assert.True((steps[1].Data as ContainerSetupInfo).StepIds.Contains(actionId4)); Assert.Equal((steps[1].Data as ContainerSetupInfo).Container.Image, "ubuntu:18.04"); + var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfile"); + Assert.Equal((steps[2].Data as ContainerSetupInfo).StepIds[0], actionId5); - Assert.Equal((steps[2].Data as ContainerSetupInfo).Container.WorkingDirectory, Path.Combine(Path.GetDirectoryName(watermarkFile), "master")); - Assert.Equal((steps[2].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(Path.GetDirectoryName(watermarkFile), "master", "Dockerfile")); + Assert.Equal((steps[2].Data as ContainerSetupInfo).Container.WorkingDirectory, actionDir); + Assert.Equal((steps[2].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(actionDir, "Dockerfile")); + + actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfileinrelativepath"); Assert.True((steps[3].Data as ContainerSetupInfo).StepIds.Contains(actionId6)); Assert.True((steps[3].Data as ContainerSetupInfo).StepIds.Contains(actionId7)); - Assert.Equal((steps[3].Data as ContainerSetupInfo).Container.WorkingDirectory, Path.Combine(Path.GetDirectoryName(watermarkFile), "release")); - Assert.Equal((steps[3].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(Path.GetDirectoryName(watermarkFile), "release", "Dockerfile")); + Assert.Equal((steps[3].Data as ContainerSetupInfo).Container.WorkingDirectory, actionDir); + Assert.Equal((steps[3].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(actionDir, "Dockerfile")); Assert.Equal((steps[4].Data as ContainerSetupInfo).StepIds[0], actionId8); - Assert.Equal((steps[4].Data as ContainerSetupInfo).Container.WorkingDirectory, Path.Combine(Path.GetDirectoryName(watermarkFile), "master")); - Assert.Equal((steps[4].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(Path.GetDirectoryName(watermarkFile), "master", "images/cli", "Dockerfile")); + Assert.Equal((steps[4].Data as ContainerSetupInfo).Container.WorkingDirectory, actionDir); + Assert.Equal((steps[4].Data as ContainerSetupInfo).Container.Dockerfile, Path.Combine(actionDir, "images/cli", "Dockerfile")); } finally { @@ -754,28 +571,24 @@ namespace GitHub.Runner.Common.Tests.Worker Id = actionId, Reference = new Pipelines.RepositoryPathReference() { - Name = "notexist/no", - Ref = "notexist", + Name = "actions/setup-node", + Ref = "v1", RepositoryType = "GitHub" } } }; - var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "notexist/no", "notexist.completed"); - Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile)); - File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString()); - Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist")); - File.Copy(Path.Combine(Environment.GetEnvironmentVariable("GITHUB_RUNNER_SRC_DIR"), "Test", TestDataFolderName, "nodeaction.yml"), Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "action.yml")); - //Act - await _actionManager.PrepareActionsAsync(_ec.Object, actions); + var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions); + + // node.js based action doesn't need any extra steps to build/pull containers. + Assert.True(steps.Count == 0); } finally { Teardown(); } } -*/ [Fact] [Trait("Level", "L0")] @@ -1653,7 +1466,6 @@ runs: }; } - private void Setup([CallerMemberName] string name = "") { _ecTokenSource?.Dispose(); @@ -1698,9 +1510,21 @@ runs: }); _hc.SetSingleton(_configurationStore.Object); - var pInvoker = new ProcessInvokerWrapper(); - pInvoker.Initialize(_hc); - _hc.EnqueueInstance(pInvoker); + var pInvoker1 = new ProcessInvokerWrapper(); + pInvoker1.Initialize(_hc); + var pInvoker2 = new ProcessInvokerWrapper(); + pInvoker2.Initialize(_hc); + var pInvoker3 = new ProcessInvokerWrapper(); + pInvoker3.Initialize(_hc); + var pInvoker4 = new ProcessInvokerWrapper(); + pInvoker4.Initialize(_hc); + var pInvoker5 = new ProcessInvokerWrapper(); + pInvoker5.Initialize(_hc); + _hc.EnqueueInstance(pInvoker1); + _hc.EnqueueInstance(pInvoker2); + _hc.EnqueueInstance(pInvoker3); + _hc.EnqueueInstance(pInvoker4); + _hc.EnqueueInstance(pInvoker5); // Instance to test. _actionManager = new ActionManager(); @@ -1717,43 +1541,5 @@ runs: Directory.Delete(_workFolder, recursive: true); } } - - private class ExceptionStream : Stream - { - public override bool CanRead => throw new NotImplementedException(); - - public override bool CanSeek => throw new NotImplementedException(); - - public override bool CanWrite => throw new NotImplementedException(); - - public override long Length => throw new NotImplementedException(); - - public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - - public override void Flush() - { - throw new NotImplementedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - } } } diff --git a/src/Test/L0/Worker/JobExtensionL0.cs b/src/Test/L0/Worker/JobExtensionL0.cs index 29c9729e6..2fd2c1401 100644 --- a/src/Test/L0/Worker/JobExtensionL0.cs +++ b/src/Test/L0/Worker/JobExtensionL0.cs @@ -1,386 +1,291 @@ -// using GitHub.DistributedTask.WebApi; -// using GitHub.Runner.Worker; -// using Moq; -// using System; -// using System.Collections.Generic; -// using System.Linq; -// using System.Runtime.CompilerServices; -// using System.Threading.Tasks; -// using Xunit; -// using System.Threading; -// using Pipelines = GitHub.DistributedTask.Pipelines; +using GitHub.DistributedTask.WebApi; +using GitHub.Runner.Worker; +using Moq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; +using System.Threading; +using Pipelines = GitHub.DistributedTask.Pipelines; -// namespace GitHub.Runner.Common.Tests.Worker -// { -// public sealed class JobExtensionL0 -// { -// private class TestJobExtension : JobExtension -// { -// public override HostTypes HostType => HostTypes.None; +namespace GitHub.Runner.Common.Tests.Worker +{ + public sealed class JobExtensionL0 + { + private IExecutionContext _jobEc; + private Pipelines.AgentJobRequestMessage _message; -// public override Type ExtensionType => typeof(IJobExtension); + private Mock _directoryManager; + private Mock _actionManager; + private Mock _jobServerQueue; + private Mock _cert; + private Mock _config; + private Mock _logger; + private Mock _express; + private Mock _containerProvider; + private Mock _diagnosticLogManager; -// public override void ConvertLocalPath(IExecutionContext context, string localPath, out string repoName, out string sourcePath) -// { -// repoName = ""; -// sourcePath = ""; -// } + private CancellationTokenSource _tokenSource; + private TestHostContext CreateTestContext([CallerMemberName] String testName = "") + { + var hc = new TestHostContext(this, testName); + _jobEc = new Runner.Worker.ExecutionContext(); + _actionManager = new Mock(); + _jobServerQueue = new Mock(); + _config = new Mock(); + _logger = new Mock(); + _cert = new Mock(); + _express = new Mock(); + _containerProvider = new Mock(); + _diagnosticLogManager = new Mock(); + _directoryManager = new Mock(); + _directoryManager.Setup(x => x.PrepareDirectory(It.IsAny(), It.IsAny())) + .Returns(new TrackingConfig() { PipelineDirectory = "runner", WorkspaceDirectory = "runner/runner" }); -// public override IStep GetExtensionPostJobStep(IExecutionContext jobContext) -// { -// return null; -// } + IActionRunner step1 = new ActionRunner(); + IActionRunner step2 = new ActionRunner(); + IActionRunner step3 = new ActionRunner(); + IActionRunner step4 = new ActionRunner(); + IActionRunner step5 = new ActionRunner(); -// public override IStep GetExtensionPreJobStep(IExecutionContext jobContext) -// { -// return null; -// } + _logger.Setup(x => x.Setup(It.IsAny(), It.IsAny())); + var settings = new RunnerSettings + { + AgentId = 1, + AgentName = "runner", + ServerUrl = "https://pipelines.actions.githubusercontent.com/abcd", + WorkFolder = "_work", + }; -// public override string GetRootedPath(IExecutionContext context, string path) -// { -// return path; -// } + _config.Setup(x => x.GetSettings()) + .Returns(settings); -// public override void InitializeJobExtension(IExecutionContext context, IList steps, Pipelines.WorkspaceOptions workspace) -// { -// return; -// } -// } + if (_tokenSource != null) + { + _tokenSource.Dispose(); + _tokenSource = null; + } -// private IExecutionContext _jobEc; -// private Pipelines.AgentJobRequestMessage _message; -// private Mock _taskManager; -// private Mock _logPlugin; -// private Mock _jobServerQueue; -// private Mock _proxy; -// private Mock _cert; -// private Mock _config; -// private Mock _logger; -// private Mock _express; -// private Mock _containerProvider; -// private CancellationTokenSource _tokenSource; -// private TestHostContext CreateTestContext([CallerMemberName] String testName = "") -// { -// var hc = new TestHostContext(this, testName); -// _jobEc = new Runner.Worker.ExecutionContext(); -// _taskManager = new Mock(); -// _jobServerQueue = new Mock(); -// _config = new Mock(); -// _logger = new Mock(); -// _proxy = new Mock(); -// _cert = new Mock(); -// _express = new Mock(); -// _containerProvider = new Mock(); -// _logPlugin = new Mock(); + _tokenSource = new CancellationTokenSource(); + TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference(); + TimelineReference timeline = new Timeline(Guid.NewGuid()); -// TaskRunner step1 = new TaskRunner(); -// TaskRunner step2 = new TaskRunner(); -// TaskRunner step3 = new TaskRunner(); -// TaskRunner step4 = new TaskRunner(); -// TaskRunner step5 = new TaskRunner(); -// TaskRunner step6 = new TaskRunner(); -// TaskRunner step7 = new TaskRunner(); -// TaskRunner step8 = new TaskRunner(); -// TaskRunner step9 = new TaskRunner(); -// TaskRunner step10 = new TaskRunner(); -// TaskRunner step11 = new TaskRunner(); -// TaskRunner step12 = new TaskRunner(); + List steps = new List() + { + new Pipelines.ActionStep() + { + Id = Guid.NewGuid(), + DisplayName = "action1", + }, + new Pipelines.ActionStep() + { + Id = Guid.NewGuid(), + DisplayName = "action2", + }, + new Pipelines.ActionStep() + { + Id = Guid.NewGuid(), + DisplayName = "action3", + }, + new Pipelines.ActionStep() + { + Id = Guid.NewGuid(), + DisplayName = "action4", + }, + new Pipelines.ActionStep() + { + Id = Guid.NewGuid(), + DisplayName = "action5", + } + }; -// _logger.Setup(x => x.Setup(It.IsAny(), It.IsAny())); -// var settings = new AgentSettings -// { -// AgentId = 1, -// AgentName = "agent1", -// ServerUrl = "https://test.visualstudio.com", -// WorkFolder = "_work", -// }; + Guid jobId = Guid.NewGuid(); + _message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary(), new List(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null); + GitHubContext github = new GitHubContext(); + github["repository"] = new Pipelines.ContextData.StringContextData("actions/runner"); + _message.ContextData.Add("github", github); -// _config.Setup(x => x.GetSettings()) -// .Returns(settings); + hc.SetSingleton(_actionManager.Object); + hc.SetSingleton(_config.Object); + hc.SetSingleton(_jobServerQueue.Object); + hc.SetSingleton(_cert.Object); + hc.SetSingleton(_express.Object); + hc.SetSingleton(_containerProvider.Object); + hc.SetSingleton(_directoryManager.Object); + hc.SetSingleton(_diagnosticLogManager.Object); + hc.EnqueueInstance(_logger.Object); // JobExecutionContext + hc.EnqueueInstance(_logger.Object); // Initial Job + hc.EnqueueInstance(_logger.Object); // step1 + hc.EnqueueInstance(_logger.Object); // step2 + hc.EnqueueInstance(_logger.Object); // step3 + hc.EnqueueInstance(_logger.Object); // step4 + hc.EnqueueInstance(_logger.Object); // step5 + hc.EnqueueInstance(_logger.Object); // prepare1 + hc.EnqueueInstance(_logger.Object); // prepare2 -// _proxy.Setup(x => x.ProxyAddress) -// .Returns(string.Empty); + hc.EnqueueInstance(step1); + hc.EnqueueInstance(step2); + hc.EnqueueInstance(step3); + hc.EnqueueInstance(step4); + hc.EnqueueInstance(step5); -// if (_tokenSource != null) -// { -// _tokenSource.Dispose(); -// _tokenSource = null; -// } + _jobEc.Initialize(hc); + _jobEc.InitializeJob(_message, _tokenSource.Token); + return hc; + } -// _tokenSource = new CancellationTokenSource(); -// TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference(); -// TimelineReference timeline = new Timeline(Guid.NewGuid()); -// JobEnvironment environment = new JobEnvironment(); -// environment.Variables[Constants.Variables.System.Culture] = "en-US"; -// environment.SystemConnection = new ServiceEndpoint() -// { -// Name = WellKnownServiceEndpointNames.SystemVssConnection, -// Url = new Uri("https://test.visualstudio.com"), -// Authorization = new EndpointAuthorization() -// { -// Scheme = "Test", -// } -// }; -// environment.SystemConnection.Authorization.Parameters["AccessToken"] = "token"; + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task JobExtensionBuildStepsList() + { + using (TestHostContext hc = CreateTestContext()) + { + var jobExtension = new JobExtension(); + jobExtension.Initialize(hc); -// List tasks = new List() -// { -// new TaskInstance() -// { -// InstanceId = Guid.NewGuid(), -// DisplayName = "task1", -// }, -// new TaskInstance() -// { -// InstanceId = Guid.NewGuid(), -// DisplayName = "task2", -// }, -// new TaskInstance() -// { -// InstanceId = Guid.NewGuid(), -// DisplayName = "task3", -// }, -// new TaskInstance() -// { -// InstanceId = Guid.NewGuid(), -// DisplayName = "task4", -// }, -// new TaskInstance() -// { -// InstanceId = Guid.NewGuid(), -// DisplayName = "task5", -// }, -// new TaskInstance() -// { -// InstanceId = Guid.NewGuid(), -// DisplayName = "task6", -// }, -// new TaskInstance() -// { -// InstanceId = Guid.NewGuid(), -// DisplayName = "task7", -// }, -// }; + _actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny(), It.IsAny>())) + .Returns(Task.FromResult(new List())); -// Guid JobId = Guid.NewGuid(); -// _message = Pipelines.AgentJobRequestMessageUtil.Convert(new AgentJobRequestMessage(plan, timeline, JobId, testName, testName, environment, tasks)); + List result = await jobExtension.InitializeJob(_jobEc, _message); -// _taskManager.Setup(x => x.DownloadAsync(It.IsAny(), It.IsAny>())) -// .Returns(Task.CompletedTask); + var trace = hc.GetTrace(); -// _taskManager.Setup(x => x.Load(It.Is(t => t.DisplayName == "task1"))) -// .Returns(new Definition() -// { -// Data = new DefinitionData() -// { -// PreJobExecution = null, -// Execution = new ExecutionData(), -// PostJobExecution = null, -// }, -// }); -// _taskManager.Setup(x => x.Load(It.Is(t => t.DisplayName == "task2"))) -// .Returns(new Definition() -// { -// Data = new DefinitionData() -// { -// PreJobExecution = new ExecutionData(), -// Execution = new ExecutionData(), -// PostJobExecution = new ExecutionData(), -// }, -// }); -// _taskManager.Setup(x => x.Load(It.Is(t => t.DisplayName == "task3"))) -// .Returns(new Definition() -// { -// Data = new DefinitionData() -// { -// PreJobExecution = new ExecutionData(), -// Execution = null, -// PostJobExecution = new ExecutionData(), -// }, -// }); -// _taskManager.Setup(x => x.Load(It.Is(t => t.DisplayName == "task4"))) -// .Returns(new Definition() -// { -// Data = new DefinitionData() -// { -// PreJobExecution = new ExecutionData(), -// Execution = null, -// PostJobExecution = null, -// }, -// }); -// _taskManager.Setup(x => x.Load(It.Is(t => t.DisplayName == "task5"))) -// .Returns(new Definition() -// { -// Data = new DefinitionData() -// { -// PreJobExecution = null, -// Execution = null, -// PostJobExecution = new ExecutionData(), -// }, -// }); -// _taskManager.Setup(x => x.Load(It.Is(t => t.DisplayName == "task6"))) -// .Returns(new Definition() -// { -// Data = new DefinitionData() -// { -// PreJobExecution = new ExecutionData(), -// Execution = new ExecutionData(), -// PostJobExecution = null, -// }, -// }); -// _taskManager.Setup(x => x.Load(It.Is(t => t.DisplayName == "task7"))) -// .Returns(new Definition() -// { -// Data = new DefinitionData() -// { -// PreJobExecution = null, -// Execution = new ExecutionData(), -// PostJobExecution = new ExecutionData(), -// }, -// }); + trace.Info(string.Join(", ", result.Select(x => x.DisplayName))); -// hc.SetSingleton(_taskManager.Object); -// hc.SetSingleton(_config.Object); -// hc.SetSingleton(_jobServerQueue.Object); -// hc.SetSingleton(_proxy.Object); -// hc.SetSingleton(_cert.Object); -// hc.SetSingleton(_express.Object); -// hc.SetSingleton(_containerProvider.Object); -// hc.SetSingleton(_logPlugin.Object); -// hc.EnqueueInstance(_logger.Object); // jobcontext logger -// hc.EnqueueInstance(_logger.Object); // init step logger -// hc.EnqueueInstance(_logger.Object); // step 1 -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); // step 12 + Assert.Equal(5, result.Count); -// hc.EnqueueInstance(step1); -// hc.EnqueueInstance(step2); -// hc.EnqueueInstance(step3); -// hc.EnqueueInstance(step4); -// hc.EnqueueInstance(step5); -// hc.EnqueueInstance(step6); -// hc.EnqueueInstance(step7); -// hc.EnqueueInstance(step8); -// hc.EnqueueInstance(step9); -// hc.EnqueueInstance(step10); -// hc.EnqueueInstance(step11); -// hc.EnqueueInstance(step12); + Assert.Equal("action1", result[0].DisplayName); + Assert.Equal("action2", result[1].DisplayName); + Assert.Equal("action3", result[2].DisplayName); + Assert.Equal("action4", result[3].DisplayName); + Assert.Equal("action5", result[4].DisplayName); -// _jobEc.Initialize(hc); -// _jobEc.InitializeJob(_message, _tokenSource.Token); -// return hc; -// } + Assert.NotNull(result[0].ExecutionContext); + Assert.NotNull(result[1].ExecutionContext); + Assert.NotNull(result[2].ExecutionContext); + Assert.NotNull(result[3].ExecutionContext); + Assert.NotNull(result[4].ExecutionContext); + } + } -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task JobExtensioBuildStepsList() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// TestJobExtension testExtension = new TestJobExtension(); -// testExtension.Initialize(hc); -// List result = await testExtension.InitializeJob(_jobEc, _message); + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task JobExtensionBuildPreStepsList() + { + using (TestHostContext hc = CreateTestContext()) + { + var jobExtension = new JobExtension(); + jobExtension.Initialize(hc); -// var trace = hc.GetTrace(); + _actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny(), It.IsAny>())) + .Returns(Task.FromResult(new List() { new JobExtensionRunner(null, "", "prepare1", null), new JobExtensionRunner(null, "", "prepare2", null) })); -// trace.Info(string.Join(", ", result.Select(x => x.DisplayName))); + List result = await jobExtension.InitializeJob(_jobEc, _message); -// Assert.Equal(12, result.Count); + var trace = hc.GetTrace(); -// Assert.Equal("task2", result[0].DisplayName); -// Assert.Equal("task3", result[1].DisplayName); -// Assert.Equal("task4", result[2].DisplayName); -// Assert.Equal("task6", result[3].DisplayName); -// Assert.Equal("task1", result[4].DisplayName); -// Assert.Equal("task2", result[5].DisplayName); -// Assert.Equal("task6", result[6].DisplayName); -// Assert.Equal("task7", result[7].DisplayName); -// Assert.Equal("task7", result[8].DisplayName); -// Assert.Equal("task5", result[9].DisplayName); -// Assert.Equal("task3", result[10].DisplayName); -// Assert.Equal("task2", result[11].DisplayName); -// } -// } + trace.Info(string.Join(", ", result.Select(x => x.DisplayName))); -// // [Fact] -// // [Trait("Level", "L0")] -// // [Trait("Category", "Worker")] -// // public async Task JobExtensionIntraTaskState() -// // { -// // using (TestHostContext hc = CreateTestContext()) -// // { -// // TestJobExtension testExtension = new TestJobExtension(); -// // testExtension.Initialize(hc); -// // List result = await testExtension.InitializeJob(_jobEc, _message); + Assert.Equal(7, result.Count); -// // var trace = hc.GetTrace(); + Assert.Equal("prepare1", result[0].DisplayName); + Assert.Equal("prepare2", result[1].DisplayName); + Assert.Equal("action1", result[2].DisplayName); + Assert.Equal("action2", result[3].DisplayName); + Assert.Equal("action3", result[4].DisplayName); + Assert.Equal("action4", result[5].DisplayName); + Assert.Equal("action5", result[6].DisplayName); -// // trace.Info(string.Join(", ", result.Select(x => x.DisplayName))); + Assert.NotNull(result[0].ExecutionContext); + Assert.NotNull(result[1].ExecutionContext); + Assert.NotNull(result[2].ExecutionContext); + Assert.NotNull(result[3].ExecutionContext); + Assert.NotNull(result[4].ExecutionContext); + Assert.NotNull(result[5].ExecutionContext); + Assert.NotNull(result[6].ExecutionContext); + } + } -// // Assert.Equal(12, result.Count); + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public void UploadDiganosticLogIfEnvironmentVariableSet() + { + using (TestHostContext hc = CreateTestContext()) + { + var jobExtension = new JobExtension(); + jobExtension.Initialize(hc); -// // result[0].ExecutionContext.TaskVariables.Set("state1", "value1", false); -// // Assert.Equal("value1", result[5].ExecutionContext.TaskVariables.Get("state1")); -// // Assert.Equal("value1", result[11].ExecutionContext.TaskVariables.Get("state1")); + _message.Variables[Constants.Variables.Actions.RunnerDebug] = "true"; -// // Assert.Null(result[4].ExecutionContext.TaskVariables.Get("state1")); -// // Assert.Null(result[1].ExecutionContext.TaskVariables.Get("state1")); -// // Assert.Null(result[2].ExecutionContext.TaskVariables.Get("state1")); -// // Assert.Null(result[10].ExecutionContext.TaskVariables.Get("state1")); -// // Assert.Null(result[6].ExecutionContext.TaskVariables.Get("state1")); -// // Assert.Null(result[7].ExecutionContext.TaskVariables.Get("state1")); -// // } -// // } + _jobEc = new Runner.Worker.ExecutionContext(); + _jobEc.Initialize(hc); + _jobEc.InitializeJob(_message, _tokenSource.Token); -// #if OS_WINDOWS -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task JobExtensionManagementScriptStep() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// hc.EnqueueInstance(_logger.Object); -// hc.EnqueueInstance(_logger.Object); + jobExtension.FinalizeJob(_jobEc, _message, DateTime.UtcNow); -// Environment.SetEnvironmentVariable("VSTS_AGENT_INIT_INTERNAL_TEMP_HACK", "C:\\init.ps1"); -// Environment.SetEnvironmentVariable("VSTS_AGENT_CLEANUP_INTERNAL_TEMP_HACK", "C:\\clenup.ps1"); + _diagnosticLogManager.Verify(x => + x.UploadDiagnosticLogs( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny()), + Times.Once); + } + } -// try -// { -// TestJobExtension testExtension = new TestJobExtension(); -// testExtension.Initialize(hc); -// List result = await testExtension.InitializeJob(_jobEc, _message); + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public void DontUploadDiagnosticLogIfEnvironmentVariableFalse() + { + using (TestHostContext hc = CreateTestContext()) + { + var jobExtension = new JobExtension(); + jobExtension.Initialize(hc); -// var trace = hc.GetTrace(); + _message.Variables[Constants.Variables.Actions.RunnerDebug] = "false"; -// trace.Info(string.Join(", ", result.Select(x => x.DisplayName))); + _jobEc = new Runner.Worker.ExecutionContext(); + _jobEc.Initialize(hc); + _jobEc.InitializeJob(_message, _tokenSource.Token); -// Assert.Equal(14, result.Count); + jobExtension.FinalizeJob(_jobEc, _message, DateTime.UtcNow); -// Assert.True(result[0] is ManagementScriptStep); -// Assert.True(result[13] is ManagementScriptStep); + _diagnosticLogManager.Verify(x => + x.UploadDiagnosticLogs( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny()), + Times.Never); + } + } -// Assert.Equal(result[0].DisplayName, "Agent Initialization"); -// Assert.Equal(result[13].DisplayName, "Agent Cleanup"); -// } -// finally -// { -// Environment.SetEnvironmentVariable("VSTS_AGENT_INIT_INTERNAL_TEMP_HACK", ""); -// Environment.SetEnvironmentVariable("VSTS_AGENT_CLEANUP_INTERNAL_TEMP_HACK", ""); -// } -// } -// } -// #endif -// } -// } + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public void DontUploadDiagnosticLogIfEnvironmentVariableMissing() + { + using (TestHostContext hc = CreateTestContext()) + { + var jobExtension = new JobExtension(); + jobExtension.Initialize(hc); + + jobExtension.FinalizeJob(_jobEc, _message, DateTime.UtcNow); + + _diagnosticLogManager.Verify(x => + x.UploadDiagnosticLogs( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny()), + Times.Never); + } + } + } +} diff --git a/src/Test/L0/Worker/JobRunnerL0.cs b/src/Test/L0/Worker/JobRunnerL0.cs index f2c9a9609..b47faf0e3 100644 --- a/src/Test/L0/Worker/JobRunnerL0.cs +++ b/src/Test/L0/Worker/JobRunnerL0.cs @@ -154,64 +154,5 @@ namespace GitHub.Runner.Common.Tests.Worker _stepRunner.Verify(x => x.RunAsync(It.IsAny()), Times.Never); } } - - // TODO: Move these tests over to JobExtensionL0.cs - // [Fact] - // [Trait("Level", "L0")] - // [Trait("Category", "Worker")] - // public async Task UploadDiganosticLogIfEnvironmentVariableSet() - // { - // using (TestHostContext hc = CreateTestContext()) - // { - // _message.Variables[Constants.Variables.Actions.RunnerDebug] = "true"; - - // await _jobRunner.RunAsync(_message, _tokenSource.Token); - - // _diagnosticLogManager.Verify(x => - // x.UploadDiagnosticLogsAsync( - // It.IsAny(), - // It.IsAny(), - // It.IsAny()), - // Times.Once); - // } - // } - - // [Fact] - // [Trait("Level", "L0")] - // [Trait("Category", "Worker")] - // public async Task DontUploadDiagnosticLogIfEnvironmentVariableFalse() - // { - // using (TestHostContext hc = CreateTestContext()) - // { - // _message.Variables[Constants.Variables.Actions.RunnerDebug] = "false"; - - // await _jobRunner.RunAsync(_message, _tokenSource.Token); - - // _diagnosticLogManager.Verify(x => - // x.UploadDiagnosticLogsAsync( - // It.IsAny(), - // It.IsAny(), - // It.IsAny()), - // Times.Never); - // } - // } - - // [Fact] - // [Trait("Level", "L0")] - // [Trait("Category", "Worker")] - // public async Task DontUploadDiagnosticLogIfEnvironmentVariableMissing() - // { - // using (TestHostContext hc = CreateTestContext()) - // { - // await _jobRunner.RunAsync(_message, _tokenSource.Token); - - // _diagnosticLogManager.Verify(x => - // x.UploadDiagnosticLogsAsync( - // It.IsAny(), - // It.IsAny(), - // It.IsAny()), - // Times.Never); - // } - // } } } diff --git a/src/Test/L0/Worker/StepsRunnerL0.cs b/src/Test/L0/Worker/StepsRunnerL0.cs index 071625c04..d9721305e 100644 --- a/src/Test/L0/Worker/StepsRunnerL0.cs +++ b/src/Test/L0/Worker/StepsRunnerL0.cs @@ -1,448 +1,443 @@ -// using GitHub.DistributedTask.WebApi; -// using GitHub.Runner.Worker; -// using Moq; -// using System; -// using System.Collections.Generic; -// using System.Globalization; -// using System.Linq; -// using System.Runtime.CompilerServices; -// using System.Threading.Tasks; -// using Xunit; -// using GitHub.DistributedTask.Expressions2; -// using GitHub.DistributedTask.Pipelines.ContextData; +using GitHub.DistributedTask.WebApi; +using GitHub.Runner.Worker; +using Moq; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; +using GitHub.DistributedTask.Expressions2; +using GitHub.DistributedTask.Pipelines.ContextData; +using GitHub.DistributedTask.ObjectTemplating.Tokens; -// namespace GitHub.Runner.Common.Tests.Worker -// { -// public sealed class StepsRunnerL0 -// { -// private Mock _ec; -// private StepsRunner _stepsRunner; -// private Variables _variables; -// private Dictionary _contexts; -// private TestHostContext CreateTestContext([CallerMemberName] String testName = "") -// { -// var hc = new TestHostContext(this, testName); -// var expressionManager = new ExpressionManager(); -// expressionManager.Initialize(hc); -// hc.SetSingleton(expressionManager); -// Dictionary variablesToCopy = new Dictionary(); -// variablesToCopy.Add(Constants.Variables.Agent.RetainDefaultEncoding, new VariableValue("true", false)); -// _variables = new Variables( -// hostContext: hc, -// copy: variablesToCopy); -// _ec = new Mock(); -// _ec.SetupAllProperties(); -// _ec.Setup(x => x.Variables).Returns(_variables); +namespace GitHub.Runner.Common.Tests.Worker +{ + public sealed class StepsRunnerL0 + { + private Mock _ec; + private StepsRunner _stepsRunner; + private Variables _variables; + private DictionaryContextData _contexts; + private JobContext _jobContext; + private StepsContext _stepContext; + private TestHostContext CreateTestContext([CallerMemberName] String testName = "") + { + var hc = new TestHostContext(this, testName); + var expressionManager = new ExpressionManager(); + expressionManager.Initialize(hc); + hc.SetSingleton(expressionManager); + Dictionary variablesToCopy = new Dictionary(); + _variables = new Variables( + hostContext: hc, + copy: variablesToCopy); + _ec = new Mock(); + _ec.SetupAllProperties(); + _ec.Setup(x => x.Variables).Returns(_variables); -// _contexts = new Dictionary(); -// _contexts["github"] = new DictionaryContextData(); -// _contexts["runner"] = new DictionaryContextData(); -// _contexts["actions"] = new DictionaryContextData(); -// _ec.Setup(x => x.ExpressionValues).Returns(_contexts); + _contexts = new DictionaryContextData(); + _jobContext = new JobContext(); + _contexts["github"] = new DictionaryContextData(); + _contexts["runner"] = new DictionaryContextData(); + _contexts["job"] = _jobContext; + _ec.Setup(x => x.ExpressionValues).Returns(_contexts); + _ec.Setup(x => x.JobContext).Returns(_jobContext); -// var _stepContext = new StepsContext(); -// _ec.Setup(x => x.StepsContext).Returns(_stepContext); -// _stepsRunner = new StepsRunner(); -// _stepsRunner.Initialize(hc); -// return hc; -// } + _stepContext = new StepsContext(); + _ec.Setup(x => x.StepsContext).Returns(_stepContext); -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task RunNormalStepsAllStepPass() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// // Arrange. -// var variableSets = new[] -// { -// new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded) }, -// new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.SucceededOrFailed) }, -// new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) } -// }; -// foreach (var variableSet in variableSets) -// { -// _ec.Object.Result = null; + _ec.Setup(x => x.PostJobSteps).Returns(new Stack()); -// // Act. -// await _stepsRunner.RunAsync( -// jobContext: _ec.Object, -// steps: variableSet.Select(x => x.Object).ToList()); + _stepsRunner = new StepsRunner(); + _stepsRunner.Initialize(hc); + return hc; + } -// // Assert. -// Assert.Equal(TaskResult.Succeeded, _ec.Object.Result ?? TaskResult.Succeeded); -// Assert.Equal(2, variableSet.Length); -// variableSet[0].Verify(x => x.RunAsync()); -// variableSet[1].Verify(x => x.RunAsync()); -// } -// } -// } + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task RunNormalStepsAllStepPass() + { + using (TestHostContext hc = CreateTestContext()) + { + // Arrange. + var variableSets = new[] + { + new[] { CreateStep(TaskResult.Succeeded, "success()"), CreateStep(TaskResult.Succeeded, "success()") }, + new[] { CreateStep(TaskResult.Succeeded, "success()"), CreateStep(TaskResult.Succeeded, "success() || failure()") }, + new[] { CreateStep(TaskResult.Succeeded, "success()"), CreateStep(TaskResult.Succeeded, "always()") } + }; + foreach (var variableSet in variableSets) + { + _ec.Object.Result = null; -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task RunNormalStepsContinueOnError() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// // Arrange. -// var variableSets = new[] -// { -// new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, true), CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded) }, -// new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, true), CreateStep(TaskResult.Succeeded, ExpressionManager.SucceededOrFailed) }, -// new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, true), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) }, -// new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, true), CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, true) }, -// new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, true), CreateStep(TaskResult.Failed, ExpressionManager.SucceededOrFailed, true) }, -// new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, true), CreateStep(TaskResult.Failed, ExpressionManager.Always, true) } -// }; -// foreach (var variableSet in variableSets) -// { -// _ec.Object.Result = null; + _ec.Setup(x => x.JobSteps).Returns(new Queue(variableSet.Select(x => x.Object).ToList())); -// // Act. -// await _stepsRunner.RunAsync( -// jobContext: _ec.Object, -// steps: variableSet.Select(x => x.Object).ToList()); + // Act. + await _stepsRunner.RunAsync(jobContext: _ec.Object); -// // Assert. -// Assert.Equal(TaskResult.SucceededWithIssues, _ec.Object.Result); -// Assert.Equal(2, variableSet.Length); -// variableSet[0].Verify(x => x.RunAsync()); -// variableSet[1].Verify(x => x.RunAsync()); -// } -// } -// } + // Assert. + Assert.Equal(TaskResult.Succeeded, _ec.Object.Result ?? TaskResult.Succeeded); + Assert.Equal(2, variableSet.Length); + variableSet[0].Verify(x => x.RunAsync()); + variableSet[1].Verify(x => x.RunAsync()); + } + } + } -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task RunsAfterFailureBasedOnCondition() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// // Arrange. -// var variableSets = new[] -// { -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded) }, -// Expected = false, -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.SucceededOrFailed) }, -// Expected = true, -// }, -// }; -// foreach (var variableSet in variableSets) -// { -// _ec.Object.Result = null; + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task RunNormalStepsContinueOnError() + { + using (TestHostContext hc = CreateTestContext()) + { + // Arrange. + var variableSets = new[] + { + new[] { CreateStep(TaskResult.Failed, "success()", true), CreateStep(TaskResult.Succeeded, "success()") }, + new[] { CreateStep(TaskResult.Failed, "success()", true), CreateStep(TaskResult.Succeeded, "success() || failure()") }, + new[] { CreateStep(TaskResult.Failed, "success()", true), CreateStep(TaskResult.Succeeded, "always()") }, + new[] { CreateStep(TaskResult.Failed, "success()", true), CreateStep(TaskResult.Failed, "success()", true) }, + new[] { CreateStep(TaskResult.Failed, "success()", true), CreateStep(TaskResult.Failed, "success() || failure()", true) }, + new[] { CreateStep(TaskResult.Failed, "success()", true), CreateStep(TaskResult.Failed, "always()", true) } + }; + foreach (var variableSet in variableSets) + { + _ec.Object.Result = null; -// // Act. -// await _stepsRunner.RunAsync( -// jobContext: _ec.Object, -// steps: variableSet.Steps.Select(x => x.Object).ToList()); + _ec.Setup(x => x.JobSteps).Returns(new Queue(variableSet.Select(x => x.Object).ToList())); -// // Assert. -// Assert.Equal(TaskResult.Failed, _ec.Object.Result ?? TaskResult.Succeeded); -// Assert.Equal(2, variableSet.Steps.Length); -// variableSet.Steps[0].Verify(x => x.RunAsync()); -// variableSet.Steps[1].Verify(x => x.RunAsync(), variableSet.Expected ? Times.Once() : Times.Never()); -// } -// } -// } + // Act. + await _stepsRunner.RunAsync(jobContext: _ec.Object); -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task RunsAlwaysSteps() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// // Arrange. -// var variableSets = new[] -// { -// new -// { -// Steps = new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) }, -// Expected = TaskResult.Succeeded, -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) }, -// Expected = TaskResult.Failed, -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) }, -// Expected = TaskResult.Failed, -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded), CreateStep(TaskResult.Failed, ExpressionManager.Always) }, -// Expected = TaskResult.Failed, -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded), CreateStep(TaskResult.Failed, ExpressionManager.Always, true) }, -// Expected = TaskResult.SucceededWithIssues, -// }, -// }; -// foreach (var variableSet in variableSets) -// { -// _ec.Object.Result = null; + // Assert. + Assert.Equal(TaskResult.Succeeded, _ec.Object.Result ?? TaskResult.Succeeded); + Assert.Equal(2, variableSet.Length); + variableSet[0].Verify(x => x.RunAsync()); + variableSet[1].Verify(x => x.RunAsync()); + } + } + } -// // Act. -// await _stepsRunner.RunAsync( -// jobContext: _ec.Object, -// steps: variableSet.Steps.Select(x => x.Object).ToList()); + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task RunsAfterFailureBasedOnCondition() + { + using (TestHostContext hc = CreateTestContext()) + { + // Arrange. + var variableSets = new[] + { + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "success()") }, + Expected = false, + }, + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "success() || failure()") }, + Expected = true, + }, + }; + foreach (var variableSet in variableSets) + { + _ec.Object.Result = null; -// // Assert. -// Assert.Equal(variableSet.Expected, _ec.Object.Result ?? TaskResult.Succeeded); -// Assert.Equal(2, variableSet.Steps.Length); -// variableSet.Steps[0].Verify(x => x.RunAsync()); -// variableSet.Steps[1].Verify(x => x.RunAsync()); -// } -// } -// } + _ec.Setup(x => x.JobSteps).Returns(new Queue(variableSet.Steps.Select(x => x.Object).ToList())); -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task SetsJobResultCorrectly() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// // Arrange. -// var variableSets = new[] -// { -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded) }, -// Expected = TaskResult.Failed -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.SucceededOrFailed) }, -// Expected = TaskResult.Failed -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) }, -// Expected = TaskResult.Failed -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, continueOnError: true), CreateStep(TaskResult.Failed, ExpressionManager.Succeeded) }, -// Expected = TaskResult.Failed -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, continueOnError: true), CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded) }, -// Expected = TaskResult.SucceededWithIssues -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, continueOnError: true), CreateStep(TaskResult.Failed, ExpressionManager.Succeeded, continueOnError: true) }, -// Expected = TaskResult.SucceededWithIssues -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.SucceededOrFailed) }, -// Expected = TaskResult.Succeeded -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded), CreateStep(TaskResult.Failed, ExpressionManager.Succeeded) }, -// Expected = TaskResult.Failed -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded), CreateStep(TaskResult.SucceededWithIssues, ExpressionManager.Succeeded) }, -// Expected = TaskResult.SucceededWithIssues -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.SucceededWithIssues, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded) }, -// Expected = TaskResult.SucceededWithIssues -// }, -// new -// { -// Steps = new[] { CreateStep(TaskResult.SucceededWithIssues, ExpressionManager.Succeeded), CreateStep(TaskResult.Failed, ExpressionManager.Succeeded) }, -// Expected = TaskResult.Failed -// }, -// // Abandoned -// // Canceled -// // Failed -// // Skipped -// // Succeeded -// // SucceededWithIssues -// }; -// foreach (var variableSet in variableSets) -// { -// _ec.Object.Result = null; + // Act. + await _stepsRunner.RunAsync(jobContext: _ec.Object); -// // Act. -// await _stepsRunner.RunAsync( -// jobContext: _ec.Object, -// steps: variableSet.Steps.Select(x => x.Object).ToList()); + // Assert. + Assert.Equal(TaskResult.Failed, _ec.Object.Result ?? TaskResult.Succeeded); + Assert.Equal(2, variableSet.Steps.Length); + variableSet.Steps[0].Verify(x => x.RunAsync()); + variableSet.Steps[1].Verify(x => x.RunAsync(), variableSet.Expected ? Times.Once() : Times.Never()); + } + } + } -// // Assert. -// Assert.True( -// variableSet.Expected == (_ec.Object.Result ?? TaskResult.Succeeded), -// $"Expected '{variableSet.Expected}'. Actual '{_ec.Object.Result}'. Steps: {FormatSteps(variableSet.Steps)}"); -// } -// } -// } + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task RunsAlwaysSteps() + { + using (TestHostContext hc = CreateTestContext()) + { + // Arrange. + var variableSets = new[] + { + new + { + Steps = new[] { CreateStep(TaskResult.Succeeded, "success()"), CreateStep(TaskResult.Succeeded, "always()") }, + Expected = TaskResult.Succeeded, + }, + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "always()") }, + Expected = TaskResult.Failed, + }, + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "always()") }, + Expected = TaskResult.Failed, + }, + new + { + Steps = new[] { CreateStep(TaskResult.Succeeded, "success()"), CreateStep(TaskResult.Failed, "always()") }, + Expected = TaskResult.Failed, + }, + new + { + Steps = new[] { CreateStep(TaskResult.Succeeded, "success()"), CreateStep(TaskResult.Failed, "always()", true) }, + Expected = TaskResult.Succeeded, + }, + }; + foreach (var variableSet in variableSets) + { + _ec.Object.Result = null; -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task SkipsAfterFailureOnlyBaseOnCondition() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// // Arrange. -// var variableSets = new[] -// { -// new -// { -// Step = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded) }, -// Expected = false -// }, -// new -// { -// Step = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.SucceededOrFailed) }, -// Expected = true -// }, -// new -// { -// Step = new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) }, -// Expected = true -// } -// }; -// foreach (var variableSet in variableSets) -// { -// _ec.Object.Result = null; + _ec.Setup(x => x.JobSteps).Returns(new Queue(variableSet.Steps.Select(x => x.Object).ToList())); -// // Act. -// await _stepsRunner.RunAsync( -// jobContext: _ec.Object, -// steps: variableSet.Step.Select(x => x.Object).ToList()); + // Act. + await _stepsRunner.RunAsync(jobContext: _ec.Object); -// // Assert. -// Assert.Equal(2, variableSet.Step.Length); -// variableSet.Step[0].Verify(x => x.RunAsync()); -// variableSet.Step[1].Verify(x => x.RunAsync(), variableSet.Expected ? Times.Once() : Times.Never()); -// } -// } -// } + // Assert. + Assert.Equal(variableSet.Expected, _ec.Object.Result ?? TaskResult.Succeeded); + Assert.Equal(2, variableSet.Steps.Length); + variableSet.Steps[0].Verify(x => x.RunAsync()); + variableSet.Steps[1].Verify(x => x.RunAsync()); + } + } + } -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task AlwaysMeansAlways() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// // Arrange. -// var variableSets = new[] -// { -// new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) }, -// new[] { CreateStep(TaskResult.SucceededWithIssues, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) }, -// new[] { CreateStep(TaskResult.Failed, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) }, -// new[] { CreateStep(TaskResult.Canceled, ExpressionManager.Succeeded), CreateStep(TaskResult.Succeeded, ExpressionManager.Always) } -// }; -// foreach (var variableSet in variableSets) -// { -// _ec.Object.Result = null; + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task SetsJobResultCorrectly() + { + using (TestHostContext hc = CreateTestContext()) + { + // Arrange. + var variableSets = new[] + { + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "success()") }, + Expected = TaskResult.Failed + }, + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "success() || failure()") }, + Expected = TaskResult.Failed + }, + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "always()") }, + Expected = TaskResult.Failed + }, + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()", continueOnError: true), CreateStep(TaskResult.Failed, "success()") }, + Expected = TaskResult.Failed + }, + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()", continueOnError: true), CreateStep(TaskResult.Succeeded, "success()") }, + Expected = TaskResult.Succeeded + }, + new + { + Steps = new[] { CreateStep(TaskResult.Failed, "success()", continueOnError: true), CreateStep(TaskResult.Failed, "success()", continueOnError: true) }, + Expected = TaskResult.Succeeded + }, + new + { + Steps = new[] { CreateStep(TaskResult.Succeeded, "success() || failure()") }, + Expected = TaskResult.Succeeded + }, + new + { + Steps = new[] { CreateStep(TaskResult.Succeeded, "success()"), CreateStep(TaskResult.Failed, "success()") }, + Expected = TaskResult.Failed + }, + new + { + Steps = new[] { CreateStep(TaskResult.Succeeded, "success()"), CreateStep(TaskResult.Succeeded, "success()") }, + Expected = TaskResult.Succeeded + }, + // Abandoned + // Canceled + // Failed + // Skipped + // Succeeded + }; + foreach (var variableSet in variableSets) + { + _ec.Object.Result = null; -// // Act. -// await _stepsRunner.RunAsync( -// jobContext: _ec.Object, -// steps: variableSet.Select(x => x.Object).ToList()); + _ec.Setup(x => x.JobSteps).Returns(new Queue(variableSet.Steps.Select(x => x.Object).ToList())); -// // Assert. -// Assert.Equal(2, variableSet.Length); -// variableSet[0].Verify(x => x.RunAsync()); -// variableSet[1].Verify(x => x.RunAsync(), Times.Once()); -// } -// } -// } + // Act. + await _stepsRunner.RunAsync(jobContext: _ec.Object); -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public async Task TreatsConditionErrorAsFailure() -// { -// using (TestHostContext hc = CreateTestContext()) -// { -// var expressionManager = new Mock(); -// expressionManager.Object.Initialize(hc); -// hc.SetSingleton(expressionManager.Object); -// expressionManager.Setup(x => x.Evaluate(It.IsAny(), It.IsAny(), It.IsAny())).Throws(new Exception()); + // Assert. + Assert.True( + variableSet.Expected == (_ec.Object.Result ?? TaskResult.Succeeded), + $"Expected '{variableSet.Expected}'. Actual '{_ec.Object.Result}'. Steps: {FormatSteps(variableSet.Steps)}"); + } + } + } -// // Arrange. -// var variableSets = new[] -// { -// new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded) }, -// new[] { CreateStep(TaskResult.Succeeded, ExpressionManager.Succeeded) }, -// }; -// foreach (var variableSet in variableSets) -// { -// _ec.Object.Result = null; + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task SkipsAfterFailureOnlyBaseOnCondition() + { + using (TestHostContext hc = CreateTestContext()) + { + // Arrange. + var variableSets = new[] + { + new + { + Step = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "success()") }, + Expected = false + }, + new + { + Step = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "success() || failure()") }, + Expected = true + }, + new + { + Step = new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "always()") }, + Expected = true + } + }; + foreach (var variableSet in variableSets) + { + _ec.Object.Result = null; -// // Act. -// await _stepsRunner.RunAsync( -// jobContext: _ec.Object, -// steps: variableSet.Select(x => x.Object).ToList()); + _ec.Setup(x => x.JobSteps).Returns(new Queue(variableSet.Step.Select(x => x.Object).ToList())); -// // Assert. -// Assert.Equal(TaskResult.Failed, _ec.Object.Result ?? TaskResult.Succeeded); -// } -// } -// } + // Act. + await _stepsRunner.RunAsync(jobContext: _ec.Object); -// private Mock CreateStep(TaskResult result, IExpressionNode condition, Boolean continueOnError = false) -// { -// // Setup the step. -// var step = new Mock(); -// step.Setup(x => x.Condition).Returns(condition); -// step.Setup(x => x.ContinueOnError).Returns(continueOnError); -// step.Setup(x => x.Enabled).Returns(true); -// step.Setup(x => x.RunAsync()).Returns(Task.CompletedTask); + // Assert. + Assert.Equal(2, variableSet.Step.Length); + variableSet.Step[0].Verify(x => x.RunAsync()); + variableSet.Step[1].Verify(x => x.RunAsync(), variableSet.Expected ? Times.Once() : Times.Never()); + } + } + } -// // Setup the step execution context. -// var stepContext = new Mock(); -// stepContext.SetupAllProperties(); -// stepContext.Setup(x => x.Variables).Returns(_variables); -// stepContext.Setup(x => x.ExpressionValues).Returns(_contexts); -// stepContext.Setup(x => x.Complete(It.IsAny(), It.IsAny(), It.IsAny())) -// .Callback((TaskResult? r, string currentOperation, string resultCode) => -// { -// if (r != null) -// { -// stepContext.Object.Result = r; -// } -// }); -// stepContext.Object.Result = result; -// step.Setup(x => x.ExecutionContext).Returns(stepContext.Object); + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task AlwaysMeansAlways() + { + using (TestHostContext hc = CreateTestContext()) + { + // Arrange. + var variableSets = new[] + { + new[] { CreateStep(TaskResult.Succeeded, "success()"), CreateStep(TaskResult.Succeeded, "always()") }, + new[] { CreateStep(TaskResult.Failed, "success()"), CreateStep(TaskResult.Succeeded, "always()") }, + new[] { CreateStep(TaskResult.Canceled, "success()"), CreateStep(TaskResult.Succeeded, "always()") } + }; + foreach (var variableSet in variableSets) + { + _ec.Object.Result = null; -// return step; -// } + _ec.Setup(x => x.JobSteps).Returns(new Queue(variableSet.Select(x => x.Object).ToList())); -// private string FormatSteps(IEnumerable> steps) -// { -// return String.Join( -// " ; ", -// steps.Select(x => String.Format( -// CultureInfo.InvariantCulture, -// "Returns={0},Condition=[{1}],ContinueOnError={2},Enabled={3}", -// x.Object.ExecutionContext.Result, -// x.Object.Condition, -// x.Object.ContinueOnError, -// x.Object.Enabled))); -// } -// } -// } + // Act. + await _stepsRunner.RunAsync(jobContext: _ec.Object); + + // Assert. + Assert.Equal(2, variableSet.Length); + variableSet[0].Verify(x => x.RunAsync()); + variableSet[1].Verify(x => x.RunAsync(), Times.Once()); + } + } + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public async Task TreatsConditionErrorAsFailure() + { + using (TestHostContext hc = CreateTestContext()) + { + var expressionManager = new Mock(); + expressionManager.Object.Initialize(hc); + hc.SetSingleton(expressionManager.Object); + expressionManager.Setup(x => x.Evaluate(It.IsAny(), It.IsAny(), It.IsAny())).Throws(new Exception()); + + // Arrange. + var variableSets = new[] + { + new[] { CreateStep(TaskResult.Succeeded, "success()") }, + new[] { CreateStep(TaskResult.Succeeded, "success()") }, + }; + foreach (var variableSet in variableSets) + { + _ec.Object.Result = null; + + _ec.Setup(x => x.JobSteps).Returns(new Queue(variableSet.Select(x => x.Object).ToList())); + + // Act. + await _stepsRunner.RunAsync(jobContext: _ec.Object); + + // Assert. + Assert.Equal(TaskResult.Failed, _ec.Object.Result ?? TaskResult.Succeeded); + } + } + } + + private Mock CreateStep(TaskResult result, string condition, Boolean continueOnError = false) + { + // Setup the step. + var step = new Mock(); + step.Setup(x => x.Condition).Returns(condition); + step.Setup(x => x.ContinueOnError).Returns(new BooleanToken(null, null, null, continueOnError)); + step.Setup(x => x.RunAsync()).Returns(Task.CompletedTask); + + // Setup the step execution context. + var stepContext = new Mock(); + stepContext.SetupAllProperties(); + stepContext.Setup(x => x.Variables).Returns(_variables); + stepContext.Setup(x => x.ExpressionValues).Returns(_contexts); + stepContext.Setup(x => x.JobContext).Returns(_jobContext); + stepContext.Setup(x => x.StepsContext).Returns(_stepContext); + stepContext.Setup(x => x.Complete(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((TaskResult? r, string currentOperation, string resultCode) => + { + if (r != null) + { + stepContext.Object.Result = r; + } + }); + stepContext.Object.Result = result; + step.Setup(x => x.ExecutionContext).Returns(stepContext.Object); + + return step; + } + + private string FormatSteps(IEnumerable> steps) + { + return String.Join( + " ; ", + steps.Select(x => String.Format( + CultureInfo.InvariantCulture, + "Returns={0},Condition=[{1}],ContinueOnError={2}", + x.Object.ExecutionContext.Result, + x.Object.Condition, + x.Object.ContinueOnError))); + } + } +} diff --git a/src/Test/L0/Worker/TaskCommandExtensionL0.cs b/src/Test/L0/Worker/TaskCommandExtensionL0.cs deleted file mode 100644 index e695fe09d..000000000 --- a/src/Test/L0/Worker/TaskCommandExtensionL0.cs +++ /dev/null @@ -1,181 +0,0 @@ -// using System; -// using System.Collections.Generic; -// using System.Runtime.CompilerServices; -// using GitHub.DistributedTask.WebApi; -// using GitHub.Runner.Worker; -// using Moq; -// using Xunit; - -// namespace GitHub.Runner.Common.Tests.Worker -// { -// public sealed class TaskCommandExtensionL0 -// { -// private TestHostContext _hc; -// private Mock _ec; -// private ServiceEndpoint _endpoint; - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointAuthParameter() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// commandExtension.Initialize(_hc); -// var cmd = new Command("task", "setEndpoint"); -// cmd.Data = "blah"; -// cmd.Properties.Add("field", "authParameter"); -// cmd.Properties.Add("id", Guid.Empty.ToString()); -// cmd.Properties.Add("key", "test"); - -// commandExtension.ProcessCommand(_ec.Object, cmd); - -// Assert.Equal(_endpoint.Authorization.Parameters["test"], "blah"); -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointDataParameter() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// var cmd = new Command("task", "setEndpoint"); -// cmd.Data = "blah"; -// cmd.Properties.Add("field", "dataParameter"); -// cmd.Properties.Add("id", Guid.Empty.ToString()); -// cmd.Properties.Add("key", "test"); - -// commandExtension.ProcessCommand(_ec.Object, cmd); - -// Assert.Equal(_endpoint.Data["test"], "blah"); -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointUrlParameter() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// var cmd = new Command("task", "setEndpoint"); -// cmd.Data = "http://blah/"; -// cmd.Properties.Add("field", "url"); -// cmd.Properties.Add("id", Guid.Empty.ToString()); - -// commandExtension.ProcessCommand(_ec.Object, cmd); - -// Assert.Equal(_endpoint.Url.ToString(), cmd.Data); -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointWithoutValue() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// var cmd = new Command("task", "setEndpoint"); -// Assert.Throws(() => commandExtension.ProcessCommand(_ec.Object, cmd)); -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointWithoutEndpointField() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// var cmd = new Command("task", "setEndpoint"); - -// Assert.Throws(() => commandExtension.ProcessCommand(_ec.Object, cmd)); -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointInvalidEndpointField() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// var cmd = new Command("task", "setEndpoint"); -// cmd.Properties.Add("field", "blah"); - -// Assert.Throws(() => commandExtension.ProcessCommand(_ec.Object, cmd)); -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointWithoutEndpointId() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// var cmd = new Command("task", "setEndpoint"); -// cmd.Properties.Add("field", "url"); - -// Assert.Throws(() => commandExtension.ProcessCommand(_ec.Object, cmd)); -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointInvalidEndpointId() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// var cmd = new Command("task", "setEndpoint"); -// cmd.Properties.Add("field", "url"); -// cmd.Properties.Add("id", "blah"); - -// Assert.Throws(() => commandExtension.ProcessCommand(_ec.Object, cmd)); -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointIdWithoutEndpointKey() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// var cmd = new Command("task", "setEndpoint"); -// cmd.Properties.Add("field", "authParameter"); -// cmd.Properties.Add("id", Guid.Empty.ToString()); - -// Assert.Throws(() => commandExtension.ProcessCommand(_ec.Object, cmd)); -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Worker")] -// public void SetEndpointUrlWithInvalidValue() -// { -// SetupMocks(); -// TaskCommandExtension commandExtension = new TaskCommandExtension(); -// var cmd = new Command("task", "setEndpoint"); -// cmd.Data = "blah"; -// cmd.Properties.Add("field", "url"); -// cmd.Properties.Add("id", Guid.Empty.ToString()); - -// Assert.Throws(() => commandExtension.ProcessCommand(_ec.Object, cmd)); -// } - -// private void SetupMocks([CallerMemberName] string name = "") -// { -// _hc = new TestHostContext(this, name); -// _ec = new Mock(); - -// _endpoint = new ServiceEndpoint() -// { -// Id = Guid.Empty, -// Url = new Uri("https://test.com"), -// Authorization = new EndpointAuthorization() -// { -// Scheme = "Test", -// } -// }; - -// _ec.Setup(x => x.Endpoints).Returns(new List { _endpoint }); -// } -// } -// }