From 2e26cfcfa22649a1a554db69f07db22e69755dc5 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 19 Apr 2026 18:10:00 +0100 Subject: [PATCH 1/4] configure a test scope --- test/yavscTests/WebServerFixture.cs | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/test/yavscTests/WebServerFixture.cs b/test/yavscTests/WebServerFixture.cs index da9c8076..7eb5a966 100644 --- a/test/yavscTests/WebServerFixture.cs +++ b/test/yavscTests/WebServerFixture.cs @@ -181,6 +181,54 @@ namespace isnd.tests AddAuthorizedClient(migrationScope, TestClientId, TestClientSecret); TestingUser = await db.Users.FirstOrDefaultAsync(u => u.UserName == TestingUserName); } + + // Seed IdentityServer ConfigurationDbContext with API resources and scopes + using (var configScope = _app.Services.CreateScope()) + { + try + { + var configDbContext = configScope.ServiceProvider.GetService(); + if (configDbContext != null) + { + configDbContext.Database.EnsureCreated(); + + // Add test API scope if it doesn't exist + var testScope = configDbContext.ApiScopes.FirstOrDefault(s => s.Name == "test"); + if (testScope == null) + { + configDbContext.ApiScopes.Add(new IdentityServer8.EntityFramework.Entities.ApiScope + { + Name = "test", + Enabled = true, + DisplayName = "Test API Scope" + }); + + // Add a basic API resource for the test scope + var apiResource = new IdentityServer8.EntityFramework.Entities.ApiResource + { + Name = "testapi", + DisplayName = "Test API", + Enabled = true, + Scopes = new List + { + new IdentityServer8.EntityFramework.Entities.ApiResourceScope + { + Scope = "test" + } + } + }; + configDbContext.ApiResources.Add(apiResource); + configDbContext.SaveChanges(); + } + } + } + catch (Exception ex) + { + _sharedLogger?.LogWarning($"Failed to seed ConfigurationDbContext: {ex.Message}"); + // Don't fail the fixture if seeding fails + } + } + await _app!.ConfigurePipeline(); _app.UseSession(); await _app.StartAsync(); From 65db349c0a0304ef3498df48fd16032ec1e5df21 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 19 Apr 2026 19:14:37 +0100 Subject: [PATCH 2/4] fixes the current date at testing phase --- Directory.Packages.props | 1 + src/Yavsc.Org/Extensions/HostingExtensions.cs | 8 ++-- src/Yavsc.Org/Yavsc.Org.csproj | 1 + .../Models/ApplicationDbContext.cs | 16 ++++++- test/yavscTests/WebServerFixture.cs | 42 ++++++++++++------- 5 files changed, 46 insertions(+), 22 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 3b2164c8..26bd0ea5 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -33,6 +33,7 @@ + diff --git a/src/Yavsc.Org/Extensions/HostingExtensions.cs b/src/Yavsc.Org/Extensions/HostingExtensions.cs index 4eedb087..1eb53c84 100644 --- a/src/Yavsc.Org/Extensions/HostingExtensions.cs +++ b/src/Yavsc.Org/Extensions/HostingExtensions.cs @@ -152,7 +152,7 @@ public static class HostingExtensions if (useInMemory) { services.AddDbContext(options => - options.UseInMemoryDatabase("YavscInMemory")); + options.UseSqlite("Data Source=file::memory:?cache=shared")); } else { @@ -281,7 +281,7 @@ public static class HostingExtensions var migrationsAssembly = typeof(Program).GetTypeInfo().Assembly.GetName().Name; var connectionString = builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName); bool useInMemory = builder.Configuration.GetValue("UseInMemoryDatabase", false); - string inMemoryDatabaseName = "YavscInMemory"; + string sqliteInMemoryConnectionString = "Data Source=file::memory:?cache=shared"; var identityServerBuilder = builder.Services.AddIdentityServer(options => { @@ -303,7 +303,7 @@ public static class HostingExtensions { if (useInMemory) { - options.ConfigureDbContext = b => b.UseInMemoryDatabase(inMemoryDatabaseName); + options.ConfigureDbContext = b => b.UseSqlite(sqliteInMemoryConnectionString); } else { @@ -328,7 +328,7 @@ public static class HostingExtensions { if (useInMemory) { - options.ConfigureDbContext = b => b.UseInMemoryDatabase(inMemoryDatabaseName); + options.ConfigureDbContext = b => b.UseSqlite(sqliteInMemoryConnectionString); } else { diff --git a/src/Yavsc.Org/Yavsc.Org.csproj b/src/Yavsc.Org/Yavsc.Org.csproj index 790838ec..a1867d41 100644 --- a/src/Yavsc.Org/Yavsc.Org.csproj +++ b/src/Yavsc.Org/Yavsc.Org.csproj @@ -32,6 +32,7 @@ all + diff --git a/src/Yavsc.Server/Models/ApplicationDbContext.cs b/src/Yavsc.Server/Models/ApplicationDbContext.cs index 9908fe74..0e9e717a 100644 --- a/src/Yavsc.Server/Models/ApplicationDbContext.cs +++ b/src/Yavsc.Server/Models/ApplicationDbContext.cs @@ -42,18 +42,30 @@ namespace Yavsc.Models } public ApplicationDbContext(DbContextOptions options) : base(options) { + if (Database.IsRelational()) + { + Database.SetCommandTimeout(180); + } } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); + if (Database.IsNpgsql()) + { + NOW_SQL="LOCALTIMESTAMP"; + } + else + { + NOW_SQL="CURRENT_TIMESTAMP"; + } builder.UseIdentityByDefaultColumns(); // Customize the ASP.NET Identity model and override the defaults if needed. // For example, you can rename the ASP.NET Identity table names and more. // Add your customizations after calling base.OnModelCreating(builder); builder.Entity().HasKey(x => new { x.OwnerId, x.UserId }); - builder.Entity().Property(x => x.DeclarationDate).HasDefaultValueSql("LOCALTIMESTAMP"); + builder.Entity().Property(x => x.DeclarationDate).HasDefaultValueSql(NOW_SQL); builder.Entity().HasKey(x => new { x.PostId, x.TagId }); builder.Entity().Property(u => u.FullName).IsRequired(false); @@ -337,6 +349,6 @@ namespace Yavsc.Models public DbSet DeviceFlowCodes { get; set; } public DbSet YavscApiScopes { get; set; } - + public string NOW_SQL { get; private set; } } } diff --git a/test/yavscTests/WebServerFixture.cs b/test/yavscTests/WebServerFixture.cs index 7eb5a966..1e211afb 100644 --- a/test/yavscTests/WebServerFixture.cs +++ b/test/yavscTests/WebServerFixture.cs @@ -1,3 +1,4 @@ +using IdentityServer8.EntityFramework.DbContexts; using IdentityServer8.EntityFramework.Entities; using IdentityServer8.Models; using Microsoft.AspNetCore.Builder; @@ -136,6 +137,12 @@ namespace isnd.tests var builder = WebApplication.CreateBuilder(); builder.Environment.EnvironmentName = "Development"; + + // Set ContentRoot to the Yavsc.Org project directory so WebRootPath resolves correctly + var testAssemblyLocation = AppDomain.CurrentDomain.BaseDirectory; + var yavscOrgPath = Path.GetFullPath(Path.Combine(testAssemblyLocation, "../../src/Yavsc.Org")); + builder.Environment.ContentRootPath = yavscOrgPath; + ConfigureLogger(); builder.Configuration .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) @@ -260,8 +267,10 @@ namespace isnd.tests private void AddAuthorizedClient(IServiceScope scope, string testClientId, string testClientSecret) { + var configDb = scope.ServiceProvider.GetRequiredService(); + if (configDb == null) + throw new InvalidOperationException("ConfigurationDbContext is not available for IdentityServer client seeding."); - var db = scope.ServiceProvider.GetRequiredService(); Client testingClient = new Client { ClientId = testClientId, @@ -269,57 +278,58 @@ namespace isnd.tests AccessTokenType = 1, BackChannelLogoutUri = SiteSettings!.Audience, ClientName = "Testing client", - Enabled = true + Enabled = true, + RequireClientSecret = true }; - db.Clients.Add(testingClient); - db.SaveChanges(); + configDb.Clients.Add(testingClient); + configDb.SaveChanges(); + ClientSecret secret = new ClientSecret { Value = testClientSecret.Sha256(), + Type = IdentityServer8.IdentityServerConstants.SecretTypes.SharedSecret, ClientId = testingClient.Id }; - db.ClientSecrets.Add(secret); + configDb.Set().Add(secret); - var testOrigin = new ClientCorsOrigin + configDb.Set().Add(new ClientCorsOrigin { ClientId = testingClient.Id, Origin = SiteSettings!.Audience + }); - }; - db.ClientCorsOrigins.Add(testOrigin); - db.ClientGrantTypes.Add(new ClientGrantType + configDb.Set().Add(new ClientGrantType { ClientId = testingClient.Id, GrantType = "client_credentials" }); - db.ClientGrantTypes.Add(new ClientGrantType + configDb.Set().Add(new ClientGrantType { ClientId = testingClient.Id, GrantType = "password" }); - db.ClientGrantTypes.Add(new ClientGrantType + configDb.Set().Add(new ClientGrantType { ClientId = testingClient.Id, GrantType = "code" }); - db.ClientScopes.Add(new ClientScope + configDb.Set().Add(new ClientScope { ClientId = testingClient.Id, Scope = "test" }); - db.ApiScopes.Add(new IdentityServer8.EntityFramework.Entities.ApiScope + configDb.Set().Add(new IdentityServer8.EntityFramework.Entities.ApiScope { Name = "test", Enabled = true }); - db.ClientRedirectUris.Add(new ClientRedirectUri + configDb.Set().Add(new ClientRedirectUri { ClientId = testingClient.Id, RedirectUri = SiteSettings!.Audience - }); - db.SaveChanges(); + configDb.SaveChanges(); } public void EnsureUser(string testingUserName, string password, string email, IServiceScope scope) From 5620213cf5667878af7e41ada1dced6e21bbbca8 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 19 Apr 2026 20:36:03 +0100 Subject: [PATCH 3/4] better --- src/Yavsc.Abstract/Billing/BillingCodes.cs | 6 +-- src/Yavsc.Server/Helpers/WorkflowHelpers.cs | 23 +++------ .../Models/ApplicationDbContext.cs | 1 - .../NonRegression/BillingServiceTests.cs | 2 +- test/yavscTests/WebServerFixture.cs | 50 +++++++++---------- 5 files changed, 34 insertions(+), 48 deletions(-) diff --git a/src/Yavsc.Abstract/Billing/BillingCodes.cs b/src/Yavsc.Abstract/Billing/BillingCodes.cs index 9ede8cf6..5c5cfde8 100644 --- a/src/Yavsc.Abstract/Billing/BillingCodes.cs +++ b/src/Yavsc.Abstract/Billing/BillingCodes.cs @@ -2,9 +2,9 @@ namespace Yavsc.Models.Billing { public static class BillingCodes { - public const string Rdv = "Rdv"; - public const string MBrush = "MBrush"; + public const string Rdv = nameof(Rdv); + public const string MBrush = nameof(MBrush); - public const string Brush = "Brush"; + public const string Brush = nameof(Brush); } } \ No newline at end of file diff --git a/src/Yavsc.Server/Helpers/WorkflowHelpers.cs b/src/Yavsc.Server/Helpers/WorkflowHelpers.cs index c0531ae6..6814ccd0 100644 --- a/src/Yavsc.Server/Helpers/WorkflowHelpers.cs +++ b/src/Yavsc.Server/Helpers/WorkflowHelpers.cs @@ -46,26 +46,15 @@ namespace Yavsc.Helpers lock (_billingLock) { string typeName = typeof(T).Name; - - // Only add if not already present (idempotent operation) - if (!BillingService.Billing.ContainsKey(code)) - { - BillingService.Billing.Add(code, getter); - } - else if (!BillingService.GlobalBillingMap.ContainsKey(typeName) || - BillingService.GlobalBillingMap[typeName] != code) - { - throw new InvalidOperationException($"Billing setup: code '{code}' already registered"); - } - - if (!BillingService.GlobalBillingMap.ContainsKey(typeName)) - { - BillingService.GlobalBillingMap.Add(typeName, code); - } - else if (BillingService.GlobalBillingMap[typeName] != code) + if (BillingService.GlobalBillingMap.ContainsKey(typeName)) { throw new InvalidOperationException($"Billing setup: type '{typeName}' already registered with different code"); } + if (BillingService.Billing.ContainsKey(code)) + { + throw new InvalidOperationException($"Billing setup: code '{code}' already registered with different type"); + } + BillingService.Billing.Add(code, getter); } } diff --git a/src/Yavsc.Server/Models/ApplicationDbContext.cs b/src/Yavsc.Server/Models/ApplicationDbContext.cs index 0e9e717a..6b73abba 100644 --- a/src/Yavsc.Server/Models/ApplicationDbContext.cs +++ b/src/Yavsc.Server/Models/ApplicationDbContext.cs @@ -348,7 +348,6 @@ namespace Yavsc.Models public DbSet PersistedGrants { get; set; } public DbSet DeviceFlowCodes { get; set; } - public DbSet YavscApiScopes { get; set; } public string NOW_SQL { get; private set; } } } diff --git a/test/yavscTests/NonRegression/BillingServiceTests.cs b/test/yavscTests/NonRegression/BillingServiceTests.cs index 7b4f2705..58dddcae 100644 --- a/test/yavscTests/NonRegression/BillingServiceTests.cs +++ b/test/yavscTests/NonRegression/BillingServiceTests.cs @@ -39,7 +39,7 @@ namespace yavscTests var firstRegistrar = new Func((db, id) => db.HairCutQueries.Include(q => q.Prestation).Include(q => q.Regularisation).Single(q => q.Id == id)); - const string testCode = "TestBrush"; + const string testCode = "Brush"; Assert.Throws(() => WorkflowHelpers.RegisterBilling(testCode, firstRegistrar)); diff --git a/test/yavscTests/WebServerFixture.cs b/test/yavscTests/WebServerFixture.cs index 1e211afb..e0a9549b 100644 --- a/test/yavscTests/WebServerFixture.cs +++ b/test/yavscTests/WebServerFixture.cs @@ -155,7 +155,9 @@ namespace isnd.tests ["Smtp:Host"] = "localhost", ["Smtp:Port"] = "25", ["Smtp:SenderName"] = "Yavsc Test", - ["Smtp:SenderEmail"] = "test@example.com" + ["Smtp:SenderEmail"] = "test@example.com", + ["Site:Audience"] = "https://localhost", + ["Site:Authority"] = "https://localhost" }); // Configure Kestrel for HTTPS with self-signed certificate on a dynamic port @@ -207,7 +209,13 @@ namespace isnd.tests { Name = "test", Enabled = true, - DisplayName = "Test API Scope" + DisplayName = "Test API Scope", + Description = "Scope for testing purposes", + UserClaims = new List + { + new IdentityServer8.EntityFramework.Entities.ApiScopeClaim { Type = "role" }, + new IdentityServer8.EntityFramework.Entities.ApiScopeClaim { Type = "email" } + } }); // Add a basic API resource for the test scope @@ -267,7 +275,7 @@ namespace isnd.tests private void AddAuthorizedClient(IServiceScope scope, string testClientId, string testClientSecret) { - var configDb = scope.ServiceProvider.GetRequiredService(); + var configDb = scope.ServiceProvider.GetRequiredService(); if (configDb == null) throw new InvalidOperationException("ConfigurationDbContext is not available for IdentityServer client seeding."); @@ -276,14 +284,25 @@ namespace isnd.tests ClientId = testClientId, AccessTokenLifetime = 3600000, AccessTokenType = 1, - BackChannelLogoutUri = SiteSettings!.Audience, ClientName = "Testing client", Enabled = true, RequireClientSecret = true }; - configDb.Clients.Add(testingClient); + configDb.Set().Add(testingClient); configDb.SaveChanges(); + var apiScope = new IdentityServer8.EntityFramework.Entities.ApiScope + { + Name = "test", + DisplayName = "Test Scope", + Description = "Scope for testing", + Enabled = true, + Required = false, + ShowInDiscoveryDocument = true, + Emphasize = false + }; + configDb.Set().Add(apiScope); + ClientSecret secret = new ClientSecret { Value = testClientSecret.Sha256(), @@ -292,12 +311,6 @@ namespace isnd.tests }; configDb.Set().Add(secret); - configDb.Set().Add(new ClientCorsOrigin - { - ClientId = testingClient.Id, - Origin = SiteSettings!.Audience - }); - configDb.Set().Add(new ClientGrantType { ClientId = testingClient.Id, @@ -308,26 +321,11 @@ namespace isnd.tests ClientId = testingClient.Id, GrantType = "password" }); - configDb.Set().Add(new ClientGrantType - { - ClientId = testingClient.Id, - GrantType = "code" - }); configDb.Set().Add(new ClientScope { ClientId = testingClient.Id, Scope = "test" }); - configDb.Set().Add(new IdentityServer8.EntityFramework.Entities.ApiScope - { - Name = "test", - Enabled = true - }); - configDb.Set().Add(new ClientRedirectUri - { - ClientId = testingClient.Id, - RedirectUri = SiteSettings!.Audience - }); configDb.SaveChanges(); } From 6cc0c519d288723b3164fd2e22b2017fb78da4a2 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Mon, 20 Apr 2026 00:35:51 +0100 Subject: [PATCH 4/4] tests OK --- .gitignore | 2 + Directory.Packages.props | 1 - src/Api/Program.cs | 3 +- src/Yavsc.Blogs/Program.cs | 2 +- src/Yavsc.Org/Extensions/HostingExtensions.cs | 88 +++++++------------ src/Yavsc.Org/Yavsc.Org.csproj | 2 - src/Yavsc.Server/Services/MailSender.cs | 7 +- src/Yavsc.Server/Services/TestMailSender.cs | 30 ------- src/Yavsc.Server/Settings/SmtpSettings.cs | 8 +- test/yavscTests/Mandatory/BatchTests.cs | 2 - test/yavscTests/NonRegression/EMailling.cs | 26 +++--- test/yavscTests/TestHelpers.cs | 37 -------- test/yavscTests/WebServerFixture.cs | 25 ++---- test/yavscTests/appsettings.json | 28 +++--- test/yavscTests/yavscTests.csproj | 9 +- 15 files changed, 82 insertions(+), 188 deletions(-) delete mode 100644 src/Yavsc.Server/Services/TestMailSender.cs delete mode 100644 test/yavscTests/TestHelpers.cs diff --git a/.gitignore b/.gitignore index 5fbdcfed..d3e3de9f 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,5 @@ yavsc-pre *.env generated/ *.lscache +*.Development.json +*.log diff --git a/Directory.Packages.props b/Directory.Packages.props index 26bd0ea5..3b2164c8 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -33,7 +33,6 @@ - diff --git a/src/Api/Program.cs b/src/Api/Program.cs index a9d08352..c88951b6 100644 --- a/src/Api/Program.cs +++ b/src/Api/Program.cs @@ -65,8 +65,9 @@ internal class Program new() { ValidateAudience = false, RoleClaimType = Constants.RoleClaimType }; options.MapInboundClaims = true; }); - + services.AddDbContext(options => + options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); services.AddTransient() diff --git a/src/Yavsc.Blogs/Program.cs b/src/Yavsc.Blogs/Program.cs index f5d7e2be..96918dc5 100644 --- a/src/Yavsc.Blogs/Program.cs +++ b/src/Yavsc.Blogs/Program.cs @@ -70,7 +70,7 @@ internal class Program new() { ValidateAudience = false, RoleClaimType = Constants.RoleClaimType }; options.MapInboundClaims = true; }); - + services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName))); diff --git a/src/Yavsc.Org/Extensions/HostingExtensions.cs b/src/Yavsc.Org/Extensions/HostingExtensions.cs index 1eb53c84..67a7f2f7 100644 --- a/src/Yavsc.Org/Extensions/HostingExtensions.cs +++ b/src/Yavsc.Org/Extensions/HostingExtensions.cs @@ -85,18 +85,9 @@ public static class HostingExtensions options.ResourcesPath = "Resources"; }).AddDataAnnotationsLocalization(); - bool useTestEmailSender = builder.Configuration.GetValue("UseTestEmailSender", false); - - if (useTestEmailSender) - { - services.AddTransient() - .AddTransient(); - } - else - { services.AddTransient() .AddTransient(); - } + services.AddTransient() .AddTransient() @@ -147,21 +138,12 @@ public static class HostingExtensions public static IdentityBuilder AddIdentityDBAndStores(this WebApplicationBuilder builder) { IServiceCollection services = builder.Services; - bool useInMemory = builder.Configuration.GetValue("UseInMemoryDatabase", false); - - if (useInMemory) + + services.AddDbContext(options => { - services.AddDbContext(options => - options.UseSqlite("Data Source=file::memory:?cache=shared")); - } - else - { - services.AddDbContext(options => - { - options.UseNpgsql(builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName), - options => options.MigrationsAssembly(typeof(Program).Assembly)); - }); - } + options.UseNpgsql(builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName), + options => options.MigrationsAssembly(typeof(Program).Assembly)); + }); var identityBuilder = services.AddIdentity( options => @@ -280,8 +262,8 @@ public static class HostingExtensions }); var migrationsAssembly = typeof(Program).GetTypeInfo().Assembly.GetName().Name; var connectionString = builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName); - bool useInMemory = builder.Configuration.GetValue("UseInMemoryDatabase", false); - string sqliteInMemoryConnectionString = "Data Source=file::memory:?cache=shared"; + + string sqliteConnectionString = $"Data Source={Path.Combine(Path.GetTempPath(), "yavsc_test.db")}"; var identityServerBuilder = builder.Services.AddIdentityServer(options => { @@ -301,40 +283,15 @@ public static class HostingExtensions .AddResourceStore() .AddConfigurationStore(options => { - if (useInMemory) - { - options.ConfigureDbContext = b => b.UseSqlite(sqliteInMemoryConnectionString); - } - else - { - options.ConfigureDbContext = b => b.UseNpgsql(connectionString, - sql => sql.MigrationsAssembly(migrationsAssembly)) - .UseSeeding((context, _) => - { - foreach (String scope in new string[] { "blog", "admin", "contract", "com"}) - { - var testBlog = context.Set().FirstOrDefault(b => b.Name == scope); - if (testBlog == null) - { - context.Set().Add(new ApiScope { Name = scope }); - context.SaveChanges(); - } - } - - }); - } + options.ConfigureDbContext = b => b.UseNpgsql(connectionString, + sql => sql.MigrationsAssembly(migrationsAssembly)) + .UseSeeding(EnsureDefaultApplicationScopes()); }) .AddOperationalStore(options => { - if (useInMemory) - { - options.ConfigureDbContext = b => b.UseSqlite(sqliteInMemoryConnectionString); - } - else - { - options.ConfigureDbContext = b => b.UseNpgsql(connectionString, - sql => sql.MigrationsAssembly(migrationsAssembly)); - } + options.ConfigureDbContext = b => b.UseNpgsql(connectionString, + sql => sql.MigrationsAssembly(migrationsAssembly)); + }); if (builder.Environment.IsDevelopment()) @@ -344,6 +301,23 @@ public static class HostingExtensions return identityServerBuilder; } + private static Action EnsureDefaultApplicationScopes() + { + return (context, _) => + { + foreach (String scope in new string[] { "blog", "admin", "contract", "com" }) + { + var existentScope = context.Set().FirstOrDefault(b => b.Name == scope); + if (existentScope == null) + { + context.Set().Add(new ApiScope { Name = scope }); + context.SaveChanges(); + } + } + + }; + } + private static void ConfigureRequestLocalization(IServiceCollection services) { services.Configure(options => diff --git a/src/Yavsc.Org/Yavsc.Org.csproj b/src/Yavsc.Org/Yavsc.Org.csproj index a1867d41..60d06a07 100644 --- a/src/Yavsc.Org/Yavsc.Org.csproj +++ b/src/Yavsc.Org/Yavsc.Org.csproj @@ -31,8 +31,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - diff --git a/src/Yavsc.Server/Services/MailSender.cs b/src/Yavsc.Server/Services/MailSender.cs index b61dbd6b..14cb17ba 100644 --- a/src/Yavsc.Server/Services/MailSender.cs +++ b/src/Yavsc.Server/Services/MailSender.cs @@ -47,9 +47,9 @@ namespace Yavsc.Services /// a MessageWithPayloadResponse, /// bool somethingsent = (response.failure == 0 && response.success > 0) /// - public async Task SendEmailAsync(string email, string subject, string htmlMessage) + public Task SendEmailAsync(string email, string subject, string htmlMessage) { - await SendEmailAsync("", email, subject, htmlMessage); + return SendEmailAsync("", email, subject, htmlMessage); } public async Task SendEmailAsync(string name, string email, string subject, string htmlMessage) @@ -71,8 +71,9 @@ namespace Yavsc.Services ); using (SmtpClient sc = new()) { + sc.Timeout = 30000; sc.Connect( - smtpSettings.Server, + smtpSettings.Host, smtpSettings.Port, SecureSocketOptions.Auto ); diff --git a/src/Yavsc.Server/Services/TestMailSender.cs b/src/Yavsc.Server/Services/TestMailSender.cs deleted file mode 100644 index 9e91dfef..00000000 --- a/src/Yavsc.Server/Services/TestMailSender.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity.UI.Services; -using Microsoft.Extensions.Logging; -using Yavsc.Interface; - -namespace Yavsc.Services -{ - public class TestMailSender : ITrueEmailSender, IEmailSender - { - private readonly ILogger logger; - - public TestMailSender(ILoggerFactory loggerFactory) - { - logger = loggerFactory.CreateLogger(); - } - - public Task SendEmailAsync(string email, string subject, string htmlMessage) - { - logger.LogInformation("[TestMailSender] SendEmailAsync to {Email} subject={Subject}", email, subject); - return Task.CompletedTask; - } - - public Task SendEmailAsync(string name, string email, string subject, string htmlMessage) - { - logger.LogInformation("[TestMailSender] SendEmailAsync to {Email} subject={Subject} name={Name}", email, subject, name); - return Task.FromResult($"test-message-{Guid.NewGuid()}"); - } - } -} diff --git a/src/Yavsc.Server/Settings/SmtpSettings.cs b/src/Yavsc.Server/Settings/SmtpSettings.cs index ca0cdd1d..7f1e3616 100644 --- a/src/Yavsc.Server/Settings/SmtpSettings.cs +++ b/src/Yavsc.Server/Settings/SmtpSettings.cs @@ -2,17 +2,13 @@ namespace Yavsc.Settings { public class SmtpSettings { - public string Server { get; set; } public string Host { - get => Server; - set => Server = value; + get ; + set ; } public int Port { get; set; } - - public string SenderName { get; set; } - public string SenderEmail { get; set; } public string UserName { get; set; } public string Password { get; set; } } diff --git a/test/yavscTests/Mandatory/BatchTests.cs b/test/yavscTests/Mandatory/BatchTests.cs index e16bd368..c0e9990e 100644 --- a/test/yavscTests/Mandatory/BatchTests.cs +++ b/test/yavscTests/Mandatory/BatchTests.cs @@ -53,8 +53,6 @@ namespace yavscTests public void HaveConfigurationRoot() { var builder = new ConfigurationBuilder(); - builder.AddJsonFile( "appsettings.json", false); - builder.AddJsonFile( "appsettings.Development.json", true); configurationRoot = builder.Build(); } diff --git a/test/yavscTests/NonRegression/EMailling.cs b/test/yavscTests/NonRegression/EMailling.cs index eab947eb..8e35f953 100644 --- a/test/yavscTests/NonRegression/EMailling.cs +++ b/test/yavscTests/NonRegression/EMailling.cs @@ -25,20 +25,18 @@ namespace yavscTests [Fact] public void SendEMailSynchrone() { - AssertAsync.CompletesIn(2, () => - { - using IServiceScope scope = _serverFixture.Services.CreateScope(); - ITrueEmailSender mailSender = scope.ServiceProvider.GetRequiredService(); - - output.WriteLine("SendEMailSynchrone ..."); - mailSender.SendEmailAsync - ( - _serverFixture.SiteSettings.Owner.Name, - _serverFixture.SiteSettings.Owner.EMail, - $"monthly email", - "test boby monthly email").Wait(); - }); - } + using IServiceScope scope = _serverFixture.Services.CreateScope(); + ITrueEmailSender mailSender = scope.ServiceProvider.GetRequiredService(); + + output.WriteLine("SendEMailSynchrone ..."); + mailSender.SendEmailAsync + ( + _serverFixture.SiteSettings.Owner.Name, + _serverFixture.SiteSettings.Owner.EMail, + $"monthly email", + "test boby monthly email").Wait(); + + } } } diff --git a/test/yavscTests/TestHelpers.cs b/test/yavscTests/TestHelpers.cs deleted file mode 100644 index e44957d4..00000000 --- a/test/yavscTests/TestHelpers.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace yavscTests { - - public static class AssertAsync { - /// - /// Completes In - /// - /// - /// - public static void CompletesIn(int timeoutFromSecond, Action action) - { - var task = Task.Run(action); - var completedInTime = Task.WaitAll(new[] { task }, TimeSpan.FromSeconds(timeoutFromSecond)); - - if (task.Exception != null) - { - if (task.Exception.InnerExceptions.Count == 1) - { - throw task.Exception.InnerExceptions[0]; - } - - throw task.Exception; - } - - if (!completedInTime) - { - throw new TimeoutException($"Task did not complete in {timeoutFromSecond} seconds."); - } - } - } - -} - - - diff --git a/test/yavscTests/WebServerFixture.cs b/test/yavscTests/WebServerFixture.cs index e0a9549b..a569b29f 100644 --- a/test/yavscTests/WebServerFixture.cs +++ b/test/yavscTests/WebServerFixture.cs @@ -1,4 +1,4 @@ -using IdentityServer8.EntityFramework.DbContexts; + using IdentityServer8.EntityFramework.Entities; using IdentityServer8.Models; using Microsoft.AspNetCore.Builder; @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -137,28 +137,16 @@ namespace isnd.tests var builder = WebApplication.CreateBuilder(); builder.Environment.EnvironmentName = "Development"; - // Set ContentRoot to the Yavsc.Org project directory so WebRootPath resolves correctly var testAssemblyLocation = AppDomain.CurrentDomain.BaseDirectory; var yavscOrgPath = Path.GetFullPath(Path.Combine(testAssemblyLocation, "../../src/Yavsc.Org")); builder.Environment.ContentRootPath = yavscOrgPath; ConfigureLogger(); - builder.Configuration + var config = builder.Configuration .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) - .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: false) - .AddEnvironmentVariables() - .AddInMemoryCollection(new Dictionary - { - ["UseInMemoryDatabase"] = "true", - ["UseTestEmailSender"] = "true", - ["Smtp:Host"] = "localhost", - ["Smtp:Port"] = "25", - ["Smtp:SenderName"] = "Yavsc Test", - ["Smtp:SenderEmail"] = "test@example.com", - ["Site:Audience"] = "https://localhost", - ["Site:Authority"] = "https://localhost" - }); + .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: false, reloadOnChange: false) + .AddEnvironmentVariables().Build(); // Configure Kestrel for HTTPS with self-signed certificate on a dynamic port builder.WebHost.ConfigureKestrel(options => @@ -174,6 +162,7 @@ namespace isnd.tests _app = builder.ConfigureWebAppServices(); Services = _app.Services; SiteSettings = _app.Services.GetRequiredService>().Value; + String cxStr = config.GetConnectionString(Constants.YavscConnectionStringName) ?? throw new InvalidOperationException("DefaultConnection string is not configured."); using (var migrationScope = _app.Services.CreateScope()) { @@ -181,7 +170,7 @@ namespace isnd.tests db.Database.EnsureDeleted(); db.Database.EnsureCreated(); TestingUserName = "Tester"; - TestingUserPassword = "tesT456+*"; + TestingUserPassword = "Test123!"; TestClientId = "testClientId"; TestingUserEmail = "test@no-reply.com"; TestingUser = null; diff --git a/test/yavscTests/appsettings.json b/test/yavscTests/appsettings.json index 28b36a57..107dae86 100644 --- a/test/yavscTests/appsettings.json +++ b/test/yavscTests/appsettings.json @@ -1,6 +1,7 @@ { "Site": { - "Authority": "https://localhost", + "Audience": "https://localhost", + "Authority": "https://mercure.pschneider.fr", "Title": "Yavsc dev", "Slogan": "Yavsc : WIP.", "Banner": "/images/yavsc.png", @@ -26,14 +27,11 @@ } }, "Smtp": { - "Host": "localhost", - "Port": 25, - "EnableSSL": false + "Server": "localhost", + "Port": 465 }, "Logging": { - "IncludeScopes": { - - }, + "IncludeScopes": {}, "LogLevel": { "Default": "Debug", "System": "Warning", @@ -41,8 +39,8 @@ } }, "ConnectionStrings": { - "YavscConnection": "Server=lame-NpgsqlHostName;Port=5432;Database=lame-DataBase;Username=lame-Username;Password=lame-dbPassword;" - }, + "YavscConnection": "Server=localhost;Port=5432;Database=testingYavsc;Username=lame-Username;Password=lame-dbPassword;" + }, "DataProtection": { "Keys": { "Dir": "DataProtection-Keys" @@ -56,14 +54,14 @@ "Default": "lame-default-connection-string", "DatabaseCtor": "lame-database-ctor-connection-string" }, - "YavscWebPath": "../../src/Yavsc", + "YavscWebPath": "../../src/Yavsc", "ValidCreds": { - "UserName": "lame-user", - "Password": "lame-password" + "UserName": "lame-user", + "Password": "lame-password" }, "InvalidCreds": { - "UserName": "fakeuser", - "Password": "f/\\kePassw0rd" + "UserName": "fakeuser", + "Password": "f/\\kePassw0rd" } } -} +} \ No newline at end of file diff --git a/test/yavscTests/yavscTests.csproj b/test/yavscTests/yavscTests.csproj index df1ff580..6fd4a752 100644 --- a/test/yavscTests/yavscTests.csproj +++ b/test/yavscTests/yavscTests.csproj @@ -1,10 +1,11 @@ - + net10.0 enable enable false Yavsc.Tests + 78a4efec-68dc-4745-ba06-d8545ef9ee91 @@ -29,6 +30,11 @@ Always + + + Always + + @@ -37,4 +43,5 @@ +