using System; using System.Collections.Generic; using System.Data.Common; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using NUnit.Framework; using Umbraco.Core.Composing; using Umbraco.Core.Composing.LightInject; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Scoping; using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.Testing; using Umbraco.Web.BackOffice.AspNetCore; namespace Umbraco.Tests.Integration.Testing { /// /// Abstract class for integration tests /// /// /// This will use a Host Builder to boot and install Umbraco ready for use /// [SingleThreaded] [NonParallelizable] public abstract class UmbracoIntegrationTest { public static LightInjectContainer GetUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory) { var container = UmbracoServiceProviderFactory.CreateServiceContainer(); serviceProviderFactory = new UmbracoServiceProviderFactory(container); var umbracoContainer = serviceProviderFactory.GetContainer(); return umbracoContainer; } /// /// Get or create an instance of /// /// /// /// /// /// /// /// There must only be ONE instance shared between all tests in a session /// public static LocalDbTestDatabase GetOrCreate(string filesPath, ILogger logger, IGlobalSettings globalSettings, IUmbracoDatabaseFactory dbFactory) { lock (_dbLocker) { if (_dbInstance != null) return _dbInstance; var localDb = new LocalDb(); if (localDb.IsAvailable == false) throw new InvalidOperationException("LocalDB is not available."); _dbInstance = new LocalDbTestDatabase(logger, globalSettings, localDb, filesPath, dbFactory); return _dbInstance; } } private static readonly object _dbLocker = new object(); private static LocalDbTestDatabase _dbInstance; private readonly List _testTeardown = new List(); private readonly List _fixtureTeardown = new List(); public void OnTestTearDown(Action tearDown) { _testTeardown.Add(tearDown); } public void OnFixtureTearDown(Action tearDown) { _fixtureTeardown.Add(tearDown); } [OneTimeTearDown] public void FixtureTearDown() { // call all registered callbacks foreach (var action in _fixtureTeardown) { action(); } } [TearDown] public void TearDown() { // call all registered callbacks foreach (var action in _testTeardown) { action(); } } [SetUp] public async Task Setup() { var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory); var testHelper = new TestHelper(); var hostBuilder = new HostBuilder() .UseUmbraco(serviceProviderFactory) .ConfigureServices((hostContext, services) => { var webHostEnvironment = testHelper.GetWebHostEnvironment(); services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); // Add it! services.AddUmbracoConfiguration(hostContext.Configuration); services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly); }); var host = await hostBuilder.StartAsync(); var app = new ApplicationBuilder(host.Services); Services = app.ApplicationServices; // This will create a db, install the schema and ensure the app is configured to run app.UseTestLocalDb(Path.Combine(testHelper.CurrentAssemblyDirectory, "LocalDb"), this); app.UseUmbracoCore(); } /// /// Returns the DI container /// protected IServiceProvider Services { get; private set; } /// /// Returns the /// protected IScopeProvider ScopeProvider => Services.GetRequiredService(); /// /// Returns the /// protected IScopeAccessor ScopeAccessor => Services.GetRequiredService(); /// /// Returns the /// protected ILogger Logger => Services.GetRequiredService(); } }