Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f3aa7c9
build: re-create the bug by building on windows
wonderbird Feb 17, 2021
4185ba3
build: setup tmate debugging session
wonderbird Feb 17, 2021
ca60337
chore: add logging to unit test failing under windows
wonderbird Feb 17, 2021
760f3e9
fix: consider the windows path separator - backslash - in test expect…
wonderbird Feb 17, 2021
306fc6b
revert: chore: add logging to unit test failing under windows
wonderbird Feb 17, 2021
f7a00ab
revert: build: setup tmate debugging session
wonderbird Feb 17, 2021
695c1d4
test(acceptance): enhance logging
wonderbird Feb 18, 2021
b3b50af
build: separate unit tests run from acceptance test run
wonderbird Feb 18, 2021
b1b0366
build: setup tmate debugging session
wonderbird Feb 18, 2021
940c9ec
revert: build: setup tmate debugging session
wonderbird Feb 18, 2021
74c7269
revert: build: separate unit tests run from acceptance test run
wonderbird Feb 18, 2021
6c717b0
test: test output of taskkill on windows
wonderbird Feb 18, 2021
e4d775f
test(acceptance): deactivate acceptance tests temporarily
wonderbird Feb 19, 2021
8a90eb0
build: setup tmate debugging session
wonderbird Feb 19, 2021
554ef15
build: setup tmate debugging session
wonderbird Feb 19, 2021
5060bc0
revert: build: setup tmate debugging session
wonderbird Feb 19, 2021
3958f8d
test: run all tests sequentially
wonderbird Feb 19, 2021
280180c
build: fix failed dotnet restore and dotnet build
wonderbird Feb 19, 2021
c08809f
test(smoketest): fix when run unter windows
wonderbird Feb 19, 2021
00c5e84
revert: test(acceptance): deactivate acceptance tests temporarily
wonderbird Feb 19, 2021
e6b32e0
test(consumer): create consumer driven tests for kill and taskkill sy…
wonderbird Feb 19, 2021
121b4b7
refactor(consumer driven tests): extract ProcessRunner class
wonderbird Feb 19, 2021
e7e7e52
docs: add explanation for serializing tests
wonderbird Feb 19, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ on:
branches: [ main ]
pull_request:
branches: [ main ]

env:
packageVersionPrefix: ${{ '0.0.' }}
packageVersionSuffixForFeatureBranch: ${{ '-alpha' }}
packageVersionSuffixForMainBranch: ${{ '' }}

jobs:
build-and-test:
runs-on: ubuntu-latest
strategy:
matrix:
# os: [ macos-latest, ubuntu-latest, windows-latest ]
os: [ windows-latest ]
runs-on: ${{ matrix.os }}
name: Build and test

steps:
- uses: actions/checkout@v2

- name: Setup environment variables (main branch)
if: github.ref == 'refs/heads/main'
run: echo "packageVersion=${{ env.packageVersionPrefix }}${{ github.run_number }}${{ env.packageVersionSuffixForMainBranch }}" >> $GITHUB_ENV
Expand All @@ -38,13 +41,17 @@ jobs:
dotnet tool install --global dotnet-reportgenerator-globaltool

- name: Install dependencies
run: dotnet restore
run: dotnet restore RemoteControlledProcess.sln

- name: Build
run: dotnet build --configuration Debug --no-restore
run: dotnet build --configuration Debug --no-restore RemoteControlledProcess.sln

- name: Test with coverage
run: dotnet test --no-restore --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput='./TestResults/coverage.cobertura.xml'
- name: Run tests sequentially with coverage
# By default tests run in parallel.
# Coverlet instrumentation requires running tests sequentially.
# Thus, using a separate project and the /p:BuildInParallel switch to serialize the test runs
# See also: https://github.com/nunit/nunit3-vs-adapter/issues/657
run: dotnet test --no-restore --verbosity normal /p:BuildInParallel=false /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput='./TestResults/coverage.cobertura.xml' RemoteControlledProcess.Tests.proj

- name: Build NuGet package
run: |
Expand All @@ -54,7 +61,7 @@ jobs:
- name: Test NuGet package
run: ./smoketest.sh
working-directory: RemoteControlledProcess.Nupkg.Tests

- name: Generate coverage reports
run: reportgenerator "-reports:RemoteControlledProcess.Acceptance.Tests/TestResults/*.xml;RemoteControlledProcess.Unit.Tests/TestResults/*.xml" \
"-targetdir:report" \
Expand All @@ -78,9 +85,9 @@ jobs:
publish-reports:
runs-on: ubuntu-latest
name: Publish coverage reports

