2019-05-11 02:18:58 +03:00
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------
2020-02-10 20:36:48 +03:00
using System ;
2024-05-08 00:54:57 +03:00
using System.Diagnostics ;
2019-05-11 02:18:58 +03:00
using System.Text ;
2020-02-10 20:36:48 +03:00
using System.Threading ;
2019-05-11 02:18:58 +03:00
using System.Threading.Tasks ;
2020-10-15 19:40:36 +03:00
using EnsureThat ;
2020-09-16 17:34:26 +03:00
using MediatR ;
2020-10-15 19:40:36 +03:00
using Microsoft.Data.SqlClient ;
2022-05-10 01:20:09 +03:00
using Microsoft.Extensions.DependencyInjection ;
2020-02-10 20:36:48 +03:00
using Microsoft.Extensions.Logging.Abstractions ;
2021-07-15 03:39:01 +03:00
using Microsoft.Extensions.Options ;
2020-02-10 20:36:48 +03:00
using Microsoft.Health.Fhir.SqlServer.Features.Schema ;
2020-06-26 23:40:54 +03:00
using Microsoft.Health.Fhir.SqlServer.Features.Storage ;
2022-11-08 20:46:39 +03:00
using Microsoft.Health.Fhir.SqlServer.Features.Watchdogs ;
2022-10-31 21:17:02 +03:00
using Microsoft.Health.JobManagement.UnitTests ;
2020-10-15 19:40:36 +03:00
using Microsoft.Health.SqlServer ;
2020-03-28 01:19:05 +03:00
using Microsoft.Health.SqlServer.Configs ;
2022-05-10 01:20:09 +03:00
using Microsoft.Health.SqlServer.Features.Client ;
2020-03-28 01:19:05 +03:00
using Microsoft.Health.SqlServer.Features.Schema ;
2021-02-17 02:10:18 +03:00
using Microsoft.Health.SqlServer.Features.Schema.Manager ;
2022-05-10 01:20:09 +03:00
using Microsoft.Health.SqlServer.Features.Storage ;
2020-09-16 17:34:26 +03:00
using NSubstitute ;
2020-02-10 20:36:48 +03:00
using Polly ;
2021-11-30 21:59:04 +03:00
using Polly.Retry ;
2019-05-11 02:18:58 +03:00
using Xunit ;
2020-02-10 20:36:48 +03:00
using Task = System . Threading . Tasks . Task ;
2019-05-11 02:18:58 +03:00
namespace Microsoft.Health.Fhir.Tests.Integration.Persistence
{
2020-02-10 20:36:48 +03:00
public class SqlServerFhirStorageTestHelper : IFhirStorageTestHelper , ISqlServerFhirStorageTestHelper
2019-05-11 02:18:58 +03:00
{
2020-10-15 19:40:36 +03:00
private readonly string _masterDatabaseName ;
2020-02-10 20:36:48 +03:00
private readonly string _initialConnectionString ;
2020-06-26 23:40:54 +03:00
private readonly SqlServerFhirModel _sqlServerFhirModel ;
2022-02-10 03:45:33 +03:00
private readonly ISqlConnectionBuilder _sqlConnectionBuilder ;
2021-11-30 21:59:04 +03:00
private readonly AsyncRetryPolicy _dbSetupRetryPolicy ;
2022-10-31 21:17:02 +03:00
private readonly TestQueueClient _queueClient ;
2024-06-17 18:53:50 +03:00
private static readonly SemaphoreSlim DbSetupSemaphore = new ( 14 ) ; // max number of concurrent requests to the master database is 64 and we run 4 FHIR versions in parallel
2019-05-11 02:18:58 +03:00
2020-11-12 02:01:26 +03:00
public SqlServerFhirStorageTestHelper (
string initialConnectionString ,
string masterDatabaseName ,
SqlServerFhirModel sqlServerFhirModel ,
2022-10-31 21:17:02 +03:00
ISqlConnectionBuilder sqlConnectionBuilder ,
TestQueueClient queueClient )
2019-05-11 02:18:58 +03:00
{
2020-11-12 02:01:26 +03:00
EnsureArg . IsNotNull ( sqlServerFhirModel , nameof ( sqlServerFhirModel ) ) ;
2022-02-10 03:45:33 +03:00
EnsureArg . IsNotNull ( sqlConnectionBuilder , nameof ( sqlConnectionBuilder ) ) ;
2020-10-15 19:40:36 +03:00
_masterDatabaseName = masterDatabaseName ;
2020-02-10 20:36:48 +03:00
_initialConnectionString = initialConnectionString ;
2020-06-26 23:40:54 +03:00
_sqlServerFhirModel = sqlServerFhirModel ;
2022-02-10 03:45:33 +03:00
_sqlConnectionBuilder = sqlConnectionBuilder ;
2022-10-31 21:17:02 +03:00
_queueClient = queueClient ;
2021-11-30 21:59:04 +03:00
_dbSetupRetryPolicy = Policy
2022-11-08 20:46:39 +03:00
. Handle < Exception > ( )
2021-11-30 21:59:04 +03:00
. WaitAndRetryAsync (
2024-06-17 18:53:50 +03:00
retryCount : 5 ,
2024-05-08 00:54:57 +03:00
sleepDurationProvider : retryAttempt = > TimeSpan . FromSeconds ( 3 ) ) ;
2020-02-10 20:36:48 +03:00
}
2021-01-21 17:16:56 +03:00
public async Task CreateAndInitializeDatabase ( string databaseName , int maximumSupportedSchemaVersion , bool forceIncrementalSchemaUpgrade , SchemaInitializer schemaInitializer = null , CancellationToken cancellationToken = default )
2020-02-10 20:36:48 +03:00
{
2024-05-08 00:54:57 +03:00
string testConnectionString = new SqlConnectionStringBuilder ( _initialConnectionString ) { InitialCatalog = databaseName } . ToString ( ) ;
2020-02-10 20:36:48 +03:00
2024-05-08 00:54:57 +03:00
await _dbSetupRetryPolicy . ExecuteAsync (
async ( ) = >
{
// Create the database.
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( _masterDatabaseName , null , cancellationToken ) ;
await connection . OpenAsync ( cancellationToken ) ;
2020-02-10 20:36:48 +03:00
2024-05-08 00:54:57 +03:00
await using SqlCommand command = connection . CreateCommand ( ) ;
2024-06-17 18:53:50 +03:00
command . CommandTimeout = 300 ;
2024-05-08 00:54:57 +03:00
command . CommandText = @ $ "
2021-01-21 17:16:56 +03:00
IF NOT EXISTS ( SELECT * FROM sys . databases WHERE name = ' { databaseName } ' )
BEGIN
CREATE DATABASE { databaseName } ;
END ";
2024-05-08 00:54:57 +03:00
await DbSetupSemaphore . WaitAsync ( cancellationToken ) ;
try
{
await command . ExecuteNonQueryAsync ( cancellationToken ) ;
}
finally
{
DbSetupSemaphore . Release ( ) ;
}
await connection . CloseAsync ( ) ;
} ) ;
2020-02-10 20:36:48 +03:00
// Verify that we can connect to the new database. This sometimes does not work right away with Azure SQL.
2021-11-30 21:59:04 +03:00
2024-05-08 00:54:57 +03:00
await _dbSetupRetryPolicy . ExecuteAsync (
async ( ) = >
{
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( databaseName , null , cancellationToken ) ;
await connection . OpenAsync ( cancellationToken ) ;
await using SqlCommand sqlCommand = connection . CreateCommand ( ) ;
2024-10-15 19:23:29 +03:00
sqlCommand . CommandText = "IF object_id('sp_changedbowner') IS NOT NULL EXECUTE sp_changedbowner 'sa'" ;
await sqlCommand . ExecuteNonQueryAsync ( cancellationToken ) ;
2024-05-08 00:54:57 +03:00
await connection . CloseAsync ( ) ;
} ) ;
2020-02-10 20:36:48 +03:00
2024-05-08 00:54:57 +03:00
schemaInitializer ? ? = CreateSchemaInitializer ( testConnectionString , maximumSupportedSchemaVersion ) ;
await _dbSetupRetryPolicy . ExecuteAsync ( async ( ) = > { await schemaInitializer . InitializeAsync ( forceIncrementalSchemaUpgrade , cancellationToken ) ; } ) ;
2024-01-04 02:36:52 +03:00
await InitWatchdogsParameters ( databaseName ) ;
await EnableDatabaseLogging ( databaseName ) ;
2024-06-19 01:18:35 +03:00
await _sqlServerFhirModel . Initialize ( maximumSupportedSchemaVersion , cancellationToken ) ;
2020-02-10 20:36:48 +03:00
}
2024-01-04 02:36:52 +03:00
public async Task EnableDatabaseLogging ( string databaseName )
2022-11-08 20:46:39 +03:00
{
2024-01-04 02:36:52 +03:00
await _dbSetupRetryPolicy . ExecuteAsync ( async ( ) = >
{
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( databaseName , cancellationToken : CancellationToken . None ) ;
await connection . OpenAsync ( CancellationToken . None ) ;
await using SqlCommand sqlCommand = connection . CreateCommand ( ) ;
sqlCommand . CommandText = @ "
INSERT INTO Parameters ( Id , Char ) SELECT name , ' LogEvent ' FROM sys . objects WHERE type = 'p'
INSERT INTO Parameters ( Id , Char ) SELECT ' Search ',' LogEvent '
";
await sqlCommand . ExecuteNonQueryAsync ( CancellationToken . None ) ;
await connection . CloseAsync ( ) ;
} ) ;
}
public async Task InitWatchdogsParameters ( string databaseName )
{
await using var conn = await _sqlConnectionBuilder . GetSqlConnectionAsync ( databaseName , cancellationToken : CancellationToken . None ) ;
2023-04-13 22:28:03 +03:00
await conn . OpenAsync ( CancellationToken . None ) ;
2022-11-08 20:46:39 +03:00
using var cmd = new SqlCommand (
@ "
2023-04-13 22:28:03 +03:00
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @IsEnabledId , 1
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @ThreadsId , 4
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @PeriodSecId , 5
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @LeasePeriodSecId , 2
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @HeartbeatPeriodSecId , 2
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @HeartbeatTimeoutSecId , 10
INSERT INTO dbo . Parameters ( Id , Number ) SELECT ' Defrag . MinFragPct ' , 0
INSERT INTO dbo . Parameters ( Id , Number ) SELECT ' Defrag . MinSizeGB ' , 0.01
2022-11-08 20:46:39 +03:00
",
conn ) ;
var defragWatchdog = new DefragWatchdog ( ) ;
cmd . Parameters . AddWithValue ( "@IsEnabledId" , defragWatchdog . IsEnabledId ) ;
cmd . Parameters . AddWithValue ( "@ThreadsId" , defragWatchdog . ThreadsId ) ;
cmd . Parameters . AddWithValue ( "@PeriodSecId" , defragWatchdog . PeriodSecId ) ;
2023-04-13 22:28:03 +03:00
cmd . Parameters . AddWithValue ( "@LeasePeriodSecId" , defragWatchdog . LeasePeriodSecId ) ;
2022-11-08 20:46:39 +03:00
cmd . Parameters . AddWithValue ( "@HeartbeatPeriodSecId" , defragWatchdog . HeartbeatPeriodSecId ) ;
cmd . Parameters . AddWithValue ( "@HeartbeatTimeoutSecId" , defragWatchdog . HeartbeatTimeoutSecId ) ;
await cmd . ExecuteNonQueryAsync ( CancellationToken . None ) ;
2023-04-13 22:28:03 +03:00
using var cmd2 = new SqlCommand (
@ "
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @PeriodSecId , 5
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @LeasePeriodSecId , 2
INSERT INTO dbo . Parameters ( Id , Number ) SELECT ' CleanupEventLog . DeleteBatchSize ' , 1000
INSERT INTO dbo . Parameters ( Id , Number ) SELECT ' CleanupEventLog . AllowedRows ' , 1000
INSERT INTO dbo . Parameters ( Id , Number ) SELECT ' CleanupEventLog . RetentionPeriodDay ' , 1.0 / 24 / 3600
INSERT INTO dbo . Parameters ( Id , Number ) SELECT ' CleanupEventLog . IsEnabled ' , 1
",
conn ) ;
var cleanupWatchdog = new CleanupEventLogWatchdog ( ) ;
cmd2 . Parameters . AddWithValue ( "@PeriodSecId" , cleanupWatchdog . PeriodSecId ) ;
cmd2 . Parameters . AddWithValue ( "@LeasePeriodSecId" , cleanupWatchdog . LeasePeriodSecId ) ;
await cmd2 . ExecuteNonQueryAsync ( CancellationToken . None ) ;
2023-07-28 02:17:33 +03:00
using var cmd3 = new SqlCommand (
@ "
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @PeriodSecId , 2
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @LeasePeriodSecId , 5
",
conn ) ;
var transactionWatchdog = new TransactionWatchdog ( ) ;
cmd3 . Parameters . AddWithValue ( "@PeriodSecId" , transactionWatchdog . PeriodSecId ) ;
cmd3 . Parameters . AddWithValue ( "@LeasePeriodSecId" , transactionWatchdog . LeasePeriodSecId ) ;
await cmd3 . ExecuteNonQueryAsync ( CancellationToken . None ) ;
using var cmd4 = new SqlCommand (
@ "
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @PeriodSecId , 5
INSERT INTO dbo . Parameters ( Id , Number ) SELECT @LeasePeriodSecId , 10
",
conn ) ;
var invisibleHistoryCleanupWatchdog = new InvisibleHistoryCleanupWatchdog ( ) ;
cmd4 . Parameters . AddWithValue ( "@PeriodSecId" , invisibleHistoryCleanupWatchdog . PeriodSecId ) ;
cmd4 . Parameters . AddWithValue ( "@LeasePeriodSecId" , invisibleHistoryCleanupWatchdog . LeasePeriodSecId ) ;
await cmd4 . ExecuteNonQueryAsync ( CancellationToken . None ) ;
2023-04-13 22:28:03 +03:00
2022-11-08 20:46:39 +03:00
await conn . CloseAsync ( ) ;
}
2022-05-21 01:59:11 +03:00
public async Task ExecuteSqlCmd ( string sql )
{
2023-10-09 18:46:57 +03:00
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( cancellationToken : CancellationToken . None ) ;
2022-06-18 00:11:39 +03:00
using SqlCommand command = new SqlCommand ( sql , connection ) ;
await connection . OpenAsync ( CancellationToken . None ) ;
2022-05-21 01:59:11 +03:00
await command . ExecuteNonQueryAsync ( CancellationToken . None ) ;
2022-06-18 00:11:39 +03:00
await connection . CloseAsync ( ) ;
2022-05-21 01:59:11 +03:00
}
2020-02-10 20:36:48 +03:00
public async Task DeleteDatabase ( string databaseName , CancellationToken cancellationToken = default )
{
2024-05-08 00:54:57 +03:00
try
{
await DbSetupSemaphore . WaitAsync ( cancellationToken ) ;
try
{
SqlConnection . ClearAllPools ( ) ;
2022-11-03 19:19:13 +03:00
2024-05-08 00:54:57 +03:00
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( _masterDatabaseName , null , cancellationToken ) ;
await connection . OpenAsync ( cancellationToken ) ;
await using SqlCommand command = connection . CreateCommand ( ) ;
2024-06-17 18:53:50 +03:00
command . CommandTimeout = 15 ;
2024-05-08 00:54:57 +03:00
command . CommandText = $"DROP DATABASE IF EXISTS {databaseName}" ;
await command . ExecuteNonQueryAsync ( cancellationToken ) ;
await connection . CloseAsync ( ) ;
}
finally
{
DbSetupSemaphore . Release ( ) ;
}
}
catch ( Exception ex )
2021-11-30 21:59:04 +03:00
{
2024-09-27 21:25:16 +03:00
Trace . TraceError ( $"Failed to delete database: {ex.Message}. Stack Trace: {ex.StackTrace}. Inner Exception: {ex.InnerException?.Message}" ) ;
2024-05-08 00:54:57 +03:00
}
2020-02-10 20:36:48 +03:00
}
2022-10-31 21:17:02 +03:00
public Task DeleteAllExportJobRecordsAsync ( CancellationToken cancellationToken = default )
2019-05-11 02:18:58 +03:00
{
2022-10-31 21:17:02 +03:00
_queueClient . JobInfos . Clear ( ) ;
return Task . CompletedTask ;
2020-02-10 20:36:48 +03:00
}
2022-10-31 21:17:02 +03:00
public Task DeleteExportJobRecordAsync ( string id , CancellationToken cancellationToken = default )
2020-02-10 20:36:48 +03:00
{
2022-10-31 21:17:02 +03:00
_queueClient . JobInfos . RemoveAll ( ( info ) = > info . Id = = long . Parse ( id ) ) ;
return Task . CompletedTask ;
2019-05-11 02:18:58 +03:00
}
2020-11-12 02:01:26 +03:00
public async Task DeleteSearchParameterStatusAsync ( string uri , CancellationToken cancellationToken = default )
{
2023-10-09 18:46:57 +03:00
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( cancellationToken : cancellationToken ) ;
2021-11-30 21:59:04 +03:00
var command = new SqlCommand ( "DELETE FROM dbo.SearchParam WHERE Uri = @uri" , connection ) ;
command . Parameters . AddWithValue ( "@uri" , uri ) ;
2020-11-12 02:01:26 +03:00
2021-11-30 21:59:04 +03:00
await command . Connection . OpenAsync ( cancellationToken ) ;
await command . ExecuteNonQueryAsync ( cancellationToken ) ;
2022-06-18 00:11:39 +03:00
await connection . CloseAsync ( ) ;
2021-04-02 08:01:44 +03:00
_sqlServerFhirModel . RemoveSearchParamIdToUriMapping ( uri ) ;
2020-11-12 02:01:26 +03:00
}
2021-02-18 04:50:52 +03:00
public async Task DeleteAllReindexJobRecordsAsync ( CancellationToken cancellationToken = default )
2020-07-31 20:34:30 +03:00
{
2023-10-09 18:46:57 +03:00
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( cancellationToken : cancellationToken ) ;
2021-11-30 21:59:04 +03:00
var command = new SqlCommand ( "DELETE FROM dbo.ReindexJob" , connection ) ;
2021-02-18 04:50:52 +03:00
2021-11-30 21:59:04 +03:00
await command . Connection . OpenAsync ( cancellationToken ) ;
await command . ExecuteNonQueryAsync ( cancellationToken ) ;
2022-06-18 00:11:39 +03:00
await connection . CloseAsync ( ) ;
2021-02-18 04:50:52 +03:00
}
public async Task DeleteReindexJobRecordAsync ( string id , CancellationToken cancellationToken = default )
{
2023-10-09 18:46:57 +03:00
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( cancellationToken : cancellationToken ) ;
2021-11-30 21:59:04 +03:00
var command = new SqlCommand ( "DELETE FROM dbo.ReindexJob WHERE Id = @id" , connection ) ;
2021-02-18 04:50:52 +03:00
2021-11-30 21:59:04 +03:00
var parameter = new SqlParameter { ParameterName = "@id" , Value = id } ;
command . Parameters . Add ( parameter ) ;
2021-02-18 04:50:52 +03:00
2021-11-30 21:59:04 +03:00
await command . Connection . OpenAsync ( cancellationToken ) ;
await command . ExecuteNonQueryAsync ( cancellationToken ) ;
2022-06-18 00:11:39 +03:00
await connection . CloseAsync ( ) ;
2020-07-31 20:34:30 +03:00
}
2019-05-11 02:18:58 +03:00
async Task < object > IFhirStorageTestHelper . GetSnapshotToken ( )
{
2023-10-09 18:46:57 +03:00
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( ) ;
2021-11-30 21:59:04 +03:00
await connection . OpenAsync ( ) ;
2019-05-11 02:18:58 +03:00
2021-11-30 21:59:04 +03:00
SqlCommand command = connection . CreateCommand ( ) ;
command . CommandText = "SELECT MAX(ResourceSurrogateId) FROM dbo.Resource" ;
return await command . ExecuteScalarAsync ( ) ;
2019-05-11 02:18:58 +03:00
}
async Task IFhirStorageTestHelper . ValidateSnapshotTokenIsCurrent ( object snapshotToken )
{
2023-10-09 18:46:57 +03:00
await using SqlConnection connection = await _sqlConnectionBuilder . GetSqlConnectionAsync ( ) ;
2021-11-30 21:59:04 +03:00
await connection . OpenAsync ( ) ;
2019-05-11 02:18:58 +03:00
2021-11-30 21:59:04 +03:00
var sb = new StringBuilder ( ) ;
await using ( SqlCommand outerCommand = connection . CreateCommand ( ) )
{
outerCommand . CommandText = @ "
2019-05-11 02:18:58 +03:00
SELECT t . name
FROM sys . tables t
INNER JOIN sys . columns c ON c . object_id = t . object_id
WHERE c . name = ' ResourceSurrogateId ' ";
2021-11-30 21:59:04 +03:00
await using ( SqlDataReader reader = await outerCommand . ExecuteReaderAsync ( ) )
{
while ( reader . Read ( ) )
2019-05-11 02:18:58 +03:00
{
2021-11-30 21:59:04 +03:00
if ( sb . Length > 0 )
2019-05-11 02:18:58 +03:00
{
2021-11-30 21:59:04 +03:00
sb . AppendLine ( "UNION ALL" ) ;
2019-05-11 02:18:58 +03:00
}
2021-11-30 21:59:04 +03:00
string tableName = reader . GetString ( 0 ) ;
sb . AppendLine ( $"SELECT '{tableName}' as TableName, MAX(ResourceSurrogateId) as MaxResourceSurrogateId FROM dbo.{tableName}" ) ;
2019-05-11 02:18:58 +03:00
}
}
2021-11-30 21:59:04 +03:00
}
2019-05-11 02:18:58 +03:00
2021-11-30 21:59:04 +03:00
await using ( SqlCommand command = connection . CreateCommand ( ) )
{
command . CommandText = sb . ToString ( ) ;
await using ( SqlDataReader reader = await command . ExecuteReaderAsync ( ) )
2019-05-11 02:18:58 +03:00
{
2021-11-30 21:59:04 +03:00
while ( await reader . ReadAsync ( ) )
2019-05-11 02:18:58 +03:00
{
2021-11-30 21:59:04 +03:00
Assert . True ( reader . IsDBNull ( 1 ) | | reader . GetInt64 ( 1 ) < = ( long ) snapshotToken ) ;
2019-05-11 02:18:58 +03:00
}
}
}
2022-06-18 00:11:39 +03:00
await connection . CloseAsync ( ) ;
2019-05-11 02:18:58 +03:00
}
2020-02-10 20:36:48 +03:00
2021-04-14 04:48:47 +03:00
private SchemaInitializer CreateSchemaInitializer ( string testConnectionString , int maxSupportedSchemaVersion )
2020-02-10 20:36:48 +03:00
{
2020-05-21 20:02:52 +03:00
var schemaOptions = new SqlServerSchemaOptions { AutomaticUpdatesEnabled = true } ;
2021-11-17 21:00:51 +03:00
var config = Options . Create ( new SqlServerDataStoreConfiguration { ConnectionString = testConnectionString , Initialize = true , SchemaOptions = schemaOptions , StatementTimeout = TimeSpan . FromMinutes ( 10 ) } ) ;
2021-04-14 04:48:47 +03:00
var schemaInformation = new SchemaInformation ( SchemaVersionConstants . Min , maxSupportedSchemaVersion ) ;
2020-02-10 20:36:48 +03:00
2022-05-10 01:20:09 +03:00
var sqlConnection = Substitute . For < ISqlConnectionBuilder > ( ) ;
2023-08-17 20:12:25 +03:00
sqlConnection . GetSqlConnectionAsync ( Arg . Any < string > ( ) , Arg . Any < int? > ( ) , Arg . Any < CancellationToken > ( ) ) . ReturnsForAnyArgs ( ( x ) = > Task . FromResult ( GetSqlConnection ( testConnectionString ) ) ) ;
2022-05-10 01:20:09 +03:00
SqlRetryLogicBaseProvider sqlRetryLogicBaseProvider = SqlConfigurableRetryFactory . CreateFixedRetryProvider ( new SqlClientRetryOptions ( ) . Settings ) ;
2022-05-12 21:39:30 +03:00
var sqlServerDataStoreConfiguration = new SqlServerDataStoreConfiguration ( ) { ConnectionString = testConnectionString } ;
2022-05-10 01:20:09 +03:00
var sqlConnectionWrapperFactory = new SqlConnectionWrapperFactory ( new SqlTransactionHandler ( ) , sqlConnection , sqlRetryLogicBaseProvider , config ) ;
var schemaManagerDataStore = new SchemaManagerDataStore ( sqlConnectionWrapperFactory , config , NullLogger < SchemaManagerDataStore > . Instance ) ;
var schemaUpgradeRunner = new SchemaUpgradeRunner ( new ScriptProvider < SchemaVersion > ( ) , new BaseScriptProvider ( ) , NullLogger < SchemaUpgradeRunner > . Instance , sqlConnectionWrapperFactory , schemaManagerDataStore ) ;
2023-09-21 19:20:45 +03:00
////Func<IServiceProvider, ISqlConnectionStringProvider> sqlConnectionStringProvider = p => sqlConnectionString;
2022-05-12 21:39:30 +03:00
Func < IServiceProvider , SqlConnectionWrapperFactory > sqlConnectionWrapperFactoryFunc = p = > sqlConnectionWrapperFactory ;
2022-05-10 01:20:09 +03:00
Func < IServiceProvider , SchemaUpgradeRunner > schemaUpgradeRunnerFactory = p = > schemaUpgradeRunner ;
Func < IServiceProvider , IReadOnlySchemaManagerDataStore > schemaManagerDataStoreFactory = p = > schemaManagerDataStore ;
var collection = new ServiceCollection ( ) ;
2023-09-21 19:20:45 +03:00
////collection.AddScoped(sqlConnectionStringProvider);
2022-05-12 21:39:30 +03:00
collection . AddScoped ( sqlConnectionWrapperFactoryFunc ) ;
2022-05-10 01:20:09 +03:00
collection . AddScoped ( schemaManagerDataStoreFactory ) ;
2022-05-12 21:39:30 +03:00
collection . AddScoped ( schemaUpgradeRunnerFactory ) ;
2022-05-10 01:20:09 +03:00
var serviceProvider = collection . BuildServiceProvider ( ) ;
2022-05-12 21:39:30 +03:00
return new SchemaInitializer ( serviceProvider , config , schemaInformation , Substitute . For < IMediator > ( ) , NullLogger < SchemaInitializer > . Instance ) ;
2022-05-10 01:20:09 +03:00
}
2023-04-12 19:16:30 +03:00
public async Task < SqlConnection > GetSqlConnectionAsync ( )
{
return await _sqlConnectionBuilder . GetSqlConnectionAsync ( cancellationToken : CancellationToken . None ) ;
}
2022-06-18 00:11:39 +03:00
protected SqlConnection GetSqlConnection ( string connectionString )
2022-05-10 01:20:09 +03:00
{
var connectionBuilder = new SqlConnectionStringBuilder ( connectionString ) ;
var result = new SqlConnection ( connectionBuilder . ToString ( ) ) ;
return result ;
2020-02-10 20:36:48 +03:00
}
2019-05-11 02:18:58 +03:00
}
}