Skip to content

Commit bf30aa7

Browse files
feat: replace concurent dict with in-memory database
1 parent fc7186f commit bf30aa7

12 files changed

Lines changed: 188 additions & 42 deletions

AuthService.Test/AuthService.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
2121
<PackageReference Include="Moq" Version="4.20.70" />
2222
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
23+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.6" />
2324
</ItemGroup>
2425

2526
<ItemGroup>

AuthService.Test/AuthServiceTests.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System;
2-
using AuthService.DataAccess;
2+
using System.Collections.Generic;
3+
using AuthService.DataAccess.EF;
4+
using AuthService.Domain;
35
using FluentAssertions;
6+
using Microsoft.EntityFrameworkCore;
47
using Microsoft.Extensions.Options;
58
using Moq;
69
using Xunit;
@@ -11,21 +14,37 @@ namespace AuthService.Test;
1114
public class AuthServiceTests
1215
{
1316
private readonly Domain.AuthService authService;
14-
private readonly InsuranceAgentsInMemoryDb agentsDb;
17+
private readonly IInsuranceAgents agentsRepository;
1518
private readonly AppSettings appSettings;
1619
private readonly ITestOutputHelper output;
1720

1821
public AuthServiceTests(ITestOutputHelper output)
1922
{
2023
this.output = output;
21-
agentsDb = new InsuranceAgentsInMemoryDb();
24+
25+
// Setup EF Core in-memory database
26+
var options = new DbContextOptionsBuilder<AuthDbContext>()
27+
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
28+
.Options;
29+
30+
var dbContext = new AuthDbContext(options);
31+
agentsRepository = new InsuranceAgentRepository(dbContext);
32+
33+
// Seed test data
34+
agentsRepository.Add(new InsuranceAgent("jimmy.solid", "secret", "static/avatars/jimmy_solid.png",
35+
new List<string> { "TRI", "HSI", "FAI", "CAR" }));
36+
agentsRepository.Add(new InsuranceAgent("danny.solid", "secret", "static/avatars/danny.solid.png",
37+
new List<string> { "TRI", "HSI", "FAI", "CAR" }));
38+
agentsRepository.Add(new InsuranceAgent("admin", "admin", "static/avatars/admin.png",
39+
new List<string> { "TRI", "HSI", "FAI", "CAR" }));
40+
2241
appSettings = new AppSettings
2342
{
2443
Secret = "ThisIsASecretKeyForJWTTokenGeneration123456789"
2544
};
26-
var options = Options.Create(appSettings);
45+
var appSettingsOptions = Options.Create(appSettings);
2746

28-
authService = new Domain.AuthService(agentsDb, options);
47+
authService = new Domain.AuthService(agentsRepository, appSettingsOptions);
2948
}
3049

3150
[Theory]

AuthService/AuthService.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.6" />
99
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.6.0" />
1010
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.6" />
11+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.6" />
12+
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.6" />
1113
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6" />
1214
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
1315
</ItemGroup>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Linq;
3+
using Microsoft.EntityFrameworkCore;
4+
using AuthService.Domain;
5+
6+
namespace AuthService.DataAccess.EF;
7+
8+
public class AuthDbContext : DbContext
9+
{
10+
public AuthDbContext(DbContextOptions<AuthDbContext> options) : base(options)
11+
{
12+
}
13+
14+
public DbSet<InsuranceAgent> InsuranceAgents { get; set; }
15+
16+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
17+
{
18+
optionsBuilder.EnableSensitiveDataLogging();
19+
}
20+
21+
protected override void OnModelCreating(ModelBuilder modelBuilder)
22+
{
23+
modelBuilder.Entity<InsuranceAgent>(entity =>
24+
{
25+
entity.HasKey(e => e.Id);
26+
entity.HasIndex(e => e.Login).IsUnique();
27+
entity.Property(e => e.Login).IsRequired();
28+
entity.Property(e => e.Password).IsRequired();
29+
entity.Property(e => e.Avatar).IsRequired();
30+
entity.Property(e => e.AvailableProducts)
31+
.HasConversion(
32+
v => string.Join(',', v),
33+
v => v.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList()
34+
);
35+
});
36+
}
37+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.Extensions.Configuration;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using AuthService.Domain;
5+
6+
namespace AuthService.DataAccess.EF;
7+
8+
public static class EFInstaller
9+
{
10+
public static IServiceCollection AddEFConfiguration(this IServiceCollection services, IConfiguration configuration)
11+
{
12+
services.AddDbContext<AuthDbContext>(options =>
13+
{
14+
options.UseInMemoryDatabase("InsuranceAgents");
15+
});
16+
17+
services.AddScoped<IInsuranceAgents, InsuranceAgentRepository>();
18+
return services;
19+
}
20+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Linq;
3+
using Microsoft.EntityFrameworkCore;
4+
using AuthService.Domain;
5+
6+
namespace AuthService.DataAccess.EF;
7+
8+
public class InsuranceAgentRepository : IInsuranceAgents
9+
{
10+
private readonly AuthDbContext dbContext;
11+
12+
public InsuranceAgentRepository(AuthDbContext dbContext)
13+
{
14+
this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
15+
}
16+
17+
public void Add(InsuranceAgent agent)
18+
{
19+
dbContext.InsuranceAgents.Add(agent);
20+
}
21+
22+
public InsuranceAgent FindByLogin(string login)
23+
{
24+
return dbContext.InsuranceAgents
25+
.FirstOrDefault(a => a.Login == login);
26+
}
27+
}

AuthService/DataAccess/InsuranceAgentsInMemoryDb.cs

Lines changed: 0 additions & 30 deletions
This file was deleted.

AuthService/Domain/InsuranceAgent.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ namespace AuthService.Domain;
44

55
public class InsuranceAgent
66
{
7+
// EF Core requires a parameterless constructor
8+
private InsuranceAgent()
9+
{
10+
}
11+
712
public InsuranceAgent(string login, string password, string avatar, List<string> availableProducts)
813
{
914
Login = login;
@@ -12,13 +17,14 @@ public InsuranceAgent(string login, string password, string avatar, List<string>
1217
AvailableProducts = availableProducts;
1318
}
1419

15-
public string Login { get; }
16-
public string Password { get; }
17-
public string Avatar { get; }
18-
public List<string> AvailableProducts { get; }
20+
public int Id { get; private set; }
21+
public string Login { get; private set; }
22+
public string Password { get; private set; }
23+
public string Avatar { get; private set; }
24+
public List<string> AvailableProducts { get; private set; }
1925

2026
public bool PasswordMatches(string passwordToTest)
2127
{
2228
return Password == passwordToTest;
2329
}
24-
}
30+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.Extensions.DependencyInjection;
3+
4+
namespace AuthService.Init;
5+
6+
public static class ApplicationBuilderExtensions
7+
{
8+
public static void UseInitializer(this IApplicationBuilder app)
9+
{
10+
using (var scope = app.ApplicationServices.CreateScope())
11+
{
12+
var initializer = scope.ServiceProvider.GetService<DataLoader>();
13+
initializer.Seed();
14+
}
15+
}
16+
}

AuthService/Init/DataLoader.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using AuthService.DataAccess.EF;
4+
using AuthService.Domain;
5+
6+
namespace AuthService.Init;
7+
8+
public class DataLoader
9+
{
10+
private readonly AuthDbContext dbContext;
11+
12+
public DataLoader(AuthDbContext context)
13+
{
14+
dbContext = context;
15+
}
16+
17+
public void Seed()
18+
{
19+
dbContext.Database.EnsureCreated();
20+
if (dbContext.InsuranceAgents.Any()) return;
21+
22+
dbContext.InsuranceAgents.Add(new InsuranceAgent("jimmy.solid", "secret", "static/avatars/jimmy_solid.png",
23+
new List<string> { "TRI", "HSI", "FAI", "CAR" }));
24+
dbContext.InsuranceAgents.Add(new InsuranceAgent("danny.solid", "secret", "static/avatars/danny.solid.png",
25+
new List<string> { "TRI", "HSI", "FAI", "CAR" }));
26+
dbContext.InsuranceAgents.Add(new InsuranceAgent("admin", "admin", "static/avatars/admin.png",
27+
new List<string> { "TRI", "HSI", "FAI", "CAR" }));
28+
29+
dbContext.SaveChanges();
30+
}
31+
}

0 commit comments

Comments
 (0)