2020-03-30 20:55:13 +11:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using Microsoft.AspNetCore.Builder;
|
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
|
|
using NUnit.Framework;
|
2020-03-30 21:53:30 +11:00
|
|
|
|
using Umbraco.Core.Cache;
|
2020-03-30 20:55:13 +11:00
|
|
|
|
using Umbraco.Core.Composing;
|
|
|
|
|
|
using Umbraco.Core.Composing.LightInject;
|
|
|
|
|
|
using Umbraco.Core.Configuration;
|
2020-03-30 21:53:30 +11:00
|
|
|
|
using Umbraco.Core.IO;
|
2020-03-30 20:55:13 +11:00
|
|
|
|
using Umbraco.Core.Logging;
|
|
|
|
|
|
using Umbraco.Core.Persistence;
|
2020-03-30 21:53:30 +11:00
|
|
|
|
using Umbraco.Core.Persistence.Mappers;
|
2020-03-30 20:55:13 +11:00
|
|
|
|
using Umbraco.Core.Scoping;
|
2020-03-30 21:53:30 +11:00
|
|
|
|
using Umbraco.Core.Strings;
|
|
|
|
|
|
using Umbraco.Tests.Common.Builders;
|
2020-03-30 20:55:13 +11:00
|
|
|
|
using Umbraco.Tests.Integration.Extensions;
|
|
|
|
|
|
using Umbraco.Tests.Integration.Implementations;
|
2020-05-07 10:08:23 +02:00
|
|
|
|
using Umbraco.Extensions;
|
2020-06-30 20:11:39 +02:00
|
|
|
|
using Umbraco.Tests.Testing;
|
2020-06-09 07:49:26 +02:00
|
|
|
|
using Umbraco.Web;
|
2020-09-02 18:10:29 +10:00
|
|
|
|
using Umbraco.Core.Runtime;
|
|
|
|
|
|
using Umbraco.Core;
|
|
|
|
|
|
using Moq;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using Microsoft.Extensions.Configuration;
|
|
|
|
|
|
using System.Data.SqlClient;
|
|
|
|
|
|
using System.Data.Common;
|
|
|
|
|
|
using System.IO;
|
2020-08-24 12:34:37 +02:00
|
|
|
|
using Umbraco.Core.Configuration.Models;
|
|
|
|
|
|
using Microsoft.Extensions.Options;
|
2020-09-15 15:14:44 +02:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2020-10-06 18:43:07 +02:00
|
|
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
2020-09-23 15:37:19 +02:00
|
|
|
|
using Serilog;
|
|
|
|
|
|
using Umbraco.Core.Logging.Serilog;
|
2020-09-04 14:30:48 +02:00
|
|
|
|
using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings;
|
2020-09-17 10:35:11 +02:00
|
|
|
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Tests.Integration.Testing
|
|
|
|
|
|
{
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
2020-03-30 20:55:13 +11:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Abstract class for integration tests
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// This will use a Host Builder to boot and install Umbraco ready for use
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
[SingleThreaded]
|
|
|
|
|
|
[NonParallelizable]
|
|
|
|
|
|
public abstract class UmbracoIntegrationTest
|
|
|
|
|
|
{
|
2020-09-02 18:10:29 +10:00
|
|
|
|
public static LightInjectContainer CreateUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory)
|
2020-03-30 20:55:13 +11:00
|
|
|
|
{
|
|
|
|
|
|
var container = UmbracoServiceProviderFactory.CreateServiceContainer();
|
2020-05-12 17:14:39 +10:00
|
|
|
|
serviceProviderFactory = new UmbracoServiceProviderFactory(container, false);
|
2020-03-30 20:55:13 +11:00
|
|
|
|
var umbracoContainer = serviceProviderFactory.GetContainer();
|
|
|
|
|
|
return umbracoContainer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-04 00:27:43 +10:00
|
|
|
|
private List<Action> _testTeardown = null;
|
|
|
|
|
|
private List<Action> _fixtureTeardown = new List<Action>();
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
2020-09-04 00:27:43 +10:00
|
|
|
|
public void OnTestTearDown(Action tearDown)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_testTeardown == null)
|
|
|
|
|
|
_testTeardown = new List<Action>();
|
|
|
|
|
|
_testTeardown.Add(tearDown);
|
|
|
|
|
|
}
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
2020-09-04 00:27:43 +10:00
|
|
|
|
public void OnFixtureTearDown(Action tearDown) => _fixtureTeardown.Add(tearDown);
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
|
|
|
|
|
[OneTimeTearDown]
|
2020-09-04 00:27:43 +10:00
|
|
|
|
public void FixtureTearDown()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var a in _fixtureTeardown) a();
|
|
|
|
|
|
}
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
|
|
|
|
|
[TearDown]
|
2020-09-04 00:27:43 +10:00
|
|
|
|
public virtual void TearDown()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var a in _testTeardown) a();
|
|
|
|
|
|
_testTeardown = null;
|
2020-10-05 13:33:39 +02:00
|
|
|
|
FirstTestInFixture = false;
|
|
|
|
|
|
FirstTestInSession = false;
|
2020-09-04 00:27:43 +10:00
|
|
|
|
}
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
|
|
|
|
|
[SetUp]
|
2020-10-05 10:02:11 +02:00
|
|
|
|
public virtual void Setup()
|
2020-09-02 18:10:29 +10:00
|
|
|
|
{
|
|
|
|
|
|
var hostBuilder = CreateHostBuilder();
|
2020-10-05 10:02:11 +02:00
|
|
|
|
var host = hostBuilder.StartAsync().GetAwaiter().GetResult();
|
2020-09-17 10:35:11 +02:00
|
|
|
|
Services = host.Services;
|
2020-09-02 18:10:29 +10:00
|
|
|
|
var app = new ApplicationBuilder(host.Services);
|
|
|
|
|
|
Configure(app);
|
2020-09-11 21:13:18 +02:00
|
|
|
|
|
|
|
|
|
|
OnFixtureTearDown(() => host.Dispose());
|
2020-09-02 18:10:29 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region Generic Host Builder and Runtime
|
|
|
|
|
|
|
2020-10-06 18:43:07 +02:00
|
|
|
|
private ILoggerFactory CreateLoggerFactory()
|
|
|
|
|
|
{
|
|
|
|
|
|
ILoggerFactory factory;
|
|
|
|
|
|
var testOptions = TestOptionAttributeBase.GetTestOptions<UmbracoTestAttribute>();
|
|
|
|
|
|
switch (testOptions.Logger)
|
|
|
|
|
|
{
|
|
|
|
|
|
case UmbracoTestOptions.Logger.Mock:
|
|
|
|
|
|
factory = NullLoggerFactory.Instance;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case UmbracoTestOptions.Logger.Serilog:
|
|
|
|
|
|
factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddSerilog(); });
|
|
|
|
|
|
break;
|
|
|
|
|
|
case UmbracoTestOptions.Logger.Console:
|
|
|
|
|
|
factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); });
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw new NotSupportedException($"Logger option {testOptions.Logger} is not supported.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return factory;
|
|
|
|
|
|
}
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Create the Generic Host and execute startup ConfigureServices/Configure calls
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual IHostBuilder CreateHostBuilder()
|
|
|
|
|
|
{
|
|
|
|
|
|
UmbracoContainer = CreateUmbracoContainer(out var serviceProviderFactory);
|
|
|
|
|
|
_serviceProviderFactory = serviceProviderFactory;
|
2020-10-06 20:04:13 +02:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
var hostBuilder = Host.CreateDefaultBuilder()
|
|
|
|
|
|
// IMPORTANT: We Cannot use UseStartup, there's all sorts of threads about this with testing. Although this can work
|
|
|
|
|
|
// if you want to setup your tests this way, it is a bit annoying to do that as the WebApplicationFactory will
|
|
|
|
|
|
// create separate Host instances. So instead of UseStartup, we just call ConfigureServices/Configure ourselves,
|
|
|
|
|
|
// and in the case of the UmbracoTestServerTestBase it will use the ConfigureWebHost to Configure the IApplicationBuilder directly.
|
|
|
|
|
|
//.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(GetType()); })
|
|
|
|
|
|
.UseUmbraco(_serviceProviderFactory)
|
|
|
|
|
|
.ConfigureAppConfiguration((context, configBuilder) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
context.HostingEnvironment = TestHelper.GetWebHostEnvironment();
|
|
|
|
|
|
Configuration = context.Configuration;
|
|
|
|
|
|
configBuilder.AddInMemoryCollection(InMemoryConfiguration);
|
|
|
|
|
|
})
|
|
|
|
|
|
.ConfigureServices((hostContext, services) =>
|
|
|
|
|
|
{
|
2020-10-06 18:43:07 +02:00
|
|
|
|
services.AddTransient(_ => CreateLoggerFactory());
|
2020-09-02 18:10:29 +10:00
|
|
|
|
ConfigureServices(services);
|
|
|
|
|
|
});
|
|
|
|
|
|
return hostBuilder;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Creates a <see cref="CoreRuntime"/> instance for testing and registers an event handler for database install
|
|
|
|
|
|
/// </summary>
|
2020-09-04 14:30:48 +02:00
|
|
|
|
/// <param name="connectionStrings"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <param name="umbracoVersion"></param>
|
|
|
|
|
|
/// <param name="ioHelper"></param>
|
|
|
|
|
|
/// <param name="logger"></param>
|
2020-09-15 15:14:44 +02:00
|
|
|
|
/// <param name="loggerFactory"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <param name="profiler"></param>
|
|
|
|
|
|
/// <param name="hostingEnvironment"></param>
|
|
|
|
|
|
/// <param name="backOfficeInfo"></param>
|
|
|
|
|
|
/// <param name="typeFinder"></param>
|
2020-09-04 00:27:43 +10:00
|
|
|
|
/// <param name="appCaches"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <param name="dbProviderFactoryCreator"></param>
|
2020-09-04 14:30:48 +02:00
|
|
|
|
/// <param name="globalSettings"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <returns></returns>
|
2020-09-04 14:30:48 +02:00
|
|
|
|
public CoreRuntime CreateTestRuntime(
|
|
|
|
|
|
GlobalSettings globalSettings,
|
|
|
|
|
|
ConnectionStrings connectionStrings,
|
|
|
|
|
|
IUmbracoVersion umbracoVersion, IIOHelper ioHelper,
|
2020-10-06 21:23:15 +02:00
|
|
|
|
ILoggerFactory loggerFactory, IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo,
|
2020-09-04 00:27:43 +10:00
|
|
|
|
ITypeFinder typeFinder, AppCaches appCaches, IDbProviderFactoryCreator dbProviderFactoryCreator)
|
2020-09-02 18:10:29 +10:00
|
|
|
|
{
|
2020-09-08 13:03:43 +02:00
|
|
|
|
var runtime = CreateTestRuntime(
|
2020-09-04 14:30:48 +02:00
|
|
|
|
globalSettings,
|
|
|
|
|
|
connectionStrings,
|
2020-09-02 18:10:29 +10:00
|
|
|
|
umbracoVersion,
|
|
|
|
|
|
ioHelper,
|
2020-09-15 15:14:44 +02:00
|
|
|
|
loggerFactory,
|
2020-09-02 18:10:29 +10:00
|
|
|
|
profiler,
|
|
|
|
|
|
hostingEnvironment,
|
2020-09-17 10:35:11 +02:00
|
|
|
|
backOfficeInfo,
|
2020-09-02 18:10:29 +10:00
|
|
|
|
typeFinder,
|
2020-09-04 00:27:43 +10:00
|
|
|
|
appCaches,
|
2020-09-02 18:10:29 +10:00
|
|
|
|
dbProviderFactoryCreator,
|
|
|
|
|
|
TestHelper.MainDom, // SimpleMainDom
|
|
|
|
|
|
UseTestLocalDb // DB Installation event handler
|
2020-09-04 00:27:43 +10:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
return runtime;
|
2020-09-02 18:10:29 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Creates a <see cref="CoreRuntime"/> instance for testing and registers an event handler for database install
|
|
|
|
|
|
/// </summary>
|
2020-09-04 14:30:48 +02:00
|
|
|
|
/// <param name="connectionStrings"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <param name="umbracoVersion"></param>
|
|
|
|
|
|
/// <param name="ioHelper"></param>
|
|
|
|
|
|
/// <param name="logger"></param>
|
2020-09-15 15:14:44 +02:00
|
|
|
|
/// <param name="loggerFactory"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <param name="profiler"></param>
|
|
|
|
|
|
/// <param name="hostingEnvironment"></param>
|
|
|
|
|
|
/// <param name="backOfficeInfo"></param>
|
|
|
|
|
|
/// <param name="typeFinder"></param>
|
2020-09-15 15:14:44 +02:00
|
|
|
|
/// <param name="appCaches"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <param name="dbProviderFactoryCreator"></param>
|
|
|
|
|
|
/// <param name="mainDom"></param>
|
|
|
|
|
|
/// <param name="eventHandler">The event handler used for DB installation</param>
|
2020-09-04 14:30:48 +02:00
|
|
|
|
/// <param name="globalSettings"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <returns></returns>
|
2020-09-04 14:30:48 +02:00
|
|
|
|
public static CoreRuntime CreateTestRuntime(
|
|
|
|
|
|
GlobalSettings globalSettings,
|
|
|
|
|
|
ConnectionStrings connectionStrings,
|
|
|
|
|
|
IUmbracoVersion umbracoVersion, IIOHelper ioHelper,
|
2020-10-06 21:23:15 +02:00
|
|
|
|
ILoggerFactory loggerFactory, IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo,
|
2020-09-04 00:27:43 +10:00
|
|
|
|
ITypeFinder typeFinder, AppCaches appCaches, IDbProviderFactoryCreator dbProviderFactoryCreator,
|
2020-09-02 18:10:29 +10:00
|
|
|
|
IMainDom mainDom, Action<CoreRuntime, RuntimeEssentialsEventArgs> eventHandler)
|
|
|
|
|
|
{
|
|
|
|
|
|
var runtime = new CoreRuntime(
|
2020-09-04 14:30:48 +02:00
|
|
|
|
globalSettings,
|
|
|
|
|
|
connectionStrings,
|
2020-09-02 18:10:29 +10:00
|
|
|
|
umbracoVersion,
|
|
|
|
|
|
ioHelper,
|
2020-09-15 15:14:44 +02:00
|
|
|
|
loggerFactory,
|
2020-09-02 18:10:29 +10:00
|
|
|
|
profiler,
|
|
|
|
|
|
Mock.Of<IUmbracoBootPermissionChecker>(),
|
|
|
|
|
|
hostingEnvironment,
|
2020-09-17 10:35:11 +02:00
|
|
|
|
backOfficeInfo,
|
2020-09-02 18:10:29 +10:00
|
|
|
|
dbProviderFactoryCreator,
|
|
|
|
|
|
mainDom,
|
|
|
|
|
|
typeFinder,
|
2020-09-04 00:27:43 +10:00
|
|
|
|
appCaches);
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
|
|
|
|
|
runtime.RuntimeEssentials += (sender, args) => eventHandler(sender, args);
|
|
|
|
|
|
|
|
|
|
|
|
return runtime;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region IStartup
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void ConfigureServices(IServiceCollection services)
|
|
|
|
|
|
{
|
|
|
|
|
|
services.AddSingleton(TestHelper.DbProviderFactoryCreator);
|
|
|
|
|
|
var webHostEnvironment = TestHelper.GetWebHostEnvironment();
|
|
|
|
|
|
services.AddRequiredNetCoreServices(TestHelper, webHostEnvironment);
|
|
|
|
|
|
|
|
|
|
|
|
// Add it!
|
|
|
|
|
|
services.AddUmbracoConfiguration(Configuration);
|
2020-09-04 00:27:43 +10:00
|
|
|
|
services.AddUmbracoCore(
|
|
|
|
|
|
webHostEnvironment,
|
|
|
|
|
|
UmbracoContainer,
|
|
|
|
|
|
GetType().Assembly,
|
|
|
|
|
|
AppCaches.NoCache, // Disable caches for integration tests
|
|
|
|
|
|
TestHelper.GetLoggingConfiguration(),
|
2020-09-17 09:01:10 +02:00
|
|
|
|
Configuration,
|
2020-09-04 00:27:43 +10:00
|
|
|
|
CreateTestRuntime,
|
|
|
|
|
|
out _);
|
|
|
|
|
|
|
2020-09-30 14:27:18 +02:00
|
|
|
|
services.AddSignalR();
|
|
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
services.AddUmbracoWebComponents();
|
|
|
|
|
|
services.AddUmbracoRuntimeMinifier(Configuration);
|
|
|
|
|
|
services.AddUmbracoBackOffice();
|
|
|
|
|
|
services.AddUmbracoBackOfficeIdentity();
|
|
|
|
|
|
|
|
|
|
|
|
services.AddMvc();
|
|
|
|
|
|
|
|
|
|
|
|
CustomTestSetup(services);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void Configure(IApplicationBuilder app)
|
|
|
|
|
|
{
|
2020-09-22 10:01:00 +02:00
|
|
|
|
Services.GetRequiredService<IBackofficeSecurityFactory>().EnsureBackofficeSecurity();
|
2020-09-02 18:10:29 +10:00
|
|
|
|
Services.GetRequiredService<IUmbracoContextFactory>().EnsureUmbracoContext();
|
|
|
|
|
|
|
2020-10-06 14:16:29 +02:00
|
|
|
|
// get the currently set options
|
2020-09-02 18:10:29 +10:00
|
|
|
|
var testOptions = TestOptionAttributeBase.GetTestOptions<UmbracoTestAttribute>();
|
|
|
|
|
|
if (testOptions.Boot)
|
|
|
|
|
|
{
|
|
|
|
|
|
app.UseUmbracoCore();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region LocalDb
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly object _dbLocker = new object();
|
|
|
|
|
|
private static LocalDbTestDatabase _dbInstance;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-09-04 00:27:43 +10:00
|
|
|
|
/// Event handler for the <see cref="CoreRuntime.RuntimeEssentials"/> to install the database and register the <see cref="IRuntime"/> to Terminate
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// </summary>
|
2020-09-04 00:27:43 +10:00
|
|
|
|
/// <param name="runtime"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <param name="args"></param>
|
2020-09-04 00:27:43 +10:00
|
|
|
|
protected void UseTestLocalDb(CoreRuntime runtime, RuntimeEssentialsEventArgs args)
|
2020-09-02 18:10:29 +10:00
|
|
|
|
{
|
2020-09-04 00:27:43 +10:00
|
|
|
|
// MUST be terminated on teardown
|
|
|
|
|
|
OnTestTearDown(() => runtime.Terminate());
|
|
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
// This will create a db, install the schema and ensure the app is configured to run
|
2020-09-18 12:53:06 +02:00
|
|
|
|
InstallTestLocalDb(args.DatabaseFactory, runtime.RuntimeLoggerFactory, runtime.State, TestHelper.WorkingDirectory, out var connectionString);
|
2020-09-02 18:10:29 +10:00
|
|
|
|
TestDBConnectionString = connectionString;
|
|
|
|
|
|
InMemoryConfiguration["ConnectionStrings:" + Constants.System.UmbracoConnectionName] = TestDBConnectionString;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-30 20:55:13 +11:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Get or create an instance of <see cref="LocalDbTestDatabase"/>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filesPath"></param>
|
|
|
|
|
|
/// <param name="logger"></param>
|
2020-09-17 12:52:25 +02:00
|
|
|
|
/// <param name="loggerFactory"></param>
|
2020-03-30 20:55:13 +11:00
|
|
|
|
/// <param name="globalSettings"></param>
|
|
|
|
|
|
/// <param name="dbFactory"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// There must only be ONE instance shared between all tests in a session
|
|
|
|
|
|
/// </remarks>
|
2020-09-18 12:53:06 +02:00
|
|
|
|
private static LocalDbTestDatabase GetOrCreateDatabase(string filesPath, ILoggerFactory loggerFactory, IUmbracoDatabaseFactory dbFactory)
|
2020-03-30 20:55:13 +11:00
|
|
|
|
{
|
|
|
|
|
|
lock (_dbLocker)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_dbInstance != null) return _dbInstance;
|
|
|
|
|
|
|
|
|
|
|
|
var localDb = new LocalDb();
|
|
|
|
|
|
if (localDb.IsAvailable == false)
|
|
|
|
|
|
throw new InvalidOperationException("LocalDB is not available.");
|
2020-09-18 12:53:06 +02:00
|
|
|
|
_dbInstance = new LocalDbTestDatabase(loggerFactory, localDb, filesPath, dbFactory);
|
2020-03-30 20:55:13 +11:00
|
|
|
|
return _dbInstance;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Creates a LocalDb instance to use for the test
|
|
|
|
|
|
/// </summary>
|
2020-09-17 12:52:25 +02:00
|
|
|
|
/// <param name="runtimeState"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <param name="workingDirectory"></param>
|
|
|
|
|
|
/// <param name="connectionString"></param>
|
2020-09-17 12:52:25 +02:00
|
|
|
|
/// <param name="databaseFactory"></param>
|
|
|
|
|
|
/// <param name="loggerFactory"></param>
|
|
|
|
|
|
/// <param name="globalSettings"></param>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private void InstallTestLocalDb(
|
2020-09-18 12:53:06 +02:00
|
|
|
|
IUmbracoDatabaseFactory databaseFactory, ILoggerFactory loggerFactory,
|
2020-09-02 18:10:29 +10:00
|
|
|
|
IRuntimeState runtimeState, string workingDirectory, out string connectionString)
|
|
|
|
|
|
{
|
|
|
|
|
|
connectionString = null;
|
|
|
|
|
|
var dbFilePath = Path.Combine(workingDirectory, "LocalDb");
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
// get the currently set db options
|
|
|
|
|
|
var testOptions = TestOptionAttributeBase.GetTestOptions<UmbracoTestAttribute>();
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
if (testOptions.Database == UmbracoTestOptions.Database.None)
|
|
|
|
|
|
return;
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
// need to manually register this factory
|
|
|
|
|
|
DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance);
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
if (!Directory.Exists(dbFilePath))
|
|
|
|
|
|
Directory.CreateDirectory(dbFilePath);
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-18 12:53:06 +02:00
|
|
|
|
var db = GetOrCreateDatabase(dbFilePath, loggerFactory, databaseFactory);
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
switch (testOptions.Database)
|
|
|
|
|
|
{
|
|
|
|
|
|
case UmbracoTestOptions.Database.NewSchemaPerTest:
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
// New DB + Schema
|
|
|
|
|
|
var newSchemaDbId = db.AttachSchema();
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
// Add teardown callback
|
|
|
|
|
|
OnTestTearDown(() => db.Detach(newSchemaDbId));
|
2020-06-09 07:49:26 +02:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
// We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings
|
|
|
|
|
|
if (!databaseFactory.Configured)
|
|
|
|
|
|
{
|
|
|
|
|
|
databaseFactory.Configure(db.ConnectionString, Constants.DatabaseProviders.SqlServer);
|
|
|
|
|
|
}
|
2020-05-17 10:39:30 +01:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
// re-run the runtime level check
|
|
|
|
|
|
runtimeState.DetermineRuntimeLevel();
|
2020-06-30 20:11:39 +02:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level);
|
2020-06-30 20:11:39 +02:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
break;
|
|
|
|
|
|
case UmbracoTestOptions.Database.NewEmptyPerTest:
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
var newEmptyDbId = db.AttachEmpty();
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
// Add teardown callback
|
|
|
|
|
|
OnTestTearDown(() => db.Detach(newEmptyDbId));
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
2020-06-09 07:49:26 +02:00
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
break;
|
|
|
|
|
|
case UmbracoTestOptions.Database.NewSchemaPerFixture:
|
2020-10-06 14:16:29 +02:00
|
|
|
|
// 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
|
2020-10-05 13:33:39 +02:00
|
|
|
|
if (FirstTestInFixture)
|
2020-10-02 14:16:36 +02:00
|
|
|
|
{
|
2020-10-02 14:35:24 +02:00
|
|
|
|
// New DB + Schema
|
|
|
|
|
|
var newSchemaFixtureDbId = db.AttachSchema();
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
2020-10-02 14:35:24 +02:00
|
|
|
|
// Add teardown callback
|
2020-10-06 14:16:29 +02:00
|
|
|
|
OnFixtureTearDown(() => db.Detach(newSchemaFixtureDbId));
|
2020-10-02 14:16:36 +02:00
|
|
|
|
}
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
2020-10-02 14:35:24 +02:00
|
|
|
|
// We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings
|
|
|
|
|
|
if (!databaseFactory.Configured)
|
|
|
|
|
|
{
|
|
|
|
|
|
databaseFactory.Configure(db.ConnectionString, Constants.DatabaseProviders.SqlServer);
|
|
|
|
|
|
}
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
2020-10-02 14:35:24 +02:00
|
|
|
|
// re-run the runtime level check
|
|
|
|
|
|
runtimeState.DetermineRuntimeLevel();
|
2020-09-02 18:10:29 +10:00
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
case UmbracoTestOptions.Database.NewEmptyPerFixture:
|
|
|
|
|
|
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
|
|
//// Add teardown callback
|
|
|
|
|
|
//integrationTest.OnFixtureTearDown(() => db.Detach());
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(testOptions), testOptions, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
connectionString = db.ConnectionString;
|
2020-03-30 20:55:13 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
#endregion
|
2020-07-01 17:42:39 +02:00
|
|
|
|
|
2020-03-30 21:53:30 +11:00
|
|
|
|
#region Common services
|
|
|
|
|
|
|
2020-09-02 18:10:29 +10:00
|
|
|
|
protected LightInjectContainer UmbracoContainer { get; private set; }
|
|
|
|
|
|
private UmbracoServiceProviderFactory _serviceProviderFactory;
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual T GetRequiredService<T>() => Services.GetRequiredService<T>();
|
|
|
|
|
|
|
|
|
|
|
|
public Dictionary<string, string> InMemoryConfiguration { get; } = new Dictionary<string, string>();
|
|
|
|
|
|
|
|
|
|
|
|
public IConfiguration Configuration { get; protected set; }
|
|
|
|
|
|
|
|
|
|
|
|
public TestHelper TestHelper = new TestHelper();
|
|
|
|
|
|
|
2020-06-17 16:39:28 +02:00
|
|
|
|
protected string TestDBConnectionString { get; private set; }
|
|
|
|
|
|
|
2020-05-17 10:39:30 +01:00
|
|
|
|
protected virtual Action<IServiceCollection> CustomTestSetup => services => { };
|
|
|
|
|
|
|
2020-03-30 20:55:13 +11:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Returns the DI container
|
|
|
|
|
|
/// </summary>
|
2020-09-02 18:10:29 +10:00
|
|
|
|
protected IServiceProvider Services { get; set; }
|
2020-03-30 20:55:13 +11:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Returns the <see cref="IScopeProvider"/>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected IScopeProvider ScopeProvider => Services.GetRequiredService<IScopeProvider>();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Returns the <see cref="IScopeAccessor"/>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected IScopeAccessor ScopeAccessor => Services.GetRequiredService<IScopeAccessor>();
|
|
|
|
|
|
|
2020-09-17 10:35:11 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Returns the <see cref="ILoggerFactory"/>
|
|
|
|
|
|
/// </summary>
|
2020-10-06 18:43:07 +02:00
|
|
|
|
protected ILoggerFactory LoggerFactory => Services.GetRequiredService<ILoggerFactory>();
|
2020-09-17 10:35:11 +02:00
|
|
|
|
|
2020-03-30 21:53:30 +11:00
|
|
|
|
protected AppCaches AppCaches => Services.GetRequiredService<AppCaches>();
|
|
|
|
|
|
protected IIOHelper IOHelper => Services.GetRequiredService<IIOHelper>();
|
|
|
|
|
|
protected IShortStringHelper ShortStringHelper => Services.GetRequiredService<IShortStringHelper>();
|
2020-08-24 12:34:37 +02:00
|
|
|
|
protected GlobalSettings GlobalSettings => Services.GetRequiredService<IOptions<GlobalSettings>>().Value;
|
2020-03-30 21:53:30 +11:00
|
|
|
|
protected IMapperCollection Mappers => Services.GetRequiredService<IMapperCollection>();
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Builders
|
|
|
|
|
|
|
|
|
|
|
|
protected UserBuilder UserBuilder = new UserBuilder();
|
|
|
|
|
|
protected UserGroupBuilder UserGroupBuilder = new UserGroupBuilder();
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2020-10-05 13:33:39 +02:00
|
|
|
|
|
|
|
|
|
|
protected static bool FirstTestInSession = true;
|
|
|
|
|
|
|
|
|
|
|
|
protected bool FirstTestInFixture = true;
|
2020-03-30 20:55:13 +11:00
|
|
|
|
}
|
|
|
|
|
|
}
|