needs: build-and-test

steps:
# the repository is required by codeclimate-action
- uses: actions/checkout@v2
Expand All @@ -90,7 +97,7 @@ jobs:
with:
name: coverage-reports
path: coverage-reports

- name: Publish coverage report to coveralls.io
uses: coverallsapp/github-action@master
with:
Expand All @@ -107,7 +114,7 @@ jobs:
publish-nuget:
runs-on: ubuntu-latest
name: Publish NuGet package

needs: publish-reports

steps:
Expand All @@ -116,7 +123,7 @@ jobs:
with:
name: nuget-package
path: nuget-package

- name: Identify package version
run: cat nuget-package/VERSION.txt >> $GITHUB_ENV

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
using Xunit;
using Xunit.Abstractions;

namespace RemoteControlledProcess.Acceptance.Tests.Features
{
public class SmokeTests
{
private readonly ITestOutputHelper _testOutputHelper;

public SmokeTests(ITestOutputHelper testOutputHelper) => _testOutputHelper = testOutputHelper;

/// <summary>
/// SmokeTest used to verify that the NuGet package has been created correctly.
/// </summary>
Expand All @@ -18,8 +23,10 @@ public void SmokeTest()
processWrapper.Start();
processWrapper.ShutdownGracefully();
processWrapper.ForceTermination();

var output = processWrapper.ReadOutput();
Assert.Contains("STOP", output);
_testOutputHelper.WriteLine($"Process produced the following output: \"{output}\"");
Assert.Contains("Process ID", output);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage(
"Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores",
Justification = "Unit test naming follows https://osherove.com/blog/2005/4/3/naming-standards-for-unit-tests.html",
Scope = "namespaceanddescendants", Target = "RemoteControlledProcess.ConsumerDriven.Tests")]
28 changes: 28 additions & 0 deletions RemoteControlledProcess.ConsumerDriven.Tests/KillTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using Xunit;
using Xunit.Abstractions;

namespace RemoteControlledProcess.ConsumerDriven.Tests
{
public class KillTests
{
private readonly ITestOutputHelper _testOutputHelper;

public KillTests(ITestOutputHelper testOutputHelper) => _testOutputHelper = testOutputHelper;

[Fact]
public void RunKillProcess_NotOnWindows_ShowsProcessOutput()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
_testOutputHelper.WriteLine($"Windows OS detected. Skipping test RunKillProcess_NotOnWindows_ShowsProcessOutput.");
return;
}

var output = ProcessRunner.RunProcess("kill", "-l", _testOutputHelper);

Assert.Contains("term", output);
}
}
}
29 changes: 29 additions & 0 deletions RemoteControlledProcess.ConsumerDriven.Tests/ProcessRunner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Diagnostics;
using Xunit.Abstractions;

namespace RemoteControlledProcess.ConsumerDriven.Tests
{
public static class ProcessRunner
{
public static string RunProcess(string processName, string arguments, ITestOutputHelper testOutputHelper)
{
var processStartInfo = new ProcessStartInfo(processName)
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
Arguments = arguments
};

var process = new Process { StartInfo = processStartInfo };
process.Start();
process.WaitForExit(30000);

var output = process.StandardOutput.ReadToEnd();
testOutputHelper.WriteLine($"Process produced the following output: \"{output}\"");

return output;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\RemoteControlledProcess\RemoteControlledProcess.csproj" />
</ItemGroup>

</Project>
29 changes: 29 additions & 0 deletions RemoteControlledProcess.ConsumerDriven.Tests/TaskkillTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using Xunit;
using Xunit.Abstractions;

namespace RemoteControlledProcess.ConsumerDriven.Tests
{
public class TaskkillTests
{
private ITestOutputHelper _testOutputHelper;

public TaskkillTests(ITestOutputHelper testOutputHelper) => _testOutputHelper = testOutputHelper;

[Fact]
public void RunTaskkillProcess_OnWindows_ShowsProcessOutput()
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
_testOutputHelper.WriteLine($"Non-Windows OS detected. Skipping test RunTaskkillProcess_OnWindows_ShowsProcessOutput.");
return;
}

var output = ProcessRunner.RunProcess("taskkill", "/?", _testOutputHelper);

Assert.Contains("TASKKILL", output);
Assert.Contains("/PID", output);
}
}
}
5 changes: 5 additions & 0 deletions RemoteControlledProcess.Tests.proj
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.Build.Traversal/2.0.24">
<ItemGroup>
<ProjectReference Include="**\*.*proj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class ExceptionReporterExtensionTests

