Skip to content

Commit

Permalink
Run AspNetCore E2E tests with NET8 on server (#463)
Browse files Browse the repository at this point in the history
.NET8
  * Build with dotnet8 sdk
  * Run AspNetCore E2E tests with .NET8 on server
  * Run AspNetCore tests on .NET8

Test improvements
* improve test failure message from GetReferenceAssemblies
* Verify AspNetCore webserver is started before executing e2e tests
* Fix invalid handle from CrossProcessLoggingTests when debugger is attached

Build improvements
* Set MSBUILDDEBUGPATH to allow troubleshooting of build failures
* Stop installing dotnet (UseDotNet) for slightly faster build
* remove appveyor file
* Use msbuild directly in codeql
 * enable test diagnostics
  • Loading branch information
Daniel-Svensson committed Dec 13, 2023
1 parent 8f2b3a1 commit 3f7ddc0
Show file tree
Hide file tree
Showing 14 changed files with 100 additions and 76 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ jobs:
languages: ${{ matrix.language }}
queries: +security-and-quality

- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Add msbuild to PATH
uses: microsoft/[email protected]

- name: build
run: msbuild src\RiaServices.sln -restore /p:Configuration=Release -v:minimal -m

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
Expand Down
20 changes: 0 additions & 20 deletions appveyor.yml

This file was deleted.

52 changes: 31 additions & 21 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,31 @@ variables:
BuildConfiguration: 'release'
BuildPlatform: 'any cpu'
Solution: 'src\RiaServices.sln'
# Msbuild might create logs in the following directory in case some of the "tool" tests fail
MSBUILDDEBUGPATH: $(Build.ArtifactStagingDirectory)
# Define the following variable for the build pipeline in order to enable sonarcloud analysis
# sonarcloud-endpoint: 'sonarcloud.io'

steps:

# install dotnet 6 sdk so we can run tests against them
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '6.0.x'

# install dotet 7 sdk to allow compilation target
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '7.0.x'
# Uncomment below to install dotnet runtime and SDK if they stop beeing preinstalled
## install dotnet 6
#- task: UseDotNet@2
# inputs:
# packageType: 'runtime'
# version: '6.0.x'

## install dotnet 7
#- task: UseDotNet@2
# inputs:
# packageType: 'runtime'
# version: '7.0.x'

## install dotnet 8 sdk
#- task: UseDotNet@2
# inputs:
# packageType: 'sdk'
# version: '8.0.x'

- task: NuGetToolInstaller@1
inputs:
Expand Down Expand Up @@ -61,7 +70,8 @@ steps:
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
maximumCpuCount: true


# Load test databases and setup msbuild debug path so it becomes part of artifacts
- powershell: |
sqllocaldb start MSSQLLocalDB
if (-not $?) { write-error "failed to start MSSQLLocalDB" }
Expand All @@ -86,8 +96,9 @@ steps:
codeCoverageEnabled: true
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
diagnosticsEnabled: false
timeoutInMinutes: 15
# diagnosticsEnabled: false
timeoutInMinutes: 25
continueOnError: true

- task: VSTest@2
displayName: 'Run tests - net6'
Expand All @@ -99,15 +110,13 @@ steps:
!**\obj\**
runOnlyImpactedTests: false
# Needed to hardcode path to test adapters for NET48 tests
# pathtoCustomTestAdapters: '$(Build.SourcesDirectory)\src\OpenRiaServices.Server.UnitTesting\Test\bin\$(BuildConfiguration)\net6.0\'
runInParallel: true
# runSettingsFile: 'src\test.runsettings'
runSettingsFile: 'src\test.runsettings'
codeCoverageEnabled: true
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
diagnosticsEnabled: false
timeoutInMinutes: 15
# diagnosticsEnabled: true
timeoutInMinutes: 25

- task: SonarCloudAnalyze@1
displayName: 'Run Code Analysis'
Expand Down Expand Up @@ -142,8 +151,9 @@ steps:
inputs:
SourceFolder: '$(Agent.TempDirectory)'
Contents: |
**\*.dmp
TargetFolder: '$(build.artifactstagingdirectory)'
TestResults/*/*
**/*.diag
TargetFolder: '$(build.artifactstagingdirectory)/vstest'
condition: succeededOrFailed()

- task: PublishBuildArtifacts@1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>OpenRiaServices.Hosting.AspNetCore</RootNamespace>
<Version>1.0.0.0</Version>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
using System.IO.Pipes;
using System.Text;
using System.Threading;
using Microsoft.Win32.SafeHandles;

namespace OpenRiaServices.Tools.Logging;

Expand All @@ -78,6 +79,12 @@ public CrossProcessLoggingWriter(string pipeName)
_binaryWriter = new BinaryWriter(new BufferedStream(pipe), Encoding.Unicode);
}

public CrossProcessLoggingWriter(Microsoft.Win32.SafeHandles.SafePipeHandle pipeHandle)
{
var pipe = new AnonymousPipeClientStream(PipeDirection.Out, pipeHandle);
_binaryWriter = new BinaryWriter(new BufferedStream(pipe), Encoding.Unicode);
}

