protected void UseTestDatabase(IServiceProvider serviceProvider)
        {
            IRuntimeState state = serviceProvider.GetRequiredService <IRuntimeState>();
            TestUmbracoDatabaseFactoryProvider testDatabaseFactoryProvider = serviceProvider.GetRequiredService <TestUmbracoDatabaseFactoryProvider>();
            IUmbracoDatabaseFactory            databaseFactory             = serviceProvider.GetRequiredService <IUmbracoDatabaseFactory>();
            ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();

            // This will create a db, install the schema and ensure the app is configured to run
            SetupTestDatabase(testDatabaseFactoryProvider, databaseFactory, loggerFactory, state, TestHelper.WorkingDirectory);
        }
 /// <summary>
 /// Creates a TestDatabase instance
 /// </summary>
 /// <remarks>
 /// SQL Server setup requires configured master connection string &amp; privileges to create database.
 /// </remarks>
 /// <example>
 /// <code>
 /// # SQL Server Environment variable setup
 /// $ export Tests__Database__DatabaseType="SqlServer"
 /// $ export Tests__Database__SQLServerMasterConnectionString="Server=localhost,1433; User Id=sa; Password=MySuperSecretPassword123!;"
 /// </code>
 /// </example>
 /// <example>
 /// <code>
 /// # Docker cheat sheet
 /// $ docker run -e 'ACCEPT_EULA=Y' -e "SA_PASSWORD=MySuperSecretPassword123!" -e 'MSSQL_PID=Developer' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest-ubuntu
 /// </code>
 /// </example>
 public static ITestDatabase Create(TestDatabaseSettings settings, TestUmbracoDatabaseFactoryProvider dbFactory, ILoggerFactory loggerFactory) =>
     settings.DatabaseType switch
     {
        /// <summary>
        /// Creates a LocalDb instance to use for the test
        /// </summary>
        private void SetupTestDatabase(
            TestUmbracoDatabaseFactoryProvider testUmbracoDatabaseFactoryProvider,
            IUmbracoDatabaseFactory databaseFactory,
            ILoggerFactory loggerFactory,
            IRuntimeState runtimeState,
            string workingDirectory)
        {
            if (TestOptions.Database == UmbracoTestOptions.Database.None)
            {
                return;
            }

            // need to manually register this factory
            DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance);

            string dbFilePath = Path.Combine(workingDirectory, "LocalDb");

            ITestDatabase db = GetOrCreateDatabase(dbFilePath, loggerFactory, testUmbracoDatabaseFactoryProvider);

            switch (TestOptions.Database)
            {
            case UmbracoTestOptions.Database.NewSchemaPerTest:

                // New DB + Schema
                TestDbMeta newSchemaDbMeta = db.AttachSchema();

                // Add teardown callback
                OnTestTearDown(() => db.Detach(newSchemaDbMeta));

                ConfigureTestDatabaseFactory(newSchemaDbMeta, databaseFactory, runtimeState);

                Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level);

                break;

            case UmbracoTestOptions.Database.NewEmptyPerTest:
                TestDbMeta newEmptyDbMeta = db.AttachEmpty();

                // Add teardown callback
                OnTestTearDown(() => db.Detach(newEmptyDbMeta));

                ConfigureTestDatabaseFactory(newEmptyDbMeta, databaseFactory, runtimeState);

                Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);

                break;

            case UmbracoTestOptions.Database.NewSchemaPerFixture:
                // Only attach schema once per fixture
                // Doing it more than once will block the process since the old db hasn't been detached
                // and it would be the same as NewSchemaPerTest even if it didn't block
                if (_firstTestInFixture)
                {
                    // New DB + Schema
                    TestDbMeta newSchemaFixtureDbMeta = db.AttachSchema();
                    s_fixtureDbMeta = newSchemaFixtureDbMeta;

                    // Add teardown callback
                    OnFixtureTearDown(() => db.Detach(newSchemaFixtureDbMeta));
                }

                ConfigureTestDatabaseFactory(s_fixtureDbMeta, databaseFactory, runtimeState);

                break;

            case UmbracoTestOptions.Database.NewEmptyPerFixture:
                // Only attach schema once per fixture
                // Doing it more than once will block the process since the old db hasn't been detached
                // and it would be the same as NewSchemaPerTest even if it didn't block
                if (_firstTestInFixture)
                {
                    // New DB + Schema
                    TestDbMeta newEmptyFixtureDbMeta = db.AttachEmpty();
                    s_fixtureDbMeta = newEmptyFixtureDbMeta;

                    // Add teardown callback
                    OnFixtureTearDown(() => db.Detach(newEmptyFixtureDbMeta));
                }

                ConfigureTestDatabaseFactory(s_fixtureDbMeta, databaseFactory, runtimeState);

                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(TestOptions), TestOptions, null);
            }
        }
        /// <summary>
        /// Get or create an instance of <see cref="ITestDatabase"/>
        /// </summary>
        /// <remarks>
        /// There must only be ONE instance shared between all tests in a session
        /// </remarks>
        private static ITestDatabase GetOrCreateDatabase(string filesPath, ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory)
        {
            lock (s_dbLocker)
            {
                if (s_dbInstance != null)
                {
                    return(s_dbInstance);
                }

                // TODO: pull from IConfiguration
                var settings = new TestDatabaseSettings
                {
                    PrepareThreadCount  = 4,
                    EmptyDatabasesCount = 2,
                    SchemaDatabaseCount = 4
                };

                s_dbInstance = TestDatabaseFactory.Create(settings, filesPath, loggerFactory, dbFactory);

                return(s_dbInstance);
            }
        }
        private static ITestDatabase CreateSqlDeveloper(TestDatabaseSettings settings, ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory, string connectionString)
        {
            // NOTE: Example setup for Linux box.
            // $ export SA_PASSWORD=Foobar123!
            // $ export UmbracoIntegrationTestConnectionString="Server=localhost,1433;User Id=sa;Password=$SA_PASSWORD;"
            // $ docker run -e 'ACCEPT_EULA=Y' -e "SA_PASSWORD=$SA_PASSWORD" -e 'MSSQL_PID=Developer' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest-ubuntu
            if (string.IsNullOrEmpty(connectionString))
            {
                throw new InvalidOperationException("ENV: UmbracoIntegrationTestConnectionString is not set");
            }

            return(new SqlDeveloperTestDatabase(settings, loggerFactory, dbFactory.Create(), connectionString));
        }
        private static ITestDatabase CreateLocalDb(TestDatabaseSettings settings, string filesPath, ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory)
        {
            if (!Directory.Exists(filesPath))
            {
                Directory.CreateDirectory(filesPath);
            }

            var localDb = new LocalDb();

            if (!localDb.IsAvailable)
            {
                throw new InvalidOperationException("LocalDB is not available.");
            }

            return(new LocalDbTestDatabase(settings, loggerFactory, localDb, filesPath, dbFactory.Create()));
        }
        public static ITestDatabase Create(TestDatabaseSettings settings, string filesPath, ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory)
        {
            string connectionString = Environment.GetEnvironmentVariable("UmbracoIntegrationTestConnectionString");

            return(string.IsNullOrEmpty(connectionString)
                ? CreateLocalDb(settings, filesPath, loggerFactory, dbFactory)
                : CreateSqlDeveloper(settings, loggerFactory, dbFactory, connectionString));
        }