[Theory]
[InlineData(0,
"Unhandled exception in .*RemoteControlledProcess.Unit.Tests/ExceptionReporterExtensionTests.cs:[0-9]+")]
@"Unhandled exception in .*RemoteControlledProcess\.Unit\.Tests[\/\\]ExceptionReporterExtensionTests\.cs:[0-9]+")]
[InlineData(1, ExceptionMessage)]
public void Write_CalledInCatchBlock_WrittenMessagesMatch(int invocationIndex, string expectedMessageRegex)
{
Expand Down Expand Up @@ -51,7 +51,7 @@ public void Log_CalledInCatchBlock_LogsCriticalMessageWithExpectedRegex()

// Assert
var expectedMessageRegex =
"Unhandled exception in .*RemoteControlledProcess.Unit.Tests/ExceptionReporterExtensionTests.cs:[0-9]+";
@"Unhandled exception in .*RemoteControlledProcess\.Unit\.Tests[\/\\]ExceptionReporterExtensionTests\.cs:[0-9]+";
var actualLogLevel = (LogLevel)loggerMock.Invocations[0].Arguments[0];
var actualMessage = loggerMock.Invocations[0].Arguments[2].ToString();
Assert.Equal(LogLevel.Critical, actualLogLevel);
Expand Down
15 changes: 15 additions & 0 deletions RemoteControlledProcess.sln
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "misc", "misc", "{86E95D10-0
run-application.bat = run-application.bat
run-application.sh = run-application.sh
Nuget-OfficialOnly.config = Nuget-OfficialOnly.config
RemoteControlledProcess.Tests.proj = RemoteControlledProcess.Tests.proj
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteControlledProcess.Application", "RemoteControlledProcess.Application\RemoteControlledProcess.Application.csproj", "{5122B0AC-FAD4-44F4-B372-C5A6AED29E22}"
Expand All @@ -32,6 +33,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RemoteControlledProcess.Nup
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteControlledProcess.Unit.Tests", "RemoteControlledProcess.Unit.Tests\RemoteControlledProcess.Unit.Tests.csproj", "{7BC3300D-4599-409C-9839-A69E6E66CD7F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteControlledProcess.ConsumerDriven.Tests", "RemoteControlledProcess.ConsumerDriven.Tests\RemoteControlledProcess.ConsumerDriven.Tests.csproj", "{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -90,6 +93,18 @@ Global
{7BC3300D-4599-409C-9839-A69E6E66CD7F}.Release|x64.Build.0 = Release|Any CPU
{7BC3300D-4599-409C-9839-A69E6E66CD7F}.Release|x86.ActiveCfg = Release|Any CPU
{7BC3300D-4599-409C-9839-A69E6E66CD7F}.Release|x86.Build.0 = Release|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Debug|Any CPU.Build.0 = Debug|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Debug|x64.ActiveCfg = Debug|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Debug|x64.Build.0 = Debug|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Debug|x86.ActiveCfg = Debug|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Debug|x86.Build.0 = Debug|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Release|Any CPU.ActiveCfg = Release|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Release|Any CPU.Build.0 = Release|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Release|x64.ActiveCfg = Release|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Release|x64.Build.0 = Release|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Release|x86.ActiveCfg = Release|Any CPU
{288D6EDE-DC2C-4EE7-A3BA-7FE605865413}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
8 changes: 6 additions & 2 deletions RemoteControlledProcess/ProcessWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

namespace RemoteControlledProcess
{
// TODO: Double check whether serializing tests is really required - see dotnet.yml

public sealed class ProcessWrapper : IDisposable
{
private readonly string _appDir;
Expand Down Expand Up @@ -233,8 +235,10 @@ private void WaitForProcessExit()
{
TestOutputHelper?.WriteLine("Waiting for process to shutdown ...");
_process.WaitForExit(2000);
TestOutputHelper?.WriteLine($"Process {_appProjectName} has " + (_process.HasExited ? "" : "NOT ") +
"completed.");

var processDescription = IsCoverletEnabled ? $"coverlet({_appProjectName})" : _appProjectName;
var conditionalNot = _process.HasExited ? "" : "NOT ";
TestOutputHelper?.WriteLine($"Process {processDescription} has {conditionalNot}completed.");
}

public void ForceTermination()
Expand Down