using System; using System.Collections.Concurrent; using System.Data.SqlClient; using System.Threading; using Microsoft.Extensions.Logging; using Umbraco.Core.Persistence; // ReSharper disable ConvertToUsingDeclaration namespace Umbraco.Tests.Integration.Testing { /// /// It's not meant to be pretty, rushed port of LocalDb.cs + LocalDbTestDatabase.cs /// public class SqlDeveloperTestDatabase : BaseTestDatabase, ITestDatabase { private readonly string _masterConnectionString; public const string DatabaseName = "UmbracoTests"; public static SqlDeveloperTestDatabase Instance { get; private set; } public SqlDeveloperTestDatabase(ILoggerFactory loggerFactory, IUmbracoDatabaseFactory databaseFactory, string masterConnectionString) { _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); _databaseFactory = databaseFactory ?? throw new ArgumentNullException(nameof(databaseFactory)); _masterConnectionString = masterConnectionString; _testDatabases = new[] { // With Schema TestDbMeta.CreateWithMasterConnectionString($"{DatabaseName}-1", false, masterConnectionString), TestDbMeta.CreateWithMasterConnectionString($"{DatabaseName}-2", false, masterConnectionString), // Empty (for migration testing etc) TestDbMeta.CreateWithMasterConnectionString($"{DatabaseName}-3", true, masterConnectionString), TestDbMeta.CreateWithMasterConnectionString($"{DatabaseName}-4", true, masterConnectionString), }; Instance = this; // For GlobalSetupTeardown.cs } protected override void Initialize() { _prepareQueue = new BlockingCollection(); _readySchemaQueue = new BlockingCollection(); _readyEmptyQueue = new BlockingCollection(); foreach (var meta in _testDatabases) { CreateDatabase(meta); _prepareQueue.Add(meta); } for (var i = 0; i < _threadCount; i++) { var thread = new Thread(PrepareDatabase); thread.Start(); } } private void CreateDatabase(TestDbMeta meta) { using (var connection = new SqlConnection(_masterConnectionString)) { connection.Open(); using (var command = connection.CreateCommand()) { SetCommand(command, $@"CREATE DATABASE {LocalDb.QuotedName(meta.Name)}"); command.ExecuteNonQuery(); } } } private void Drop(TestDbMeta meta) { using (var connection = new SqlConnection(_masterConnectionString)) { connection.Open(); using (var command = connection.CreateCommand()) { SetCommand(command, $@" ALTER DATABASE{LocalDb.QuotedName(meta.Name)} SET SINGLE_USER WITH ROLLBACK IMMEDIATE "); command.ExecuteNonQuery(); SetCommand(command, $@"DROP DATABASE {LocalDb.QuotedName(meta.Name)}"); command.ExecuteNonQuery(); } } } public void Finish() { if (_prepareQueue == null) return; _prepareQueue.CompleteAdding(); while (_prepareQueue.TryTake(out _)) { } _readyEmptyQueue.CompleteAdding(); while (_readyEmptyQueue.TryTake(out _)) { } _readySchemaQueue.CompleteAdding(); while (_readySchemaQueue.TryTake(out _)) { } foreach (var testDatabase in _testDatabases) { Drop(testDatabase); } } } }