2026-08-31 02:14:04 +01:00
|
|
|
using Microsoft.AspNetCore.Builder;
|
|
|
|
|
using Microsoft.Data.Sqlite;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
using Microsoft.IdentityModel.Tokens;
|
2026-09-13 03:09:12 +01:00
|
|
|
using Npgsql;
|
|
|
|
|
using System.Runtime.Loader;
|
2026-08-31 02:14:04 +01:00
|
|
|
using Yavsc.Controllers;
|
2026-09-12 13:57:25 +01:00
|
|
|
using Yavsc.Interfaces.Workflow;
|
2026-08-31 02:14:04 +01:00
|
|
|
using Yavsc.Models;
|
2026-09-12 13:57:25 +01:00
|
|
|
using Yavsc.Models.Google.Messaging;
|
2026-08-31 04:15:10 +01:00
|
|
|
using Yavsc.Models.Haircut;
|
2026-09-12 13:57:25 +01:00
|
|
|
using Yavsc.Models.Messaging;
|
2026-08-31 02:14:04 +01:00
|
|
|
using Yavsc.Models.Relationship;
|
|
|
|
|
using Yavsc.Models.Workflow;
|
2026-09-12 13:57:25 +01:00
|
|
|
using Yavsc.Services;
|
2026-08-31 02:14:04 +01:00
|
|
|
using Yavsc.Tests.Shared;
|
|
|
|
|
|
|
|
|
|
namespace Yavsc.Api.Test.Fixtures;
|
|
|
|
|
|
|
|
|
|
public sealed class ApiWebServerFixture : WebHostFixture
|
|
|
|
|
{
|
2026-09-13 03:09:12 +01:00
|
|
|
private const string DbProviderEnvVar = "YAVSC_API_TEST_DB_PROVIDER";
|
|
|
|
|
private const string NpgsqlAdminConnectionEnvVar = "YAVSC_API_TEST_NPGSQL_ADMIN_CONNECTION";
|
|
|
|
|
private const string DefaultDevelopmentConnectionString = "Server=localhost;Port=5432;Database=yavscdev;Username=yavscdev;Password=8*5idas;Include Error Detail=true";
|
|
|
|
|
|
2026-08-31 02:14:04 +01:00
|
|
|
protected override int HttpsPort => 5104;
|
|
|
|
|
|
|
|
|
|
private static SqliteConnection? _sharedSqliteConnection;
|
|
|
|
|
private static readonly object _sqliteLock = new();
|
2026-09-13 03:09:12 +01:00
|
|
|
private static readonly object _npgsqlLock = new();
|
|
|
|
|
private static string? _sharedNpgsqlConnectionString;
|
|
|
|
|
private static string? _sharedNpgsqlAdminConnectionString;
|
|
|
|
|
private static string? _sharedNpgsqlDatabaseName;
|
|
|
|
|
private static bool _npgsqlCleanupRegistered;
|
2026-08-31 02:14:04 +01:00
|
|
|
|
|
|
|
|
protected override WebApplication BuildApp(WebApplicationBuilder builder)
|
|
|
|
|
{
|
2026-09-13 03:09:12 +01:00
|
|
|
if (UseNpgsqlProvider())
|
|
|
|
|
{
|
|
|
|
|
var npgsqlConnectionString = EnsureNpgsqlDatabaseCreated();
|
|
|
|
|
builder.Services.AddDbContext<ApplicationDbContext>(opt =>
|
|
|
|
|
opt.UseNpgsql(npgsqlConnectionString));
|
|
|
|
|
}
|
|
|
|
|
else
|
2026-08-31 02:14:04 +01:00
|
|
|
{
|
2026-09-13 03:09:12 +01:00
|
|
|
SqliteConnection sharedConnection;
|
|
|
|
|
lock (_sqliteLock)
|
2026-08-31 02:14:04 +01:00
|
|
|
{
|
2026-09-13 03:09:12 +01:00
|
|
|
if (_sharedSqliteConnection is null)
|
|
|
|
|
{
|
|
|
|
|
_sharedSqliteConnection = new SqliteConnection(
|
|
|
|
|
"Data Source=YavscApiTests;Mode=Memory;Cache=Shared");
|
|
|
|
|
_sharedSqliteConnection.Open();
|
|
|
|
|
}
|
|
|
|
|
sharedConnection = _sharedSqliteConnection;
|
2026-08-31 02:14:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-09-13 03:09:12 +01:00
|
|
|
builder.Services.AddDbContext<ApplicationDbContext>(opt =>
|
|
|
|
|
opt.UseSqlite(sharedConnection));
|
|
|
|
|
}
|
2026-08-31 02:14:04 +01:00
|
|
|
|
|
|
|
|
builder.Services.AddControllers()
|
|
|
|
|
.AddApplicationPart(typeof(ActivityApiController).Assembly);
|
|
|
|
|
|
2026-09-12 13:57:25 +01:00
|
|
|
builder.Services.AddLocalization();
|
|
|
|
|
builder.Services.Configure<GoogleAuthSettings>(_ => { });
|
|
|
|
|
builder.Services.AddTransient<IBillingService, BillingService>();
|
|
|
|
|
builder.Services.AddTransient<IYavscMessageSender, NoopMessageSender>();
|
2026-08-31 02:14:04 +01:00
|
|
|
builder.Services.AddAuthorization();
|
|
|
|
|
|
|
|
|
|
builder.Services.AddAuthentication("Bearer")
|
|
|
|
|
.AddJwtBearer("Bearer", options =>
|
|
|
|
|
{
|
|
|
|
|
options.IncludeErrorDetails = true;
|
|
|
|
|
options.MapInboundClaims = false;
|
|
|
|
|
options.TokenValidationParameters = new TokenValidationParameters
|
|
|
|
|
{
|
|
|
|
|
ValidateIssuer = true,
|
|
|
|
|
ValidIssuer = TestTokenIssuer.Issuer,
|
|
|
|
|
ValidateAudience = false,
|
|
|
|
|
ValidateLifetime = true,
|
|
|
|
|
ValidateIssuerSigningKey = true,
|
|
|
|
|
IssuerSigningKey = TestTokenIssuer.SigningKey,
|
|
|
|
|
NameClaimType = "sub",
|
|
|
|
|
RoleClaimType = Yavsc.Constants.RoleClaimType,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return builder.Build();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override async Task<WebApplication> ConfigurePipelineAsync(WebApplication app)
|
|
|
|
|
{
|
|
|
|
|
app.UseDeveloperExceptionPage();
|
|
|
|
|
app.UseRouting();
|
|
|
|
|
app.UseAuthentication();
|
|
|
|
|
app.UseAuthorization();
|
|
|
|
|
app.MapControllers();
|
|
|
|
|
|
|
|
|
|
using (var scope = app.Services.CreateScope())
|
|
|
|
|
{
|
|
|
|
|
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
|
|
|
|
db.Database.EnsureCreated();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await Task.CompletedTask;
|
|
|
|
|
return app;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string BaseAddress => Addresses.First(a => a.StartsWith("https://", StringComparison.Ordinal));
|
|
|
|
|
|
2026-09-13 03:09:12 +01:00
|
|
|
public static bool UseNpgsqlProvider()
|
|
|
|
|
=> string.Equals(
|
|
|
|
|
Environment.GetEnvironmentVariable(DbProviderEnvVar),
|
|
|
|
|
"npgsql",
|
|
|
|
|
StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
|
|
private static string EnsureNpgsqlDatabaseCreated()
|
|
|
|
|
{
|
|
|
|
|
lock (_npgsqlLock)
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(_sharedNpgsqlConnectionString))
|
|
|
|
|
{
|
|
|
|
|
return _sharedNpgsqlConnectionString;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var adminConnectionString = BuildAdminConnectionString();
|
|
|
|
|
var databaseName = $"yavsc_api_test_{Guid.NewGuid():N}";
|
|
|
|
|
|
|
|
|
|
using (var adminConnection = new NpgsqlConnection(adminConnectionString))
|
|
|
|
|
{
|
|
|
|
|
adminConnection.Open();
|
|
|
|
|
using var createCommand = adminConnection.CreateCommand();
|
|
|
|
|
createCommand.CommandText = $"CREATE DATABASE \"{databaseName}\"";
|
|
|
|
|
createCommand.ExecuteNonQuery();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var testConnectionBuilder = new NpgsqlConnectionStringBuilder(adminConnectionString)
|
|
|
|
|
{
|
|
|
|
|
Database = databaseName,
|
|
|
|
|
Pooling = false,
|
|
|
|
|
IncludeErrorDetail = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
_sharedNpgsqlAdminConnectionString = adminConnectionString;
|
|
|
|
|
_sharedNpgsqlDatabaseName = databaseName;
|
|
|
|
|
_sharedNpgsqlConnectionString = testConnectionBuilder.ToString();
|
|
|
|
|
RegisterNpgsqlCleanup();
|
|
|
|
|
return _sharedNpgsqlConnectionString;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string BuildAdminConnectionString()
|
|
|
|
|
{
|
|
|
|
|
var configured = Environment.GetEnvironmentVariable(NpgsqlAdminConnectionEnvVar);
|
|
|
|
|
var source = string.IsNullOrWhiteSpace(configured)
|
|
|
|
|
? DefaultDevelopmentConnectionString
|
|
|
|
|
: configured;
|
|
|
|
|
|
|
|
|
|
var builder = new NpgsqlConnectionStringBuilder(source)
|
|
|
|
|
{
|
|
|
|
|
Pooling = false,
|
|
|
|
|
IncludeErrorDetail = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(configured))
|
|
|
|
|
{
|
|
|
|
|
builder.Database = "postgres";
|
|
|
|
|
}
|
|
|
|
|
else if (string.IsNullOrWhiteSpace(builder.Database))
|
|
|
|
|
{
|
|
|
|
|
builder.Database = "postgres";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return builder.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void RegisterNpgsqlCleanup()
|
|
|
|
|
{
|
|
|
|
|
if (_npgsqlCleanupRegistered)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AppDomain.CurrentDomain.ProcessExit += (_, __) => DropTemporaryNpgsqlDatabase();
|
|
|
|
|
AssemblyLoadContext.Default.Unloading += _ => DropTemporaryNpgsqlDatabase();
|
|
|
|
|
_npgsqlCleanupRegistered = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void DropTemporaryNpgsqlDatabase()
|
|
|
|
|
{
|
|
|
|
|
lock (_npgsqlLock)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(_sharedNpgsqlDatabaseName)
|
|
|
|
|
|| string.IsNullOrWhiteSpace(_sharedNpgsqlAdminConnectionString))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using var adminConnection = new NpgsqlConnection(_sharedNpgsqlAdminConnectionString);
|
|
|
|
|
adminConnection.Open();
|
|
|
|
|
|
|
|
|
|
using (var terminateCommand = adminConnection.CreateCommand())
|
|
|
|
|
{
|
|
|
|
|
terminateCommand.CommandText = @"
|
|
|
|
|
SELECT pg_terminate_backend(pid)
|
|
|
|
|
FROM pg_stat_activity
|
|
|
|
|
WHERE datname = @databaseName
|
|
|
|
|
AND pid <> pg_backend_pid();";
|
|
|
|
|
terminateCommand.Parameters.AddWithValue("databaseName", _sharedNpgsqlDatabaseName);
|
|
|
|
|
terminateCommand.ExecuteNonQuery();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using var dropCommand = adminConnection.CreateCommand();
|
|
|
|
|
dropCommand.CommandText = $"DROP DATABASE IF EXISTS \"{_sharedNpgsqlDatabaseName}\"";
|
|
|
|
|
dropCommand.ExecuteNonQuery();
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// Best-effort cleanup only.
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_sharedNpgsqlConnectionString = null;
|
|
|
|
|
_sharedNpgsqlAdminConnectionString = null;
|
|
|
|
|
_sharedNpgsqlDatabaseName = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-12 13:57:25 +01:00
|
|
|
private sealed class NoopMessageSender : IYavscMessageSender
|
|
|
|
|
{
|
|
|
|
|
public Task<MessageWithPayloadResponse> NotifyBookQueryAsync(IEnumerable<string> connectionIds, RdvQueryEvent ev)
|
|
|
|
|
=> Task.FromResult(new MessageWithPayloadResponse());
|
|
|
|
|
|
|
|
|
|
public Task<MessageWithPayloadResponse> NotifyEstimateAsync(IEnumerable<string> connectionIds, EstimationEvent ev)
|
|
|
|
|
=> Task.FromResult(new MessageWithPayloadResponse());
|
|
|
|
|
|
|
|
|
|
public Task<MessageWithPayloadResponse> NotifyHairCutQueryAsync(IEnumerable<string> connectionIds, HairCutQueryEvent ev)
|
|
|
|
|
=> Task.FromResult(new MessageWithPayloadResponse());
|
|
|
|
|
|
|
|
|
|
public Task<MessageWithPayloadResponse> NotifyAsync(IEnumerable<string> connectionIds, IEvent yaev)
|
|
|
|
|
=> Task.FromResult(new MessageWithPayloadResponse());
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-31 02:14:04 +01:00
|
|
|
public void ResetAndSeedActivityGraph()
|
|
|
|
|
{
|
|
|
|
|
using var scope = Services.CreateScope();
|
|
|
|
|
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
|
|
|
|
|
|
|
|
|
db.Database.EnsureDeleted();
|
|
|
|
|
db.Database.EnsureCreated();
|
|
|
|
|
|
|
|
|
|
var user = new ApplicationUser
|
|
|
|
|
{
|
|
|
|
|
Id = "alice",
|
|
|
|
|
UserName = "alice",
|
|
|
|
|
Email = "alice@example.test",
|
|
|
|
|
EmailConfirmed = true,
|
|
|
|
|
FullName = "Alice",
|
|
|
|
|
};
|
|
|
|
|
db.Users.Add(user);
|
|
|
|
|
|
|
|
|
|
var location = new Location
|
|
|
|
|
{
|
|
|
|
|
Address = "1 rue du Test",
|
|
|
|
|
Latitude = 48.8566,
|
|
|
|
|
Longitude = 2.3522,
|
|
|
|
|
};
|
|
|
|
|
db.Add(location);
|
|
|
|
|
db.SaveChanges();
|
|
|
|
|
|
|
|
|
|
var activity = new Activity
|
|
|
|
|
{
|
|
|
|
|
Code = "dev",
|
|
|
|
|
Name = "Dev",
|
|
|
|
|
Hidden = false,
|
|
|
|
|
DateCreated = DateTime.UtcNow,
|
|
|
|
|
DateModified = DateTime.UtcNow,
|
|
|
|
|
};
|
|
|
|
|
db.Activities.Add(activity);
|
|
|
|
|
|
|
|
|
|
db.Activities.Add(new Activity
|
|
|
|
|
{
|
|
|
|
|
Code = "ghost",
|
|
|
|
|
Name = "Ghost",
|
|
|
|
|
Hidden = false,
|
|
|
|
|
DateCreated = DateTime.UtcNow,
|
|
|
|
|
DateModified = DateTime.UtcNow,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var performer = new PerformerProfile
|
|
|
|
|
{
|
|
|
|
|
PerformerId = "alice",
|
|
|
|
|
SIREN = "123456789",
|
|
|
|
|
OrganizationAddressId = location.Id,
|
|
|
|
|
AcceptNotifications = true,
|
|
|
|
|
AcceptPublicContact = true,
|
|
|
|
|
Active = true,
|
|
|
|
|
Rate = 5,
|
|
|
|
|
WebSite = "https://alice.dev",
|
|
|
|
|
};
|
|
|
|
|
db.Performers.Add(performer);
|
|
|
|
|
|
|
|
|
|
db.UserActivities.Add(new UserActivity
|
|
|
|
|
{
|
|
|
|
|
UserId = "alice",
|
|
|
|
|
DoesCode = "dev",
|
|
|
|
|
Weight = 100,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
db.Users.Add(new ApplicationUser
|
|
|
|
|
{
|
|
|
|
|
Id = "bob",
|
|
|
|
|
UserName = "bob",
|
|
|
|
|
Email = "bob@example.test",
|
|
|
|
|
EmailConfirmed = true,
|
|
|
|
|
FullName = "Bob",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
db.Activities.Add(new Activity
|
|
|
|
|
{
|
|
|
|
|
Code = "declared-only",
|
|
|
|
|
Name = "Declared Only",
|
|
|
|
|
Hidden = false,
|
|
|
|
|
DateCreated = DateTime.UtcNow,
|
|
|
|
|
DateModified = DateTime.UtcNow,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
db.Performers.Add(new PerformerProfile
|
|
|
|
|
{
|
|
|
|
|
PerformerId = "bob",
|
|
|
|
|
SIREN = "987654321",
|
|
|
|
|
OrganizationAddressId = location.Id,
|
|
|
|
|
AcceptNotifications = false,
|
|
|
|
|
AcceptPublicContact = false,
|
|
|
|
|
Active = false,
|
|
|
|
|
Rate = 0,
|
|
|
|
|
WebSite = "",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
db.UserActivities.Add(new UserActivity
|
|
|
|
|
{
|
|
|
|
|
UserId = "bob",
|
|
|
|
|
DoesCode = "declared-only",
|
|
|
|
|
Weight = 10,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
db.SaveChanges();
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-31 03:37:09 +01:00
|
|
|
public void ResetAndSeedRdvQueryGraph()
|
|
|
|
|
{
|
|
|
|
|
ResetAndSeedActivityGraph();
|
|
|
|
|
|
|
|
|
|
using var scope = Services.CreateScope();
|
|
|
|
|
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
|
|
|
|
|
|
|
|
|
var location = db.Locations.Single(l => l.Address == "1 rue du Test");
|
|
|
|
|
|
|
|
|
|
db.RdvQueries.Add(new RdvQuery
|
|
|
|
|
{
|
|
|
|
|
ActivityCode = "dev",
|
|
|
|
|
ClientId = "alice",
|
|
|
|
|
PerformerId = "alice",
|
|
|
|
|
Consent = true,
|
2026-09-06 19:16:41 +01:00
|
|
|
UserCreated = "alice",
|
|
|
|
|
UserModified = "alice",
|
|
|
|
|
DateCreated = DateTime.UtcNow,
|
|
|
|
|
DateModified = DateTime.UtcNow,
|
2026-08-31 03:37:09 +01:00
|
|
|
EventDate = DateTime.UtcNow.AddDays(1),
|
|
|
|
|
Location = location,
|
|
|
|
|
Reason = "Initial rendez-vous",
|
|
|
|
|
Status = Yavsc.QueryStatus.Inserted,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
db.SaveChanges();
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-31 04:15:10 +01:00
|
|
|
public void ResetAndSeedHaircutGraph()
|
|
|
|
|
{
|
|
|
|
|
ResetAndSeedActivityGraph();
|
|
|
|
|
|
|
|
|
|
using var scope = Services.CreateScope();
|
|
|
|
|
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
|
|
|
|
|
|
|
|
|
var location = db.Locations.Single(l => l.Address == "1 rue du Test");
|
|
|
|
|
|
|
|
|
|
if (!db.Activities.Any(a => a.Code == "brush"))
|
|
|
|
|
{
|
|
|
|
|
db.Activities.Add(new Activity
|
|
|
|
|
{
|
|
|
|
|
Code = "brush",
|
|
|
|
|
Name = "Brush",
|
|
|
|
|
Hidden = false,
|
|
|
|
|
DateCreated = DateTime.UtcNow,
|
|
|
|
|
DateModified = DateTime.UtcNow,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!db.Activities.Any(a => a.Code == "mbrush"))
|
|
|
|
|
{
|
|
|
|
|
db.Activities.Add(new Activity
|
|
|
|
|
{
|
|
|
|
|
Code = "mbrush",
|
|
|
|
|
Name = "MBrush",
|
|
|
|
|
Hidden = false,
|
|
|
|
|
DateCreated = DateTime.UtcNow,
|
|
|
|
|
DateModified = DateTime.UtcNow,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!db.BrusherProfile.Any(p => p.UserId == "alice"))
|
|
|
|
|
{
|
|
|
|
|
db.BrusherProfile.Add(new BrusherProfile
|
|
|
|
|
{
|
|
|
|
|
UserId = "alice",
|
|
|
|
|
ActionDistance = 25,
|
|
|
|
|
WomenLongCutPrice = 50m,
|
|
|
|
|
WomenHalfCutPrice = 40m,
|
|
|
|
|
WomenShortCutPrice = 30m,
|
|
|
|
|
ManCutPrice = 20m,
|
|
|
|
|
KidCutPrice = 15m,
|
|
|
|
|
ShampooPrice = 5m,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var prestation1 = new HairPrestation
|
|
|
|
|
{
|
|
|
|
|
Gender = HairCutGenders.Women,
|
|
|
|
|
Length = HairLength.HalfLong,
|
|
|
|
|
Cut = true,
|
|
|
|
|
Shampoo = true,
|
|
|
|
|
Dressing = HairDressings.Brushing,
|
|
|
|
|
Tech = HairTechnos.NoTech,
|
|
|
|
|
Cares = false,
|
|
|
|
|
Taints = new List<HairTaintInstance>(),
|
|
|
|
|
};
|
|
|
|
|
var prestation2 = new HairPrestation
|
|
|
|
|
{
|
|
|
|
|
Gender = HairCutGenders.Man,
|
|
|
|
|
Length = HairLength.Short,
|
|
|
|
|
Cut = true,
|
|
|
|
|
Shampoo = false,
|
|
|
|
|
Dressing = HairDressings.Brushing,
|
|
|
|
|
Tech = HairTechnos.NoTech,
|
|
|
|
|
Cares = false,
|
|
|
|
|
Taints = new List<HairTaintInstance>(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
db.HairPrestation.AddRange(prestation1, prestation2);
|
|
|
|
|
db.SaveChanges();
|
|
|
|
|
|
|
|
|
|
db.HairCutQueries.Add(new HairCutQuery
|
|
|
|
|
{
|
|
|
|
|
ActivityCode = "brush",
|
|
|
|
|
ClientId = "alice",
|
|
|
|
|
PerformerId = "alice",
|
|
|
|
|
Consent = true,
|
2026-09-06 19:16:41 +01:00
|
|
|
UserCreated = "alice",
|
|
|
|
|
UserModified = "alice",
|
|
|
|
|
DateCreated = DateTime.UtcNow,
|
|
|
|
|
DateModified = DateTime.UtcNow,
|
2026-08-31 04:15:10 +01:00
|
|
|
EventDate = DateTime.UtcNow.AddDays(3),
|
|
|
|
|
Location = location,
|
|
|
|
|
PrestationId = prestation1.Id,
|
|
|
|
|
Prestation = prestation1,
|
|
|
|
|
AdditionalInfo = "Coupe test",
|
|
|
|
|
Status = Yavsc.QueryStatus.Inserted,
|
|
|
|
|
Description = "Haircut seed",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
db.HairMultiCutQueries.Add(new HairMultiCutQuery
|
|
|
|
|
{
|
|
|
|
|
ActivityCode = "mbrush",
|
|
|
|
|
ClientId = "alice",
|
|
|
|
|
PerformerId = "alice",
|
|
|
|
|
Consent = true,
|
2026-09-06 19:16:41 +01:00
|
|
|
UserCreated = "alice",
|
|
|
|
|
UserModified = "alice",
|
|
|
|
|
DateCreated = DateTime.UtcNow,
|
|
|
|
|
DateModified = DateTime.UtcNow,
|
2026-08-31 04:15:10 +01:00
|
|
|
EventDate = DateTime.UtcNow.AddDays(4),
|
|
|
|
|
Location = location,
|
|
|
|
|
Prestations = new List<HairPrestationCollectionItem>
|
|
|
|
|
{
|
|
|
|
|
new() { PrestationId = prestation1.Id, Prestation = prestation1 },
|
|
|
|
|
new() { PrestationId = prestation2.Id, Prestation = prestation2 },
|
|
|
|
|
},
|
|
|
|
|
Status = Yavsc.QueryStatus.Inserted,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
db.SaveChanges();
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-31 02:14:04 +01:00
|
|
|
public override void Dispose()
|
|
|
|
|
{
|
2026-09-12 17:31:18 +01:00
|
|
|
// Keep the shared in-memory SQLite connection alive for the
|
|
|
|
|
// whole test process. Closing it from one fixture instance can
|
|
|
|
|
// drop the schema while other tests are still running.
|
|
|
|
|
base.Dispose();
|
2026-08-31 02:14:04 +01:00
|
|
|
}
|
|
|
|
|
}
|