1- using System ;
2- using System . Collections . Generic ;
3- using System . Linq ;
4- using System . Threading ;
5- using System . Threading . Tasks ;
6- using LinqToDB ;
7- using LinqToDB . Async ;
8- using LinqToDB . Data ;
9- using Mapster ;
10- using Migrator . Tests . Database . DatabaseName . Interfaces ;
11- using Migrator . Tests . Database . Interfaces ;
12- using Migrator . Tests . Database . Models ;
13- using Migrator . Tests . Settings . Models ;
14- using Npgsql ;
15-
16- namespace Migrator . Tests . Database . DerivedDatabaseIntegrationTestServices ;
17-
18- public class PostgreSqlDatabaseIntegrationTestService ( TimeProvider timeProvider , IDatabaseNameService databaseNameService )
19- : DatabaseIntegrationTestServiceBase ( databaseNameService ) , IDatabaseIntegrationTestService
20- {
21- public override async Task < DatabaseInfo > CreateTestDatabaseAsync ( DatabaseConnectionConfig databaseConnectionConfig , CancellationToken cancellationToken )
22- {
23- var clonedDatabaseConnectionConfig = databaseConnectionConfig . Adapt < DatabaseConnectionConfig > ( ) ;
24-
25- var builder = new NpgsqlConnectionStringBuilder
26- {
27- ConnectionString = clonedDatabaseConnectionConfig . ConnectionString ,
28- Database = "postgres"
29- } ;
30-
31- List < string > databaseNames ;
32-
33- using ( var context = new DataConnection ( new DataOptions ( ) . UsePostgreSQL ( builder . ConnectionString ) ) )
34- {
35- databaseNames = await context . FromSql < string > ( "SELECT datname from pg_database WHERE datistemplate = false" ) . ToListAsync ( cancellationToken ) ;
36- }
37-
38- var toBeDeletedDatabaseNames = databaseNames . Where ( x =>
39- {
40- var creationDate = DatabaseNameService . ReadTimeStampFromString ( x ) ;
41-
42- return creationDate . HasValue && creationDate . Value < timeProvider . GetUtcNow ( ) . Subtract ( MinTimeSpanBeforeDatabaseDeletion ) ;
43- } ) . ToList ( ) ;
44-
45- foreach ( var databaseName in toBeDeletedDatabaseNames )
46- {
47- var databaseInfoToBeDeleted = new DatabaseInfo { DatabaseConnectionConfig = databaseConnectionConfig , DatabaseName = databaseName } ;
48- await DropDatabaseAsync ( databaseInfoToBeDeleted , cancellationToken ) ;
49- }
50-
51- var newDatabaseName = DatabaseNameService . CreateDatabaseName ( ) ;
52- using ( var context = new DataConnection ( new DataOptions ( ) . UsePostgreSQL ( builder . ConnectionString ) ) )
53- {
54- await context . ExecuteAsync ( $ "CREATE DATABASE \" { newDatabaseName } \" ", cancellationToken ) ;
55- }
56-
57- var connectionStringBuilder2 = new NpgsqlConnectionStringBuilder ( clonedDatabaseConnectionConfig . ConnectionString )
58- {
59- Database = newDatabaseName
60- } ;
61-
62- clonedDatabaseConnectionConfig . ConnectionString = connectionStringBuilder2 . ConnectionString ;
63-
64- var databaseInfo = new DatabaseInfo
65- {
66- DatabaseConnectionConfig = clonedDatabaseConnectionConfig ,
67- DatabaseName = newDatabaseName
68- } ;
69-
70- return databaseInfo ;
71- }
72-
73- public override async Task DropDatabaseAsync ( DatabaseInfo databaseInfo , CancellationToken cancellationToken )
74- {
75- var creationDate = DatabaseNameService . ReadTimeStampFromString ( databaseInfo . DatabaseName ) ;
76-
77- if ( ! creationDate . HasValue )
78- {
79- throw new Exception ( "You tried to drop a database that was not created by this service. For safety reasons we deny your request." ) ;
80- }
81-
82- var builder = new NpgsqlConnectionStringBuilder ( databaseInfo . DatabaseConnectionConfig . ConnectionString )
83- {
84- Database = "postgres"
85- } ;
86-
87- var dataOptions = new DataOptions ( ) . UsePostgreSQL ( builder . ConnectionString ) ;
88-
89- using var context = new DataConnection ( dataOptions ) ;
90-
91- try
92- {
93- await context . ExecuteAsync ( $ "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{ databaseInfo . DatabaseName } '", cancellationToken ) ;
94- await context . ExecuteAsync ( $ "DROP DATABASE \" { databaseInfo . DatabaseName } \" ", cancellationToken ) ;
95- }
96- catch
97- {
98- await Task . Delay ( 2000 , cancellationToken ) ;
99-
100- var count = await context . ExecuteAsync < int > ( $ "SELECT COUNT(*) from pg_database WHERE datistemplate = false AND datname = '{ databaseInfo . DatabaseName } '", cancellationToken ) ;
101-
102- if ( count == 1 )
103- {
104- throw ;
105- }
106- else
107- {
108- // The database was removed by another asynchronously running test that kicked in earlier.
109- // That's ok for us as we have achieved our objective.
110- }
111- }
112- }
1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Linq ;
4+ using System . Threading ;
5+ using System . Threading . Tasks ;
6+ using LinqToDB ;
7+ using LinqToDB . Async ;
8+ using LinqToDB . Data ;
9+ using Mapster ;
10+ using Migrator . Tests . Database . DatabaseName . Interfaces ;
11+ using Migrator . Tests . Database . Interfaces ;
12+ using Migrator . Tests . Database . Models ;
13+ using Migrator . Tests . Settings . Models ;
14+ using Npgsql ;
15+
16+ namespace Migrator . Tests . Database . DerivedDatabaseIntegrationTestServices ;
17+
18+ public class PostgreSqlDatabaseIntegrationTestService ( TimeProvider timeProvider , IDatabaseNameService databaseNameService )
19+ : DatabaseIntegrationTestServiceBase ( databaseNameService ) , IDatabaseIntegrationTestService
20+ {
21+ public override async Task < DatabaseInfo > CreateTestDatabaseAsync ( DatabaseConnectionConfig databaseConnectionConfig , CancellationToken cancellationToken )
22+ {
23+ var clonedDatabaseConnectionConfig = databaseConnectionConfig . Adapt < DatabaseConnectionConfig > ( ) ;
24+
25+ var builder = new NpgsqlConnectionStringBuilder
26+ {
27+ ConnectionString = clonedDatabaseConnectionConfig . ConnectionString ,
28+ Database = "postgres"
29+ } ;
30+
31+ List < string > databaseNames ;
32+
33+ using ( var context = new DataConnection ( new DataOptions ( ) . UsePostgreSQL ( builder . ConnectionString ) ) )
34+ {
35+ databaseNames = await context . QueryToListAsync < string > ( "SELECT datname from pg_database WHERE datistemplate = false" , cancellationToken ) ;
36+ }
37+
38+ var toBeDeletedDatabaseNames = databaseNames . Where ( x =>
39+ {
40+ var creationDate = DatabaseNameService . ReadTimeStampFromString ( x ) ;
41+
42+ return creationDate . HasValue && creationDate . Value < timeProvider . GetUtcNow ( ) . Subtract ( MinTimeSpanBeforeDatabaseDeletion ) ;
43+ } ) . ToList ( ) ;
44+
45+ foreach ( var databaseName in toBeDeletedDatabaseNames )
46+ {
47+ var databaseInfoToBeDeleted = new DatabaseInfo { DatabaseConnectionConfig = databaseConnectionConfig , DatabaseName = databaseName } ;
48+ await DropDatabaseAsync ( databaseInfoToBeDeleted , cancellationToken ) ;
49+ }
50+
51+ var newDatabaseName = DatabaseNameService . CreateDatabaseName ( ) ;
52+ using ( var context = new DataConnection ( new DataOptions ( ) . UsePostgreSQL ( builder . ConnectionString ) ) )
53+ {
54+ await context . ExecuteAsync ( $ "CREATE DATABASE \" { newDatabaseName } \" ", cancellationToken ) ;
55+ }
56+
57+ var connectionStringBuilder2 = new NpgsqlConnectionStringBuilder ( clonedDatabaseConnectionConfig . ConnectionString )
58+ {
59+ Database = newDatabaseName
60+ } ;
61+
62+ clonedDatabaseConnectionConfig . ConnectionString = connectionStringBuilder2 . ConnectionString ;
63+
64+ var databaseInfo = new DatabaseInfo
65+ {
66+ DatabaseConnectionConfig = clonedDatabaseConnectionConfig ,
67+ DatabaseName = newDatabaseName
68+ } ;
69+
70+ return databaseInfo ;
71+ }
72+
73+ public override async Task DropDatabaseAsync ( DatabaseInfo databaseInfo , CancellationToken cancellationToken )
74+ {
75+ var creationDate = DatabaseNameService . ReadTimeStampFromString ( databaseInfo . DatabaseName ) ;
76+
77+ if ( ! creationDate . HasValue )
78+ {
79+ throw new Exception ( "You tried to drop a database that was not created by this service. For safety reasons we deny your request." ) ;
80+ }
81+
82+ var builder = new NpgsqlConnectionStringBuilder ( databaseInfo . DatabaseConnectionConfig . ConnectionString )
83+ {
84+ Database = "postgres"
85+ } ;
86+
87+ var dataOptions = new DataOptions ( ) . UsePostgreSQL ( builder . ConnectionString ) ;
88+
89+ using ( var context = new DataConnection ( dataOptions ) )
90+ {
91+
92+ try
93+ {
94+ await context . ExecuteAsync ( $ "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{ databaseInfo . DatabaseName } '", cancellationToken ) ;
95+ await context . ExecuteAsync ( $ "DROP DATABASE \" { databaseInfo . DatabaseName } \" ", cancellationToken ) ;
96+ }
97+ catch
98+ {
99+ await Task . Delay ( 2000 , cancellationToken ) ;
100+
101+ var count = await context . ExecuteAsync < int > ( $ "SELECT COUNT(*) from pg_database WHERE datistemplate = false AND datname = '{ databaseInfo . DatabaseName } '", cancellationToken ) ;
102+
103+ if ( count == 1 )
104+ {
105+ throw ;
106+ }
107+ else
108+ {
109+ // The database was removed by another asynchronously running test that kicked in earlier.
110+ // That's ok for us as we have achieved our objective.
111+ }
112+ }
113+ }
114+ }
113115}
0 commit comments