public bool HasLoggedErrors { get; private set; }

void ILoggingService.LogError(string message, string subcategory, string errorCode, string helpKeyword, string file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber)
Expand Down Expand Up @@ -168,6 +175,8 @@ public CrossProcessLoggingServer()

public string PipeName { get; }

public SafePipeHandle ClientSafePipeHandle => _pipe.ClientSafePipeHandle;

/// <summary>
/// Read logs and forwards them to <paramref name="logger"/>.
/// any exception will catched and logged
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class CrossProcessLoggingTests
public void LogsAreForwarded()
{
using var server = new CrossProcessLoggingServer();
using (var client = new CrossProcessLoggingWriter(server.PipeName))
using (var client = new CrossProcessLoggingWriter(server.ClientSafePipeHandle))
{
var log = (ILoggingService)client;
log.LogMessage("Message");
Expand Down Expand Up @@ -73,7 +73,7 @@ public void ExceptionsAreForwarded()
ex = e;
}

using (var client = new CrossProcessLoggingWriter(server.PipeName))
using (var client = new CrossProcessLoggingWriter(server.ClientSafePipeHandle))
{
var log = (ILoggingService)client;
log.LogException(ex);
Expand Down
11 changes: 4 additions & 7 deletions src/OpenRiaServices.Tools/Test/MsBuildHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Versioning;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
Expand Down Expand Up @@ -54,12 +52,11 @@ private static void GetReferenceAssemblies(string projectPath, IList<string> ass
//"AssignProjectConfiguration"
var results = project.Build(new string[] { "ResolveAssemblyReferences" }, new Microsoft.Build.Framework.ILogger[] { log });

Assert.AreEqual(null, results.Exception, "Build should not have exception result");
// Do early assert on log in case there was a task failure
if(results.OverallResult != BuildResultCode.Success)
Assert.AreEqual(string.Empty, string.Join("\n", log.Errors), "ResolveAssemblyReferences failed, se log");
Assert.AreEqual(BuildResultCode.Success, results.OverallResult, "ResolveAssemblyReferences failed");
Assert.AreEqual(string.Empty, string.Join("\n", log.Errors), "Task was successful, but there were errors logged");
if (results.OverallResult != BuildResultCode.Success || results.Exception is not null || log.Errors.Any())
{
Assert.Fail($"ResolveAssemblyReferences failed.\n Status {BuildResultCode.Success}.\n\nLog:\n {string.Join("\n", log.Errors)}\n\nException: {results.Exception}");
}

if (results.ResultsByTarget.TryGetValue("ResolveAssemblyReferences", out TargetResult resolveAssemblyReferences))
{
Expand Down
7 changes: 3 additions & 4 deletions src/RiaServices.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
..\.gitignore = ..\.gitignore
..\appveyor.yml = ..\appveyor.yml
..\azure-pipelines.yml = ..\azure-pipelines.yml
..\Changelog.md = ..\Changelog.md
Directory.Build.props = Directory.Build.props
Expand Down Expand Up @@ -150,13 +149,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCoreWebsite", "Test\A
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRiaServices.Hosting.AspNetCore.Test", "OpenRiaServices.Hosting.AspNetCore\Test\OpenRiaServices.Hosting.AspNetCore.Test\OpenRiaServices.Hosting.AspNetCore.Test.csproj", "{A9C063D1-4451-47C9-AACE-908FFC8C9F35}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRiaServices.Tools.CodeGenTask", "OpenRiaServices.Tools.CodeGenTask\OpenRiaServices.Tools.CodeGenTask.csproj", "{E0153323-9B1E-47EA-ACAD-E7A1E765001C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRiaServices.Tools.CodeGenTask", "OpenRiaServices.Tools.CodeGenTask\OpenRiaServices.Tools.CodeGenTask.csproj", "{E0153323-9B1E-47EA-ACAD-E7A1E765001C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EndToEnd", "EndToEnd", "{27DB096E-8794-4B9A-B3D0-AF74926DF9FD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRiaservices.EndToEnd.Wcf.Test", "Test\OpenRiaservices.EndToEnd.Wcf.Test\OpenRiaservices.EndToEnd.Wcf.Test.csproj", "{9428260A-EA94-430D-9A1A-CB9830B9E8EE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRiaservices.EndToEnd.Wcf.Test", "Test\OpenRiaservices.EndToEnd.Wcf.Test\OpenRiaservices.EndToEnd.Wcf.Test.csproj", "{9428260A-EA94-430D-9A1A-CB9830B9E8EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRiaservices.EndToEnd.AspNetCore.Test", "Test\OpenRiaservices.EndToEnd.AspNetCore.Test\OpenRiaservices.EndToEnd.AspNetCore.Test.csproj", "{17F902F4-7254-4FB9-9AF6-B3291B129B45}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRiaservices.EndToEnd.AspNetCore.Test", "Test\OpenRiaservices.EndToEnd.AspNetCore.Test\OpenRiaservices.EndToEnd.AspNetCore.Test.csproj", "{17F902F4-7254-4FB9-9AF6-B3291B129B45}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
2 changes: 1 addition & 1 deletion src/Test/AspNetCoreWebsite/AspNetCoreWebsite.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>disable</Nullable>
<ImplicitUsings>false</ImplicitUsings>
<NoWarn>$(NoWarn);CS0618</NoWarn>
Expand Down
40 changes: 28 additions & 12 deletions src/Test/OpenRiaservices.EndToEnd.AspNetCore.Test/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Net.Http;
using System.Threading;
using httpDomainClient::OpenRiaServices.Client.DomainClients;
using OpenRiaServices.Common.Test;
using System.Diagnostics;

namespace OpenRiaServices.Client.Test
Expand Down Expand Up @@ -66,17 +65,10 @@ private static void StartWebServer()
#else
string configuration = "Release";
#endif

#if NET80
string targetFramework = "net8.0";
#else
string targetFramework = "net6.0";
#endif

string webSitePath = Path.GetFullPath(Path.Combine(projectPath, @$"../AspNetCoreWebsite/bin/{configuration}/{targetFramework}/"));

string processPath = webSitePath + ProcessName + ".exe";
//webSitePath = Path.GetFullPath(Path.Combine(projectPath, @"../AspNetCoreWebsite"));

if (!Directory.Exists(webSitePath))
throw new FileNotFoundException($"Website not found at {webSitePath}");

Expand All @@ -86,6 +78,7 @@ private static void StartWebServer()
var websites = Process.GetProcessesByName(ProcessName);
if (websites.Any())
{
Console.WriteLine("AssemblyInitialize: Webserver process was already started, not starting anything");
// Already running do nothing
}
else
Expand All @@ -96,12 +89,35 @@ private static void StartWebServer()
startInfo.WorkingDirectory = Path.GetFullPath(Path.Combine(projectPath, @"../AspNetCoreWebsite/"));
s_aspNetCoreSite = Process.Start(startInfo);

// TODO: Wait for standard output or similar instead such as makin a successfull (GET "/"))
Thread.Sleep(TimeSpan.FromSeconds(10));
Console.WriteLine("AssemblyInitialize: Started webserver with PID {0}", s_aspNetCoreSite.Id);
}

// Wait for a successfull (GET "/") to succeed so we know webserver has started
using HttpClient httpClient = new HttpClient();
Stopwatch stopwatch = Stopwatch.StartNew();
do
{
try
{
var res = httpClient.GetAsync("http://localhost:5246/").GetAwaiter().GetResult();
if (res.IsSuccessStatusCode)
{
Console.WriteLine("AssemblyInitialize: Webserver started");
return;
}
}
catch (Exception)
{
// Ignore error
}

if (s_aspNetCoreSite.HasExited)
throw new Exception("Website stopped");
}

Thread.Sleep(TimeSpan.FromSeconds(1));
} while (stopwatch.Elapsed <= TimeSpan.FromMinutes(1));

throw new TimeoutException("webserver did not respond to '/' in 1 minute");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
<Private>false</Private>
<ExcludeAssets>All</ExcludeAssets>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<SetTargetFramework>TargetFramework=net6.0</SetTargetFramework>
<SetTargetFramework>TargetFramework=net8.0</SetTargetFramework>
</ProjectReference>
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ public void OnCompleted(Action continuation)

public void UnsafeOnCompleted(Action continuation)
{
if (_operation.IsComplete)
{
continuation();
return;
}

// Capture syncContext and scheduler from await location
var syncContext = SynchronizationContext.Current;
TaskScheduler scheduler;
Expand Down
2 changes: 1 addition & 1 deletion src/global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "7.0.200",
"version": "8.0.100",
"rollForward": "major"
}
}
12 changes: 8 additions & 4 deletions src/test.runsettings
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,23 @@
</CodeCoverage>
</Configuration>
</DataCollector>
<DataCollector friendlyName="blame" enabled="True">
<Configuration>
<CollectDump DumpType="Full" />
<CollectDumpOnTestSessionHang TestTimeout="20min" HangDumpType="Full" />
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>

<!-- Parameters used by tests at run time -->
<TestRunParameters>
<Parameter name="webAppUrl" value="http://localhost" />
<Parameter name="webAppUserName" value="Admin" />
<Parameter name="webAppPassword" value="Password" />
<!--<Parameter name="webAppUserName" value="Admin" />-->
</TestRunParameters>

<!-- Adapter Specific sections -->

<!-- MSTest adapter -->
<!-- MSTest adapter : https://learn.microsoft.com/sv-se/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file?view=vs-2022#mstest-element -->
<MSTest>
<!--
<MapInconclusiveToFailed>True</MapInconclusiveToFailed>
Expand Down

0 comments on commit 3f7ddc0

Please sign in to comment.