# Conflicts: # build/templates/UmbracoPackage/.template.config/template.json # build/templates/UmbracoProject/.template.config/template.json # src/Directory.Build.props # src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs # src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs # src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs # src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs # src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs # src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs # src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs # tests/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs # tests/Umbraco.Tests.Integration/Testing/BaseTestDatabase.cs # tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Migrations/AdvancedMigrationTests.cs # tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/SchemaValidationTest.cs # tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/SqlServerTableByTableTest.cs # tests/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs
148 lines
4.6 KiB
C#
148 lines
4.6 KiB
C#
// Copyright (c) Umbraco.
|
|
// See LICENSE for more details.
|
|
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Data.Common;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using Microsoft.Extensions.Logging;
|
|
using Moq;
|
|
using Umbraco.Cms.Core;
|
|
using Umbraco.Cms.Core.Configuration;
|
|
using Umbraco.Cms.Core.Events;
|
|
using Umbraco.Cms.Infrastructure.Migrations.Install;
|
|
using Umbraco.Cms.Infrastructure.Persistence;
|
|
|
|
namespace Umbraco.Cms.Tests.Integration.Testing
|
|
{
|
|
public abstract class BaseTestDatabase
|
|
{
|
|
public static bool IsSqlite() => BaseTestDatabase.Instance is SqliteTestDatabase;
|
|
public static bool IsSqlServer() => BaseTestDatabase.Instance is SqlServerBaseTestDatabase;
|
|
|
|
protected ILoggerFactory _loggerFactory;
|
|
protected IUmbracoDatabaseFactory _databaseFactory;
|
|
protected IList<TestDbMeta> _testDatabases;
|
|
|
|
protected BlockingCollection<TestDbMeta> _prepareQueue;
|
|
protected BlockingCollection<TestDbMeta> _readySchemaQueue;
|
|
protected BlockingCollection<TestDbMeta> _readyEmptyQueue;
|
|
public static BaseTestDatabase Instance { get; private set; }
|
|
|
|
public BaseTestDatabase() => Instance = this;
|
|
|
|
protected abstract void Initialize();
|
|
|
|
public virtual TestDbMeta AttachEmpty()
|
|
{
|
|
if (_prepareQueue == null)
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
return _readyEmptyQueue.Take();
|
|
}
|
|
|
|
public virtual TestDbMeta AttachSchema()
|
|
{
|
|
if (_prepareQueue == null)
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
return _readySchemaQueue.Take();
|
|
}
|
|
|
|
public virtual void Detach(TestDbMeta meta)
|
|
{
|
|
_prepareQueue.TryAdd(meta);
|
|
}
|
|
|
|
protected virtual void PrepareDatabase() =>
|
|
Retry(10, () =>
|
|
{
|
|
while (_prepareQueue.IsCompleted == false)
|
|
{
|
|
TestDbMeta meta;
|
|
try
|
|
{
|
|
meta = _prepareQueue.Take();
|
|
}
|
|
catch (InvalidOperationException)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ResetTestDatabase(meta);
|
|
|
|
if (!meta.IsEmpty)
|
|
{
|
|
using (var conn = GetConnection(meta))
|
|
{
|
|
conn.Open();
|
|
using (var cmd = conn.CreateCommand())
|
|
{
|
|
RebuildSchema(cmd, meta);
|
|
}
|
|
}
|
|
|
|
_readySchemaQueue.TryAdd(meta);
|
|
}
|
|
else
|
|
{
|
|
_readyEmptyQueue.TryAdd(meta);
|
|
}
|
|
}
|
|
});
|
|
|
|
protected static void AddParameter(IDbCommand cmd, UmbracoDatabase.ParameterInfo parameterInfo)
|
|
{
|
|
IDbDataParameter p = cmd.CreateParameter();
|
|
p.ParameterName = parameterInfo.Name;
|
|
p.Value = parameterInfo.Value;
|
|
p.DbType = parameterInfo.DbType;
|
|
p.Size = parameterInfo.Size;
|
|
cmd.Parameters.Add(p);
|
|
}
|
|
|
|
protected abstract DbConnection GetConnection(TestDbMeta meta);
|
|
|
|
protected abstract void RebuildSchema(IDbCommand command, TestDbMeta meta);
|
|
|
|
protected abstract void ResetTestDatabase(TestDbMeta meta);
|
|
|
|
protected static void Retry(int maxIterations, Action action)
|
|
{
|
|
for (int i = 0; i < maxIterations; i++)
|
|
{
|
|
try
|
|
{
|
|
action();
|
|
return;
|
|
}
|
|
catch (DbException ex)
|
|
{
|
|
// Console.Error.WriteLine($"SqlException occured, but we try again {i+1}/{maxIterations}.\n{e}");
|
|
// This can occur when there's a transaction deadlock which means (i think) that the database is still in use and hasn't been closed properly yet
|
|
// so we need to just wait a little bit
|
|
Thread.Sleep(100 * i);
|
|
if (i == maxIterations - 1)
|
|
{
|
|
Debugger.Launch();
|
|
throw;
|
|
}
|
|
}
|
|
catch (InvalidOperationException)
|
|
{
|
|
// Ignore
|
|
}
|
|
}
|
|
}
|
|
|
|
public abstract void TearDown();
|
|
}
|
|
}
|