diff --git a/Directory.Packages.props b/Directory.Packages.props index f725fd27..aef0ebec 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -40,6 +40,7 @@ + diff --git a/infra/modules/postgresql.bicep b/infra/modules/postgresql.bicep deleted file mode 100644 index eb1ab6aa..00000000 --- a/infra/modules/postgresql.bicep +++ /dev/null @@ -1,89 +0,0 @@ -targetScope = 'resourceGroup' - -@description('The list of firewall rules to install') -param firewallRules FirewallRule[] = [ - { startIpAddress: '0.0.0.0', endIpAddress: '0.0.0.0' } -] - -@minLength(1) -@description('The name of the test database to create') -param databaseName string = 'unittests' - -@minLength(1) -@description('Primary location for all resources') -param location string = resourceGroup().location - -@description('The name of the SQL Server to create.') -param sqlServerName string - -@description('Optional - the SQL Server administrator password. If not provided, the username will be \'appadmin\'.') -param sqlAdminUsername string = 'appadmin' - -@secure() -@description('Optional - SQL Server administrator password. If not provided, a random password will be generated.') -param sqlAdminPassword string = newGuid() - -@description('The list of tags to apply to all resources.') -param tags object = {} - -/*********************************************************************************/ - -resource pgsql_server 'Microsoft.DBforPostgreSQL/flexibleServers@2023-06-01-preview' = { - name: sqlServerName - location: location - tags: tags - sku: { - name: 'Standard_B1ms' - tier: 'Burstable' - } - properties: { - administratorLogin: sqlAdminUsername - administratorLoginPassword: sqlAdminPassword - createMode: 'Default' - authConfig: { - activeDirectoryAuth: 'Disabled' - passwordAuth: 'Enabled' - } - backup: { - backupRetentionDays: 7 - geoRedundantBackup: 'Disabled' - } - highAvailability: { - mode: 'Disabled' - } - storage: { - storageSizeGB: 32 - autoGrow: 'Disabled' - } - version: '15' - } - - resource fw 'firewallRules' = [ for (fwRule, idx) in firewallRules : { - name: 'fw${idx}' - properties: { - startIpAddress: fwRule.startIpAddress - endIpAddress: fwRule.endIpAddress - } - }] -} - -resource pgsql_database 'Microsoft.DBforPostgreSQL/flexibleServers/databases@2023-03-01-preview' = { - name: databaseName - parent: pgsql_server - properties: { - charset: 'UTF8' - collation: 'en_US.utf8' - } -} - -/*********************************************************************************/ - -#disable-next-line outputs-should-not-contain-secrets -output PGSQL_CONNECTIONSTRING string = 'Host=${pgsql_server.properties.fullyQualifiedDomainName};Database=${pgsql_database.name};Username=${pgsql_server.properties.administratorLogin};Password=${sqlAdminPassword}' - -/*********************************************************************************/ - -type FirewallRule = { - startIpAddress: string - endIpAddress: string -} diff --git a/infra/resources.bicep b/infra/resources.bicep index 42b2501c..6457e00d 100644 --- a/infra/resources.bicep +++ b/infra/resources.bicep @@ -33,7 +33,6 @@ var appServicePlanName = 'asp-${resourceToken}' var appServiceName = 'web-${resourceToken}' var azsqlServerName = 'sql-${resourceToken}' var cosmosServerName = 'cosmos-${resourceToken}' -var pgsqlServerName = 'pgsql-${resourceToken}' var mongoServerName = 'mongo-${resourceToken}' var mongoaciServerName = 'mongoaci-${resourceToken}' @@ -67,19 +66,6 @@ module azuresql './modules/azuresql.bicep' = { } } -module pgsql './modules/postgresql.bicep' = { - name: 'pgsql-deployment-${resourceToken}' - params: { - location: location - tags: tags - databaseName: testDatabaseName - firewallRules: clientIpFirewallRules - sqlServerName: pgsqlServerName - sqlAdminUsername: sqlAdminUsername - sqlAdminPassword: sqlAdminPassword - } -} - module cosmos './modules/cosmos.bicep' = { name: 'cosmos-deployment-${resourceToken}' params: { @@ -136,5 +122,4 @@ output AZSQL_CONNECTIONSTRING string = azuresql.outputs.AZSQL_CONNECTIONSTRING output COSMOS_CONNECTIONSTRING string = cosmos.outputs.COSMOS_CONNECTIONSTRING output MONGO_CONNECTIONSTRING string = mongodb.outputs.MONGO_CONNECTIONSTRING output MONGOACI_CONNECTIONSTRING string = mongoaci.outputs.MONGO_CONNECTIONSTRING -output PGSQL_CONNECTIONSTRING string = pgsql.outputs.PGSQL_CONNECTIONSTRING output SERVICE_ENDPOINT string = app_service.outputs.SERVICE_ENDPOINT diff --git a/tests/CommunityToolkit.Datasync.Server.EntityFrameworkCore.Test/AzureSqlEntityTableRepository_Tests.cs b/tests/CommunityToolkit.Datasync.Server.EntityFrameworkCore.Test/AzureSqlEntityTableRepository_Tests.cs index a3c0e3bc..dadd5d81 100644 --- a/tests/CommunityToolkit.Datasync.Server.EntityFrameworkCore.Test/AzureSqlEntityTableRepository_Tests.cs +++ b/tests/CommunityToolkit.Datasync.Server.EntityFrameworkCore.Test/AzureSqlEntityTableRepository_Tests.cs @@ -4,6 +4,7 @@ using CommunityToolkit.Datasync.TestCommon; using CommunityToolkit.Datasync.TestCommon.Databases; +using CommunityToolkit.Datasync.TestCommon.Fixtures; using Microsoft.EntityFrameworkCore; using Xunit.Abstractions; @@ -13,7 +14,7 @@ namespace CommunityToolkit.Datasync.Server.EntityFrameworkCore.Test; [ExcludeFromCodeCoverage] [Collection("LiveTestsCollection")] -public class AzureSqlEntityTableRepository_Tests(DatabaseFixture fixture, ITestOutputHelper output) : RepositoryTests, IAsyncLifetime +public class AzureSqlEntityTableRepository_Tests(MsSqlDatabaseFixture fixture, ITestOutputHelper output) : RepositoryTests, IClassFixture, IAsyncLifetime { #region Setup private readonly Random random = new(); @@ -21,11 +22,8 @@ public class AzureSqlEntityTableRepository_Tests(DatabaseFixture fixture, ITestO public async Task InitializeAsync() { - if (!string.IsNullOrEmpty(ConnectionStrings.AzureSql)) - { - Context = await AzureSqlDbContext.CreateContextAsync(ConnectionStrings.AzureSql, output); - this.movies = await Context.Movies.AsNoTracking().ToListAsync(); - } + Context = await AzureSqlDbContext.CreateContextAsync(fixture.ConnectionString, output); + this.movies = await Context.Movies.AsNoTracking().ToListAsync(); } public async Task DisposeAsync() @@ -38,7 +36,7 @@ public async Task DisposeAsync() private AzureSqlDbContext Context { get; set; } - protected override bool CanRunLiveTests() => !string.IsNullOrEmpty(ConnectionStrings.AzureSql); + protected override bool CanRunLiveTests() => true; protected override async Task GetEntityAsync(string id) => await Context.Movies.AsNoTracking().SingleOrDefaultAsync(m => m.Id == id); diff --git a/tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL_Controller_Tests.cs b/tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL_Controller_Tests.cs index bbfbdd6a..5e5abc9e 100644 --- a/tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL_Controller_Tests.cs +++ b/tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL_Controller_Tests.cs @@ -5,6 +5,7 @@ using CommunityToolkit.Datasync.Server.EntityFrameworkCore; using CommunityToolkit.Datasync.Server.Test.Helpers; using CommunityToolkit.Datasync.TestCommon.Databases; +using CommunityToolkit.Datasync.TestCommon.Fixtures; using Microsoft.EntityFrameworkCore; using Xunit.Abstractions; @@ -12,7 +13,7 @@ namespace CommunityToolkit.Datasync.Server.Test.Live; [ExcludeFromCodeCoverage] [Collection("LiveTestsCollection")] -public class AzureSQL_Controller_Tests(DatabaseFixture fixture, ITestOutputHelper output) : LiveControllerTests, IAsyncLifetime +public class AzureSQL_Controller_Tests(MsSqlDatabaseFixture fixture, ITestOutputHelper output) : LiveControllerTests, IClassFixture, IAsyncLifetime { #region Setup private readonly Random random = new(); @@ -20,16 +21,8 @@ public class AzureSQL_Controller_Tests(DatabaseFixture fixture, ITestOutputHelpe public async Task InitializeAsync() { - if (!string.IsNullOrEmpty(ConnectionStrings.AzureSql)) - { - // Note: we don't clear entities on every run to speed up the test runs. This can only be done because - // the tests are read-only (associated with the query and get capabilities). If the test being run writes - // to the database then change clearEntities to true. - output.WriteLine($"AzureSqlIsInitialized = {fixture.AzureSqlIsInitialized}"); - Context = await AzureSqlDbContext.CreateContextAsync(ConnectionStrings.AzureSql, output, clearEntities: !fixture.AzureSqlIsInitialized); - this.movies = await Context.Movies.AsNoTracking().ToListAsync(); - fixture.AzureSqlIsInitialized = true; - } + Context = await AzureSqlDbContext.CreateContextAsync(fixture.ConnectionString, output); + this.movies = await Context.Movies.AsNoTracking().ToListAsync(); } public async Task DisposeAsync() @@ -44,7 +37,7 @@ public async Task DisposeAsync() protected override string DriverName { get; } = "AzureSQL"; - protected override bool CanRunLiveTests() => !string.IsNullOrEmpty(ConnectionStrings.AzureSql); + protected override bool CanRunLiveTests() => true; protected override Task GetEntityAsync(string id) => Task.FromResult(Context.Movies.AsNoTracking().SingleOrDefault(m => m.Id == id)); diff --git a/tests/CommunityToolkit.Datasync.TestCommon/CommunityToolkit.Datasync.TestCommon.csproj b/tests/CommunityToolkit.Datasync.TestCommon/CommunityToolkit.Datasync.TestCommon.csproj index 7e8f0d9a..89d1186c 100644 --- a/tests/CommunityToolkit.Datasync.TestCommon/CommunityToolkit.Datasync.TestCommon.csproj +++ b/tests/CommunityToolkit.Datasync.TestCommon/CommunityToolkit.Datasync.TestCommon.csproj @@ -20,6 +20,7 @@ + diff --git a/tests/CommunityToolkit.Datasync.TestCommon/Databases/ConnectionStrings.cs b/tests/CommunityToolkit.Datasync.TestCommon/Databases/ConnectionStrings.cs index 16c9b4b6..4c0c324d 100644 --- a/tests/CommunityToolkit.Datasync.TestCommon/Databases/ConnectionStrings.cs +++ b/tests/CommunityToolkit.Datasync.TestCommon/Databases/ConnectionStrings.cs @@ -7,7 +7,6 @@ namespace CommunityToolkit.Datasync.TestCommon.Databases; [ExcludeFromCodeCoverage] public static class ConnectionStrings { - public static readonly string AzureSql = Environment.GetEnvironmentVariable("AZSQL_CONNECTION_STRING"); public static readonly string CosmosDb = Environment.GetEnvironmentVariable("COSMOS_CONNECTION_STRING"); public static readonly string MongoCommunity = Environment.GetEnvironmentVariable("MONGOACI_CONNECTION_STRING"); public static readonly string CosmosMongo = Environment.GetEnvironmentVariable("MONGO_CONNECTION_STRING"); diff --git a/tests/CommunityToolkit.Datasync.TestCommon/Fixtures/MsSqlDatabaseFixture.cs b/tests/CommunityToolkit.Datasync.TestCommon/Fixtures/MsSqlDatabaseFixture.cs new file mode 100644 index 00000000..2988a9e0 --- /dev/null +++ b/tests/CommunityToolkit.Datasync.TestCommon/Fixtures/MsSqlDatabaseFixture.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Testcontainers.MsSql; +using Xunit; + +namespace CommunityToolkit.Datasync.TestCommon.Fixtures; + +[ExcludeFromCodeCoverage] +public class MsSqlDatabaseFixture : IAsyncLifetime +{ + private readonly MsSqlContainer _container; + + public MsSqlDatabaseFixture() + { + this._container = new MsSqlBuilder() + .Build(); + } + + /// + public async Task DisposeAsync() + { + if (this._container is not null) + { + await this._container.DisposeAsync(); + } + } + + /// + public async Task InitializeAsync() + { + await this._container.StartAsync(); + ConnectionString = this._container.GetConnectionString(); + } + + /// + /// The connection string for the MySQL database. + /// + public string ConnectionString { get; private set; } = string.Empty; +} diff --git a/tests/CommunityToolkit.Datasync.TestCommon/Fixtures/MySqlTestFixture.cs b/tests/CommunityToolkit.Datasync.TestCommon/Fixtures/MySqlTestFixture.cs new file mode 100644 index 00000000..e69de29b