Skip to content

Commit b240d4f

Browse files
authored
Merge pull request #1 from soernt/develop
Develop
2 parents c422b8e + 3a9dfdb commit b240d4f

File tree

59 files changed

+29859
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+29859
-0
lines changed

source/.gitignore

Lines changed: 454 additions & 0 deletions
Large diffs are not rendered by default.

source/Directory.Build.targets

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<Project>
2+
3+
<!-- *************************************************
4+
1. Pinning Package Versions
5+
************************************************** -->
6+
<ItemGroup>
7+
<!-- Application -->
8+
<PackageReference Update="Marten" Version="4.3.1"/>
9+
<PackageReference Update="Microsoft.Extensions.Identity.Core" Version="6.0.1" />
10+
<PackageReference Update="Microsoft.Extensions.Identity.Stores" Version="6.0.1" />
11+
<!-- <PackageReference Update="Microsoft.Extensions.Identity.UI" Version="6.0.1" />-->
12+
13+
<!-- Testing -->
14+
<PackageReference Update="DotNet.Testcontainers" Version="1.5.0" />
15+
<PackageReference Update="Microsoft.AspNetCore.Identity.Specification.Tests" Version="5.0.13" />
16+
17+
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
18+
<PackageReference Update="xunit" Version="2.4.1"/>
19+
<PackageReference Update="xunit.runner.visualstudio" Version="2.4.3"/>
20+
<PackageReference Update="coverlet.collector" Version="3.1.0"/>
21+
22+
</ItemGroup>
23+
24+
25+
<!-- *************************************************
26+
2. Import these Packages into every Solution
27+
************************************************** -->
28+
<ItemGroup>
29+
30+
<PackageReference Include="Meziantou.Analyzer" Version="1.0.675">
31+
<PrivateAssets>all</PrivateAssets>
32+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
33+
</PackageReference>
34+
35+
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.0.64">
36+
<PrivateAssets>all</PrivateAssets>
37+
</PackageReference>
38+
39+
</ItemGroup>
40+
41+
<!-- *************************************************
42+
2. Import these Packages into every Solution
43+
************************************************** -->
44+
<PropertyGroup>
45+
<LangVersion>10.0</LangVersion>
46+
<Nullable>enable</Nullable>
47+
<ImplicitUsings>enable</ImplicitUsings>
48+
</PropertyGroup>
49+
50+
<PropertyGroup>
51+
<AnalysisModeReliability>true</AnalysisModeReliability>
52+
<EnableNETAnalyzers>true</EnableNETAnalyzers>
53+
<AnalysisLevel>latest</AnalysisLevel>
54+
</PropertyGroup>
55+
56+
</Project>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Marten" />
11+
<PackageReference Include="DotNet.Testcontainers" />
12+
13+
<PackageReference Include="Microsoft.AspNetCore.Identity.Specification.Tests" />
14+
<PackageReference Include="Microsoft.NET.Test.Sdk" />
15+
<PackageReference Include="xunit" />
16+
<PackageReference Include="xunit.runner.visualstudio">
17+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
18+
<PrivateAssets>all</PrivateAssets>
19+
</PackageReference>
20+
<PackageReference Include="coverlet.collector">
21+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
22+
<PrivateAssets>all</PrivateAssets>
23+
</PackageReference>
24+
</ItemGroup>
25+
26+
<ItemGroup>
27+
<ProjectReference Include="..\Marten.AspNetCore.Identity\Marten.AspNetCore.Identity.csproj" />
28+
</ItemGroup>
29+
30+
</Project>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
using System.Linq.Expressions;
2+
using Marten.AspNetCore.Identity.Configuration;
3+
using Marten.AspNetCore.Identity.Models;
4+
using Marten.AspNetCore.Identity.RoleStore;
5+
using Marten.AspNetCore.Identity.Tests.Support;
6+
using Marten.AspNetCore.Identity.UserStore;
7+
using Microsoft.AspNetCore.Identity;
8+
using Microsoft.AspNetCore.Identity.Test;
9+
using Microsoft.Extensions.DependencyInjection;
10+
using Xunit;
11+
using Xunit.Abstractions;
12+
13+
namespace Marten.AspNetCore.Identity.Tests
14+
{
15+
/// <summary>
16+
/// Uses the Microsoft Identity test specifications to test the <see cref="MartenUserStore{User, Role}"/>
17+
/// and <see cref="MartenRoleStore{Role}"/>
18+
/// </summary>
19+
[Collection(UsingDatabaseServerCollection.Name)]
20+
public class MicrosoftIdentitySpecificationConformanceTests :
21+
IdentitySpecificationTestBase<MartenIdentityUser, MartenIdentityRole>,
22+
IClassFixture<MartenDocumentStoreBootstrapFixture>,
23+
IDisposable
24+
{
25+
private readonly IDocumentStore _documentStore;
26+
27+
public MicrosoftIdentitySpecificationConformanceTests(
28+
MartenDocumentStoreBootstrapFixture martenDocumentStoreBootstrapFixture,
29+
ITestOutputHelper testOutputHelper
30+
)
31+
{
32+
_documentStore = martenDocumentStoreBootstrapFixture.ConfigureMartenDocumentStore(options =>
33+
{
34+
options.ConfigureMartenIdentityMapping();
35+
options.Logger(new MartenTestConsoleLogger(testOutputHelper));
36+
});
37+
}
38+
39+
public void Dispose()
40+
{
41+
_documentStore.Dispose();
42+
}
43+
44+
protected override object? CreateTestContext()
45+
{
46+
return null;
47+
}
48+
49+
protected override void AddUserStore(IServiceCollection services, object? context = null)
50+
{
51+
var userStore = new MartenUserStore<MartenIdentityUser, MartenIdentityRole>(_documentStore);
52+
services.AddSingleton<IUserStore<MartenIdentityUser>>(userStore);
53+
}
54+
55+
protected override void AddRoleStore(IServiceCollection services, object? context = null)
56+
{
57+
var roleStore = new MartenRoleStore<MartenIdentityRole>(_documentStore);
58+
59+
services.AddSingleton<IRoleStore<MartenIdentityRole>>(roleStore);
60+
}
61+
62+
protected override void SetUserPasswordHash(MartenIdentityUser user, string hashedPassword)
63+
{
64+
user.PasswordHash = hashedPassword;
65+
}
66+
67+
protected override MartenIdentityUser CreateTestUser(
68+
string namePrefix = "",
69+
string email = "",
70+
string phoneNumber = "",
71+
bool lockoutEnabled = false,
72+
DateTimeOffset? lockoutEnd = null,
73+
bool useNamePrefixAsUserName = false
74+
)
75+
{
76+
return new MartenIdentityUser
77+
{
78+
UserName = useNamePrefixAsUserName ? namePrefix : $"{namePrefix}{Guid.NewGuid()}",
79+
EmailAddress = email,
80+
PhoneNumber = phoneNumber,
81+
IsLockoutEnabled = lockoutEnabled,
82+
LockoutEndAtUtc = lockoutEnd
83+
};
84+
}
85+
86+
protected override Expression<Func<MartenIdentityUser, bool>> UserNameEqualsPredicate(string userName)
87+
{
88+
return user => user.UserName == userName;
89+
}
90+
91+
protected override Expression<Func<MartenIdentityUser, bool>> UserNameStartsWithPredicate(string userName)
92+
{
93+
return user => user.UserName.StartsWith(userName);
94+
}
95+
96+
protected override MartenIdentityRole CreateTestRole(string roleNamePrefix = "",
97+
bool useRoleNamePrefixAsRoleName = false)
98+
{
99+
var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : $"{roleNamePrefix}{Guid.NewGuid()}";
100+
return new MartenIdentityRole(roleName);
101+
}
102+
103+
protected override Expression<Func<MartenIdentityRole, bool>> RoleNameEqualsPredicate(string roleName)
104+
{
105+
return role => role.Name == roleName;
106+
}
107+
108+
protected override Expression<Func<MartenIdentityRole, bool>> RoleNameStartsWithPredicate(string roleName)
109+
{
110+
return role => role.Name.StartsWith(roleName);
111+
}
112+
}
113+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using DotNet.Testcontainers.Containers.Builders;
2+
using DotNet.Testcontainers.Containers.Configurations.Databases;
3+
using DotNet.Testcontainers.Containers.Modules.Databases;
4+
using Xunit;
5+
6+
namespace Marten.AspNetCore.Identity.Tests.Support
7+
{
8+
public class DatabaseServerBootstrapFixture : IAsyncLifetime
9+
{
10+
private readonly PostgreSqlTestcontainer _postgreSqlContainer;
11+
12+
private const string DatabaseName = "aspnetidentity";
13+
private const string DatabaseUserName = "aspnetidentity";
14+
private const string DatabaseUserPassword = "aspnetidentity";
15+
private const int DatabaseHostPort = 5435;
16+
17+
public static readonly string ConnectionString;
18+
19+
static DatabaseServerBootstrapFixture()
20+
{
21+
ConnectionString = "HOST = 127.0.0.1; " +
22+
$"PORT = {DatabaseHostPort}; " +
23+
$"DATABASE = '{DatabaseName}'; " +
24+
$"USER ID = '{DatabaseUserName}'; " +
25+
$"PASSWORD = '{DatabaseUserPassword}'; " +
26+
"TIMEOUT = 15; " +
27+
"POOLING = True; " +
28+
"MINPOOLSIZE = 1; " +
29+
"MAXPOOLSIZE = 100; " +
30+
"COMMANDTIMEOUT = 20; ";
31+
}
32+
33+
public DatabaseServerBootstrapFixture()
34+
{
35+
var testContainerBuilder = new TestcontainersBuilder<PostgreSqlTestcontainer>()
36+
.WithCleanUp(true)
37+
.WithDatabase(new PostgreSqlTestcontainerConfiguration
38+
{
39+
Database = DatabaseName,
40+
Username = DatabaseUserName,
41+
Password = DatabaseUserPassword
42+
})
43+
.WithPortBinding(DatabaseHostPort, 5432)
44+
.WithImage("clkao/postgres-plv8")
45+
.WithName("MartenAspNetIdentityTestDb")
46+
;
47+
48+
_postgreSqlContainer = testContainerBuilder.Build();
49+
}
50+
51+
public async Task InitializeAsync()
52+
{
53+
await _postgreSqlContainer.StartAsync().ConfigureAwait(false);
54+
55+
var result = await _postgreSqlContainer.ExecAsync(new[]
56+
{
57+
"/bin/sh", "-c",
58+
$"psql -U {DatabaseUserName} -c \"CREATE EXTENSION plv8; SELECT extversion FROM pg_extensions WHERE extname = 'plv8';\""
59+
})
60+
.ConfigureAwait(false);
61+
}
62+
63+
public async Task DisposeAsync()
64+
{
65+
await _postgreSqlContainer.CleanUpAsync().ConfigureAwait(false);
66+
}
67+
}
68+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System.Data;
2+
using Npgsql;
3+
using Weasel.Postgresql;
4+
using Xunit;
5+
6+
namespace Marten.AspNetCore.Identity.Tests.Support
7+
{
8+
public class MartenDocumentStoreBootstrapFixture : IAsyncLifetime
9+
{
10+
private IDocumentStore? _documentStore;
11+
12+
private readonly string _schemaName;
13+
14+
public MartenDocumentStoreBootstrapFixture()
15+
{
16+
_schemaName = CreateIntegrationTestSchemaName();
17+
}
18+
19+
public IDocumentStore ConfigureMartenDocumentStore(Action<StoreOptions> additionalConfiguration)
20+
{
21+
_documentStore = global::Marten.DocumentStore.For(_ =>
22+
{
23+
_.Connection(DatabaseServerBootstrapFixture.ConnectionString);
24+
_.AutoCreateSchemaObjects = AutoCreate.All;
25+
_.DatabaseSchemaName = _schemaName;
26+
_.Events.DatabaseSchemaName = _schemaName;
27+
additionalConfiguration(_);
28+
});
29+
30+
return _documentStore;
31+
}
32+
33+
private static string CreateIntegrationTestSchemaName()
34+
{
35+
return "IntegrationTest_" + Guid.NewGuid()
36+
.ToString()
37+
.Replace("-", string.Empty, StringComparison.Ordinal);
38+
}
39+
40+
private async Task DeleteDatabaseSchemaAsync()
41+
{
42+
var sql = $"DROP SCHEMA IF EXISTS {_schemaName} CASCADE;";
43+
await using var connection = new NpgsqlConnection(DatabaseServerBootstrapFixture.ConnectionString);
44+
await connection.OpenAsync().ConfigureAwait(false);
45+
try
46+
{
47+
await using var transaction = await connection.BeginTransactionAsync(IsolationLevel.ReadCommitted)
48+
.ConfigureAwait(false);
49+
var command = connection.CreateCommand();
50+
command.CommandText = sql;
51+
await command.ExecuteNonQueryAsync().ConfigureAwait(false);
52+
await transaction.CommitAsync().ConfigureAwait(false);
53+
}
54+
finally
55+
{
56+
await connection.CloseAsync().ConfigureAwait(false);
57+
}
58+
}
59+
60+
public Task InitializeAsync()
61+
{
62+
return Task.CompletedTask;
63+
}
64+
65+
public async Task DisposeAsync()
66+
{
67+
await DeleteDatabaseSchemaAsync().ConfigureAwait(false);
68+
_documentStore?.Dispose();
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)