Skip to content

Commit a9328b1

Browse files
authored
chore: implement integration testing (#124)
* some setup * make it build and execute without AOT * at this moment - i dont know * minimal assembly references * bump packages and then it does not work still... * do it iteratively * move pieces around * make it work with executable assembly! * omg it works. * use existing local machine table name * record stack traces * remove package versions * refactor dependencies * YES!!! YES!!! YES!!! YES!!! YES!!! YES!!! YES!!! * fix dbstring global namespace + adjust test for DbString * and run tests for new proj * last minute review * rollback package updates (they break tests) * remove coverlet collector * use sln * internal visible to * try specific routes * dont build it * try with ubuntu agents * rollback CI\CD + create another for integrations on ubuntu * fix for dbstring + rename CI * debug test * fix naming * try publish directory * move item group * get logs from build * maybe slash can fix it? * remove detailed verbosity * . * always? * test on wsl * build only test proj * move it to integration directly * give me logs * dont use copy at all * cleanup debug CI * move to csproj
1 parent 21b383a commit a9328b1

22 files changed

+542
-44
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Integration Tests
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [ main ]
7+
pull_request:
8+
branches: [ main ]
9+
10+
jobs:
11+
build:
12+
13+
runs-on: ubuntu-20.04
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
with:
18+
fetch-depth: 0 # depth is needed for nbgv
19+
20+
- name: Setup .NET
21+
uses: actions/setup-dotnet@v1
22+
with:
23+
dotnet-version: |
24+
6.0.x
25+
8.0.x
26+
include-prerelease: true
27+
28+
- name: Build
29+
run: dotnet build Dapper.AOT.sln -c Debug
30+
31+
- name: E2E Tests
32+
run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --no-build --verbosity normal -c Debug

.github/workflows/dotnet.yml

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,40 @@ jobs:
1313
runs-on: windows-latest
1414

1515
steps:
16-
- uses: actions/checkout@v2
17-
with:
18-
fetch-depth: 0 # depth is needed for nbgv
19-
20-
- name: Setup .NET
21-
uses: actions/setup-dotnet@v1
22-
with:
23-
dotnet-version: |
24-
6.0.x
25-
8.0.x
26-
include-prerelease: true
27-
28-
- uses: dotnet/nbgv@master
29-
with:
30-
setAllVars: true
31-
32-
- name: Restore dependencies
33-
run: dotnet restore Build.csproj
34-
35-
- name: Purge
36-
run: del src/Dapper.*/bin/Release/Dapper.*.nupkg
37-
38-
- name: Build
39-
run: dotnet build Build.csproj --no-restore -c Release
40-
41-
- name: Test
42-
run: dotnet test Build.csproj --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration
43-
44-
- name: Pack
45-
if: ${{ success() && !github.base_ref }}
46-
run: dotnet pack src/Dapper.AOT/Dapper.AOT.csproj --no-build --verbosity normal -c Release
47-
48-
- name: Push to MyGet
49-
if: ${{ success() && !github.base_ref }}
50-
run: dotnet nuget push src/Dapper.*/bin/Release/Dapper.*.nupkg --source https://www.myget.org/F/dapper/api/v2/package --api-key "$env:MYGETAPIKEY"
51-
env:
52-
MYGETAPIKEY: ${{ secrets.MYGETAPIKEY }}
16+
- uses: actions/checkout@v2
17+
with:
18+
fetch-depth: 0 # depth is needed for nbgv
19+
20+
- name: Setup .NET
21+
uses: actions/setup-dotnet@v1
22+
with:
23+
dotnet-version: |
24+
6.0.x
25+
8.0.x
26+
include-prerelease: true
27+
28+
- uses: dotnet/nbgv@master
29+
with:
30+
setAllVars: true
31+
32+
- name: Restore dependencies
33+
run: dotnet restore Build.csproj
34+
35+
- name: Purge
36+
run: del src/Dapper.*/bin/Release/Dapper.*.nupkg
37+
38+
- name: Build
39+
run: dotnet build Build.csproj --no-restore -c Release
40+
41+
- name: Test
42+
run: dotnet test Build.csproj --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration
43+
44+
- name: Pack
45+
if: ${{ success() && !github.base_ref }}
46+
run: dotnet pack src/Dapper.AOT/Dapper.AOT.csproj --no-build --verbosity normal -c Release
47+
48+
- name: Push to MyGet
49+
if: ${{ success() && !github.base_ref }}
50+
run: dotnet nuget push src/Dapper.*/bin/Release/Dapper.*.nupkg --source https://www.myget.org/F/dapper/api/v2/package --api-key "$env:MYGETAPIKEY"
51+
env:
52+
MYGETAPIKEY: ${{ secrets.MYGETAPIKEY }}

Dapper.AOT.sln

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1414
Directory.Build.props = Directory.Build.props
1515
Directory.Packages.props = Directory.Packages.props
1616
.github\workflows\dotnet.yml = .github\workflows\dotnet.yml
17+
.github\workflows\dotnet-integration.yml = .github\workflows\dotnet-integration.yml
1718
global.json = global.json
1819
nuget.config = nuget.config
1920
README.md = README.md
@@ -40,6 +41,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "docs", "docs\docs.csproj",
4041
EndProject
4142
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UsageVanilla", "test\UsageVanilla\UsageVanilla.csproj", "{840EA1CA-62FF-409E-89F5-CD3BB269BAE3}"
4243
EndProject
44+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration.Executables", "test\Dapper.AOT.Test.Integration.Executables\Dapper.AOT.Test.Integration.Executables.csproj", "{9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}"
45+
EndProject
46+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration", "test\Dapper.AOT.Test.Integration\Dapper.AOT.Test.Integration.csproj", "{CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}"
47+
EndProject
4348
Global
4449
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4550
Debug|Any CPU = Debug|Any CPU
@@ -78,6 +83,14 @@ Global
7883
{840EA1CA-62FF-409E-89F5-CD3BB269BAE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
7984
{840EA1CA-62FF-409E-89F5-CD3BB269BAE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
8085
{840EA1CA-62FF-409E-89F5-CD3BB269BAE3}.Release|Any CPU.Build.0 = Release|Any CPU
86+
{9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
87+
{9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
88+
{9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
89+
{9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Release|Any CPU.Build.0 = Release|Any CPU
90+
{CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
91+
{CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
92+
{CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
93+
{CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Release|Any CPU.Build.0 = Release|Any CPU
8194
EndGlobalSection
8295
GlobalSection(SolutionProperties) = preSolution
8396
HideSolutionNode = FALSE
@@ -91,6 +104,8 @@ Global
91104
{A77B633C-573E-43CD-85A4-8063B33143B4} = {FE215D4B-811B-47BB-9F05-6382DD1C6729}
92105
{C6527566-38F4-43CC-9E0E-91C4B8854774} = {1135D4FD-770E-41DF-920B-A8F75E42A832}
93106
{840EA1CA-62FF-409E-89F5-CD3BB269BAE3} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8}
107+
{9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8}
108+
{CAB51448-4F0D-497B-A035-2B7ACB2DD9EB} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8}
94109
EndGlobalSection
95110
GlobalSection(ExtensibilityGlobals) = postSolution
96111
SolutionGuid = {A89CDAFA-494F-4168-9648-1138BA738D43}

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.7.2" />
1414
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.XUnit" Version="1.1.1" />
1515
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing.XUnit" Version="1.1.1" />
16+
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
1617
<!-- 4.8 would be nice, but: let's try to offer down-level compiler support -->
1718
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="[4.4.0]" />
1819
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic.Analyzer.Testing.XUnit" Version="1.1.1" />

src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
using System.Diagnostics;
1717
using System.Globalization;
1818
using System.Linq;
19-
using System.Runtime.InteropServices.ComTypes;
2019
using System.Text;
2120
using System.Threading;
2221
using static Dapper.Internal.Inspection;
@@ -26,12 +25,33 @@ namespace Dapper.CodeAnalysis;
2625
[Generator(LanguageNames.CSharp), DiagnosticAnalyzer(LanguageNames.CSharp)]
2726
public sealed partial class DapperInterceptorGenerator : InterceptorGeneratorBase
2827
{
28+
private readonly bool _withInterceptionRecording = false;
29+
2930
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => DiagnosticsBase.All<Diagnostics>();
3031

3132
#pragma warning disable CS0067 // unused; retaining for now
3233
public event Action<string>? Log;
3334
#pragma warning restore CS0067
3435

36+
/// <summary>
37+
/// Creates an interceptor generator for Dapper
38+
/// </summary>
39+
public DapperInterceptorGenerator()
40+
{
41+
}
42+
43+
/// <summary>
44+
/// Creates an interceptor generator for Dapper used for Tests.
45+
/// </summary>
46+
/// <note>
47+
/// It will insert very specific call with known method name.
48+
/// Users will not have a reference to inserted assembly code, therefore: don't make it public
49+
/// </note>
50+
internal DapperInterceptorGenerator(bool withInterceptionRecording)
51+
{
52+
_withInterceptionRecording = withInterceptionRecording;
53+
}
54+
3555
public override void Initialize(IncrementalGeneratorInitializationContext context)
3656
{
3757
var nodes = context.SyntaxProvider.CreateSyntaxProvider(PreFilter, Parse)
@@ -360,6 +380,13 @@ internal void Generate(in GenerateState ctx)
360380

361381
sb.NewLine();
362382

383+
if (_withInterceptionRecording)
384+
{
385+
sb.Append("// record interception for tests assertions").NewLine();
386+
sb.Append("global::Dapper.AOT.Test.Integration.Executables.Recording.InterceptorRecorderResolver.Resolve().Record();").NewLine();
387+
sb.NewLine();
388+
}
389+
363390
if (flags.HasAny(OperationFlags.GetRowParser))
364391
{
365392
WriteGetRowParser(sb, resultType, readers);

src/Dapper.AOT.Analyzers/Dapper.AOT.Analyzers.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,8 @@
5959
<DependentUpon>DapperAnalyzer.cs</DependentUpon>
6060
</Compile>
6161
</ItemGroup>
62+
63+
<ItemGroup>
64+
<InternalsVisibleTo Include="Dapper.AOT.Test.Integration, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a17ba361da0990b3da23f3c20f2a002242397b452a28f27832d61d49f35edb54a68b98d98557b8a02be79be42142339c7861af309c8917dee972775e2c358dd6b96109a9147987652b25b8dc52e7f61f22a755831674f0a3cea17bef9abb6b23ef1856a02216864a1ffbb04a4c549258d32ba740fe141dad2f298a8130ea56d0" />
65+
</ItemGroup>
6266
</Project>

src/Dapper.AOT.Analyzers/Internal/Inspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ public DapperSpecialType DapperSpecialType
505505
ContainingNamespace:
506506
{
507507
Name: "Dapper",
508-
IsGlobalNamespace: true
508+
ContainingNamespace.IsGlobalNamespace: true
509509
}
510510
}) return DapperSpecialType.DbString;
511511

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFrameworks>net8.0;net6.0;net48</TargetFrameworks>
4+
<RootNamespace>Dapper.AOT.Test.Integration.Executables</RootNamespace>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Dapper" Condition="'$(TargetFramework)' == 'net6.0'" />
9+
<PackageReference Include="Dapper.StrongName" Condition="'$(TargetFramework)'=='net48'" />
10+
<PackageReference Include="Dapper" Condition="'$(TargetFramework)' == 'net8.0'" />
11+
12+
<ProjectReference Include="..\..\src\Dapper.AOT.Analyzers\Dapper.AOT.Analyzers.csproj" />
13+
<ProjectReference Include="..\..\src\Dapper.AOT\Dapper.AOT.csproj" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Linq;
4+
using System.Text;
5+
using Dapper.AOT.Test.Integration.Executables.Recording;
6+
using Dapper.CodeAnalysis;
7+
8+
namespace Dapper.AOT.Test.Integration.Executables;
9+
10+
public class ExceptedCodeInterceptorRecorder<TExecutable> : IInterceptorRecorder
11+
{
12+
readonly string expectedFileName;
13+
14+
public ExceptedCodeInterceptorRecorder(string expectedFileName)
15+
{
16+
this.expectedFileName = expectedFileName ?? throw new ArgumentNullException(nameof(expectedFileName));
17+
}
18+
19+
public bool WasCalled { get; private set; }
20+
public string? Diagnostics { get; private set; }
21+
22+
public void Record()
23+
{
24+
WasCalled = true;
25+
var diagnostics = new StringBuilder();
26+
27+
var stackTrace = new StackTrace(fNeedFileInfo: true);
28+
var recentFrames = stackTrace.GetFrames().Take(15).ToList(); // we dont need everything
29+
30+
var userCodeFrameIndex = recentFrames.FindIndex(frame =>
31+
frame.GetFileName()?.Contains(expectedFileName) == true && frame.GetMethod()?.Name.Equals(nameof(IExecutable<TExecutable>.Execute)) == true);
32+
if (userCodeFrameIndex == -1)
33+
{
34+
diagnostics.AppendLine("- User code execution is not found");
35+
}
36+
37+
var dapperInterceptionFrameIndex = recentFrames.FindIndex(frame =>
38+
frame.GetFileName()?.Contains(".generated.cs") == true && frame.GetFileName()?.Contains(nameof(DapperInterceptorGenerator)) == true);
39+
if (dapperInterceptionFrameIndex == -1)
40+
{
41+
diagnostics.AppendLine("- User code execution is not found");
42+
}
43+
44+
if (userCodeFrameIndex < dapperInterceptionFrameIndex)
45+
{
46+
diagnostics.AppendLine("- User code call should be higher (executed before) on the stack trace than intercepted code");
47+
}
48+
49+
Diagnostics = diagnostics.ToString();
50+
}
51+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using System.Data;
2+
3+
namespace Dapper.AOT.Test.Integration.Executables;
4+
5+
public interface IExecutable<T>
6+
{
7+
public T Execute(IDbConnection connection);
8+
}

0 commit comments

Comments
 (0)