From 41163c3c781b3cc29656f41dd2e22bf964348fd3 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 13 Mar 2020 14:43:41 +1100 Subject: [PATCH] Gets CoreRuntime loading/booting in integration project --- .../FindAssembliesWithReferencesTo.cs | 10 ++- src/Umbraco.Core/IO/IOHelper.cs | 2 +- src/Umbraco.Core/Routing/UriUtility.cs | 1 + .../Runtime/CoreRuntime.cs | 38 +-------- src/Umbraco.Tests.Common/TestHelperBase.cs | 44 ++++++---- .../ContainerTests.cs | 62 ++------------ .../TestDbProviderFactoryCreator.cs | 2 +- .../Implementations/TestHelper.cs | 80 +++++++++++++++++++ .../TestUmbracoBootPermissionChecker.cs | 2 +- .../Infrastructure/TestBackOfficeInfo.cs | 17 ---- .../Infrastructure/TestGlobalSettings.cs | 51 ------------ .../Infrastructure/TestHostingEnvironment.cs | 49 ------------ src/Umbraco.Tests.Integration/RuntimeTests.cs | 51 ++++++++++++ .../Umbraco.Tests.Integration.csproj | 1 + .../Routing/RenderRouteHandlerTests.cs | 2 +- .../Runtimes/CoreRuntimeTests.cs | 6 +- src/Umbraco.Tests/TestHelpers/TestHelper.cs | 5 ++ .../AspNetCore/AspNetCoreIpResolver.cs | 2 +- src/Umbraco.Web/Runtime/WebRuntime.cs | 5 +- src/Umbraco.Web/UmbracoApplication.cs | 2 +- src/Umbraco.Web/UmbracoApplicationBase.cs | 29 ++++++- 21 files changed, 223 insertions(+), 238 deletions(-) rename src/Umbraco.Tests.Integration/{Infrastructure => Implementations}/TestDbProviderFactoryCreator.cs (94%) create mode 100644 src/Umbraco.Tests.Integration/Implementations/TestHelper.cs rename src/Umbraco.Tests.Integration/{Infrastructure => Implementations}/TestUmbracoBootPermissionChecker.cs (78%) delete mode 100644 src/Umbraco.Tests.Integration/Infrastructure/TestBackOfficeInfo.cs delete mode 100644 src/Umbraco.Tests.Integration/Infrastructure/TestGlobalSettings.cs delete mode 100644 src/Umbraco.Tests.Integration/Infrastructure/TestHostingEnvironment.cs create mode 100644 src/Umbraco.Tests.Integration/RuntimeTests.cs diff --git a/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs index 91225ff973..9378941166 100644 --- a/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs +++ b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Reflection; @@ -42,7 +43,14 @@ namespace Umbraco.Core.Composing { foreach(var target in _targetAssemblies) { - referenceItems.Add(Assembly.Load(target)); + try + { + referenceItems.Add(Assembly.Load(target)); + } + catch (FileNotFoundException) + { + // occurs if we cannot load this ... for example in a test project where we aren't currently referencing Umbraco.Web, etc... + } } } diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index d5e1335f35..8e7dd500f3 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.IO public IOHelper(IHostingEnvironment hostingEnvironment) { - _hostingEnvironment = hostingEnvironment; + _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); } /// diff --git a/src/Umbraco.Core/Routing/UriUtility.cs b/src/Umbraco.Core/Routing/UriUtility.cs index 9cb6bf50f6..0c68580204 100644 --- a/src/Umbraco.Core/Routing/UriUtility.cs +++ b/src/Umbraco.Core/Routing/UriUtility.cs @@ -15,6 +15,7 @@ namespace Umbraco.Web public UriUtility(IHostingEnvironment hostingEnvironment) { + if (hostingEnvironment is null) throw new ArgumentNullException(nameof(hostingEnvironment)); ResetAppDomainAppVirtualPath(hostingEnvironment); } diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index 7b1aff1a4b..5de4c0d795 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -39,7 +39,8 @@ namespace Umbraco.Core.Runtime IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, IDbProviderFactoryCreator dbProviderFactoryCreator, - IMainDom mainDom) + IMainDom mainDom, + ITypeFinder typeFinder) { IOHelper = ioHelper; Configs = configs; @@ -53,6 +54,7 @@ namespace Umbraco.Core.Runtime Logger = logger; MainDom = mainDom; + TypeFinder = typeFinder; // runtime state // beware! must use '() => _factory.GetInstance()' and NOT '_factory.GetInstance' @@ -89,7 +91,7 @@ namespace Umbraco.Core.Runtime /// /// Gets the /// - protected ITypeFinder TypeFinder { get; private set; } + protected ITypeFinder TypeFinder { get; } /// /// Gets the @@ -110,11 +112,6 @@ namespace Umbraco.Core.Runtime // create and register the essential services // ie the bare minimum required to boot - - TypeFinder = GetTypeFinder(); - if (TypeFinder == null) - throw new InvalidOperationException($"The object returned from {nameof(GetTypeFinder)} cannot be null"); - // the boot loader boots using a container scope, so anything that is PerScope will // be disposed after the boot loader has booted, and anything else will remain. // note that this REQUIRES that perWebRequestScope has NOT been enabled yet, else @@ -254,11 +251,6 @@ namespace Umbraco.Core.Runtime return _factory; } - private IUmbracoVersion GetUmbracoVersion(IGlobalSettings globalSettings) - { - return new UmbracoVersion(globalSettings); - } - protected virtual void ConfigureUnhandledException() { //take care of unhandled exceptions - there is nothing we can do to @@ -365,28 +357,6 @@ namespace Umbraco.Core.Runtime protected virtual IEnumerable GetComposerTypes(TypeLoader typeLoader) => typeLoader.GetTypes(); - /// - /// Gets a - /// - /// - protected virtual ITypeFinder GetTypeFinder() - // TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however - // this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now. - => new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider( - // GetEntryAssembly was actually an exposed API by request of the aspnetcore team which works in aspnet core because a website - // in that case is essentially an exe. However in netframework there is no entry assembly, things don't really work that way since - // the process that is running the site is iisexpress, so this returns null. The best we can do is fallback to GetExecutingAssembly() - // which will just return Umbraco.Infrastructure (currently with netframework) and for our purposes that is OK. - // If you are curious... There is really no way to get the entry assembly in netframework without the hosting website having it's own - // code compiled for the global.asax which is the entry point. Because the default global.asax for umbraco websites is just a file inheriting - // from Umbraco.Web.UmbracoApplication, the global.asax file gets dynamically compiled into a DLL in the dynamic folder (we can get an instance - // of that, but this doesn't really help us) but the actually entry execution is still Umbraco.Web. So that is the 'highest' level entry point - // assembly we can get and we can only get that if we put this code into the WebRuntime since the executing assembly is the 'current' one. - // For this purpose, it doesn't matter if it's Umbraco.Web or Umbraco.Infrastructure since all assemblies are in that same path and we are - // getting rid of netframework. - Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly())); - - /// /// Gets the application caches. /// diff --git a/src/Umbraco.Tests.Common/TestHelperBase.cs b/src/Umbraco.Tests.Common/TestHelperBase.cs index 3d6b4617b5..e12c69a596 100644 --- a/src/Umbraco.Tests.Common/TestHelperBase.cs +++ b/src/Umbraco.Tests.Common/TestHelperBase.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Reflection; using Moq; using Umbraco.Core; using Umbraco.Core.Cache; @@ -12,7 +13,6 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; -using Umbraco.Core.Runtime; using Umbraco.Core.Serialization; using Umbraco.Core.Strings; using Umbraco.Core.Sync; @@ -27,21 +27,18 @@ namespace Umbraco.Tests.Common /// public abstract class TestHelperBase { - public TestHelperBase() + private readonly ITypeFinder _typeFinder; + private UriUtility _uriUtility; + private IIOHelper _ioHelper; + + public TestHelperBase(Assembly entryAssembly) { SettingsForTests = new SettingsForTests(); - IOHelper = new IOHelper(GetHostingEnvironment()); - MainDom = new MainDom(Mock.Of(), GetHostingEnvironment(), new MainDomSemaphoreLock(Mock.Of(), GetHostingEnvironment())); - UriUtility = new UriUtility(GetHostingEnvironment()); + MainDom = new SimpleMainDom(); + _typeFinder = new TypeFinder(Mock.Of(), new DefaultUmbracoAssemblyProvider(entryAssembly)); } - public ITypeFinder GetTypeFinder() - { - - var typeFinder = new TypeFinder(Mock.Of(), - new DefaultUmbracoAssemblyProvider(typeof(TestHelperBase).Assembly)); - return typeFinder; - } + public ITypeFinder GetTypeFinder() => _typeFinder; public TypeLoader GetMockedTypeLoader() { @@ -93,12 +90,29 @@ namespace Umbraco.Tests.Common public abstract IDbProviderFactoryCreator DbProviderFactoryCreator { get; } public abstract IBulkSqlInsertProvider BulkSqlInsertProvider { get; } public abstract IMarchal Marchal { get; } - public ICoreDebug CoreDebug { get; } = new CoreDebug(); + public ICoreDebug CoreDebug { get; } = new CoreDebug(); + public IIOHelper IOHelper + { + get + { + if (_ioHelper == null) + _ioHelper = new IOHelper(GetHostingEnvironment()); + return _ioHelper; + } + } - public IIOHelper IOHelper { get; } public IMainDom MainDom { get; } - public UriUtility UriUtility { get; } + public UriUtility UriUtility + { + get + { + if (_uriUtility == null) + _uriUtility = new UriUtility(GetHostingEnvironment()); + return _uriUtility; + } + } + public SettingsForTests SettingsForTests { get; } public IWebRoutingSettings WebRoutingSettings => SettingsForTests.GenerateMockWebRoutingSettings(); diff --git a/src/Umbraco.Tests.Integration/ContainerTests.cs b/src/Umbraco.Tests.Integration/ContainerTests.cs index 1157e74bbf..336c8007d5 100644 --- a/src/Umbraco.Tests.Integration/ContainerTests.cs +++ b/src/Umbraco.Tests.Integration/ContainerTests.cs @@ -1,53 +1,17 @@ using LightInject; -using LightInject.Microsoft.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using Moq; using NUnit.Framework; -using System; -using System.IO; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Composing.LightInject; using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; -using Umbraco.Core.Runtime; -using Umbraco.Tests.Integration.Infrastructure; +using Umbraco.Tests.Integration.Implementations; namespace Umbraco.Tests.Integration { - [TestFixture] - public class RuntimeTests - { - [Test] - public void CoreRuntime() - { - // MSDI - var services = new ServiceCollection(); - var msdiServiceProvider = services.BuildServiceProvider(); - - // LightInject / Umbraco - var umbracoContainer = RegisterFactory.CreateFrom(services, out var lightInjectServiceProvider); - - // Dependencies needed for Core Runtime - var profiler = new VoidProfiler(); - var logger = new ProfilingLogger(new ConsoleLogger(new MessageTemplates()), profiler); - var hostingEnvironment = new TestHostingEnvironment(); - var ioHelper = new IOHelper(hostingEnvironment); - var configs = new Configs(x => null); - var umbracoVersion = new UmbracoVersion(); - var testUmbracoBootPermissionChecker = new TestUmbracoBootPermissionChecker(); - var globalSettings = new TestGlobalSettings(); - var backOfficeInfo = new TestBackOfficeInfo(globalSettings); - var dbFactoryProviderCreator = new TestDbProviderFactoryCreator(); - var mainDom = new SimpleMainDom(); - var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, testUmbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbFactoryProviderCreator, mainDom); - - var factory = coreRuntime.Boot(umbracoContainer); - } - } [TestFixture] public class ContainerTests @@ -64,28 +28,18 @@ namespace Umbraco.Tests.Integration var umbracoContainer = (LightInjectContainer)RegisterFactory.CreateFrom(services, out var lightInjectServiceProvider); // Dependencies needed for creating composition/register essentials - var tempPath = Path.Combine(Path.GetTempPath(), "umbraco-temp-" + Guid.NewGuid()); - if (!Directory.Exists(tempPath)) Directory.CreateDirectory(tempPath); - var globalSettings = Mock.Of(); - - var hostingEnvironment = new TestHostingEnvironment(); - var ioHelper = new IOHelper(hostingEnvironment); - var runtimeCache = NoAppCache.Instance; - var profiler = new VoidProfiler(); - var logger = new ProfilingLogger(new ConsoleLogger(new MessageTemplates()), profiler); - var typeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly)); - var typeLoader = new TypeLoader(ioHelper, typeFinder, runtimeCache, new DirectoryInfo(tempPath), logger, false); + var testHelper = new TestHelper(); var runtimeState = Mock.Of(); - var configs = new Configs(x => null); - var appCaches = new AppCaches(runtimeCache, NoAppCache.Instance, new IsolatedCaches(type => new ObjectCacheAppCache(typeFinder))); - var mainDom = Mock.Of(); var umbracoDatabaseFactory = Mock.Of(); - var umbracoVersion = new UmbracoVersion(); var dbProviderFactoryCreator = Mock.Of(); + var typeLoader = testHelper.GetMockedTypeLoader(); // Register in the container - var composition = new Composition(umbracoContainer, typeLoader, logger, runtimeState, configs, ioHelper, appCaches); - composition.RegisterEssentials(logger, profiler, logger, mainDom, appCaches, umbracoDatabaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, dbProviderFactoryCreator); + var composition = new Composition(umbracoContainer, typeLoader, + testHelper.Logger, runtimeState, testHelper.GetConfigs(), testHelper.IOHelper, testHelper.AppCaches); + composition.RegisterEssentials(testHelper.Logger, testHelper.Profiler, testHelper.Logger, testHelper.MainDom, + testHelper.AppCaches, umbracoDatabaseFactory, typeLoader, runtimeState, testHelper.GetTypeFinder(), + testHelper.IOHelper, testHelper.GetUmbracoVersion(), dbProviderFactoryCreator); // Resolve diff --git a/src/Umbraco.Tests.Integration/Infrastructure/TestDbProviderFactoryCreator.cs b/src/Umbraco.Tests.Integration/Implementations/TestDbProviderFactoryCreator.cs similarity index 94% rename from src/Umbraco.Tests.Integration/Infrastructure/TestDbProviderFactoryCreator.cs rename to src/Umbraco.Tests.Integration/Implementations/TestDbProviderFactoryCreator.cs index f21c86c50e..9081c4ccb4 100644 --- a/src/Umbraco.Tests.Integration/Infrastructure/TestDbProviderFactoryCreator.cs +++ b/src/Umbraco.Tests.Integration/Implementations/TestDbProviderFactoryCreator.cs @@ -2,7 +2,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; -namespace Umbraco.Tests.Integration.Infrastructure +namespace Umbraco.Tests.Integration.Implementations { public class TestDbProviderFactoryCreator : IDbProviderFactoryCreator { diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs new file mode 100644 index 0000000000..7fe18843f7 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs @@ -0,0 +1,80 @@ + +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Hosting; +using Moq; +using System.Net; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Diagnostics; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; +using Umbraco.Core.Runtime; +using Umbraco.Net; +using Umbraco.Tests.Common; +using Umbraco.Web.BackOffice; +using Umbraco.Web.BackOffice.AspNetCore; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; + +namespace Umbraco.Tests.Integration.Implementations +{ + + public class TestHelper : TestHelperBase + { + private IBackOfficeInfo _backOfficeInfo; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IIpResolver _ipResolver; + private readonly IWebHostEnvironment _hostEnvironment; + private readonly IHttpContextAccessor _httpContextAccessor; + + public TestHelper() : base(typeof(TestHelper).Assembly) + { + var httpContext = new DefaultHttpContext(); + httpContext.Connection.RemoteIpAddress = IPAddress.Parse("127.0.0.1"); + _httpContextAccessor = Mock.Of(x => x.HttpContext == httpContext); + _ipResolver = new AspNetIpResolver(_httpContextAccessor); + + _hostEnvironment = Mock.Of(x => + x.ApplicationName == "UmbracoIntegrationTests" + && x.ContentRootPath == CurrentAssemblyDirectory + && x.WebRootPath == CurrentAssemblyDirectory); // same folder for now? + + _hostingEnvironment = new AspNetCoreHostingEnvironment( + SettingsForTests.GetDefaultHostingSettings(), + _hostEnvironment, + _httpContextAccessor, + Mock.Of()); + + Logger = new ProfilingLogger(new ConsoleLogger(new MessageTemplates()), Profiler); + } + + public IUmbracoBootPermissionChecker UmbracoBootPermissionChecker { get; } = new TestUmbracoBootPermissionChecker(); + + public AppCaches AppCaches { get; } = new AppCaches(NoAppCache.Instance, NoAppCache.Instance, new IsolatedCaches(type => NoAppCache.Instance)); + + public IProfilingLogger Logger { get; private set; } + + public IProfiler Profiler { get; } = new VoidProfiler(); + + public IHttpContextAccessor GetHttpContextAccessor() => _httpContextAccessor; + + public IWebHostEnvironment GetWebHostEnvironment() => _hostEnvironment; + + public override IDbProviderFactoryCreator DbProviderFactoryCreator => new TestDbProviderFactoryCreator(); + + public override IBulkSqlInsertProvider BulkSqlInsertProvider => new SqlServerBulkSqlInsertProvider(); + + public override IMarchal Marchal { get; } = new AspNetCoreMarchal(); + + public override IBackOfficeInfo GetBackOfficeInfo() + { + if (_backOfficeInfo == null) + _backOfficeInfo = new AspNetCoreBackOfficeInfo(SettingsForTests.GetDefaultGlobalSettings(GetUmbracoVersion(), IOHelper)); + return _backOfficeInfo; + } + + public override IHostingEnvironment GetHostingEnvironment() => _hostingEnvironment; + + public override IIpResolver GetIpResolver() => _ipResolver; + } +} diff --git a/src/Umbraco.Tests.Integration/Infrastructure/TestUmbracoBootPermissionChecker.cs b/src/Umbraco.Tests.Integration/Implementations/TestUmbracoBootPermissionChecker.cs similarity index 78% rename from src/Umbraco.Tests.Integration/Infrastructure/TestUmbracoBootPermissionChecker.cs rename to src/Umbraco.Tests.Integration/Implementations/TestUmbracoBootPermissionChecker.cs index f97e4fe0e0..b4f876fc66 100644 --- a/src/Umbraco.Tests.Integration/Infrastructure/TestUmbracoBootPermissionChecker.cs +++ b/src/Umbraco.Tests.Integration/Implementations/TestUmbracoBootPermissionChecker.cs @@ -1,6 +1,6 @@ using Umbraco.Core.Runtime; -namespace Umbraco.Tests.Integration.Infrastructure +namespace Umbraco.Tests.Integration.Implementations { public class TestUmbracoBootPermissionChecker : IUmbracoBootPermissionChecker { diff --git a/src/Umbraco.Tests.Integration/Infrastructure/TestBackOfficeInfo.cs b/src/Umbraco.Tests.Integration/Infrastructure/TestBackOfficeInfo.cs deleted file mode 100644 index a32dc5ac13..0000000000 --- a/src/Umbraco.Tests.Integration/Infrastructure/TestBackOfficeInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Umbraco.Core; -using Umbraco.Core.Configuration; - -namespace Umbraco.Tests.Integration.Infrastructure -{ - - public class TestBackOfficeInfo : IBackOfficeInfo - { - public TestBackOfficeInfo(IGlobalSettings globalSettings) - { - GetAbsoluteUrl = globalSettings.UmbracoPath; - } - - public string GetAbsoluteUrl { get; } - - } -} diff --git a/src/Umbraco.Tests.Integration/Infrastructure/TestGlobalSettings.cs b/src/Umbraco.Tests.Integration/Infrastructure/TestGlobalSettings.cs deleted file mode 100644 index 222e3a5571..0000000000 --- a/src/Umbraco.Tests.Integration/Infrastructure/TestGlobalSettings.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Umbraco.Core.Configuration; - -namespace Umbraco.Tests.Integration.Infrastructure -{ - public class TestGlobalSettings : IGlobalSettings - { - public string ReservedUrls => throw new System.NotImplementedException(); - - public string ReservedPaths => throw new System.NotImplementedException(); - - public string Path => throw new System.NotImplementedException(); - - public string ConfigurationStatus { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } - - public int TimeOutInMinutes => throw new System.NotImplementedException(); - - public string DefaultUILanguage => throw new System.NotImplementedException(); - - public bool HideTopLevelNodeFromPath => throw new System.NotImplementedException(); - - public bool UseHttps => throw new System.NotImplementedException(); - - public int VersionCheckPeriod => throw new System.NotImplementedException(); - - public string UmbracoPath => "/Umbraco"; - - public string UmbracoCssPath => throw new System.NotImplementedException(); - - public string UmbracoScriptsPath => throw new System.NotImplementedException(); - - public string UmbracoMediaPath => throw new System.NotImplementedException(); - - public bool IsSmtpServerConfigured => throw new System.NotImplementedException(); - - public ISmtpSettings SmtpSettings => throw new System.NotImplementedException(); - - public bool InstallMissingDatabase => throw new System.NotImplementedException(); - - public bool InstallEmptyDatabase => throw new System.NotImplementedException(); - - public bool DisableElectionForSingleServer => throw new System.NotImplementedException(); - - public string RegisterType => throw new System.NotImplementedException(); - - public string DatabaseFactoryServerVersion => throw new System.NotImplementedException(); - - public string MainDomLock => throw new System.NotImplementedException(); - - public string NoNodesViewPath => throw new System.NotImplementedException(); - } -} diff --git a/src/Umbraco.Tests.Integration/Infrastructure/TestHostingEnvironment.cs b/src/Umbraco.Tests.Integration/Infrastructure/TestHostingEnvironment.cs deleted file mode 100644 index 4a05bb93c7..0000000000 --- a/src/Umbraco.Tests.Integration/Infrastructure/TestHostingEnvironment.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Umbraco.Core; -using Umbraco.Core.Hosting; - -namespace Umbraco.Tests.Integration.Infrastructure -{ - - public class TestHostingEnvironment : IHostingEnvironment - { - public TestHostingEnvironment() - { - var tempPath = Path.Combine(Path.GetTempPath(), "umbraco-temp-" + Guid.NewGuid()); - if (!Directory.Exists(tempPath)) Directory.CreateDirectory(tempPath); - LocalTempPath = tempPath; - ApplicationPhysicalPath = tempPath; // same location for now - } - - public string SiteName => "UmbracoIntegrationTests"; - - public string ApplicationId { get; } = Guid.NewGuid().ToString(); - - public string ApplicationPhysicalPath { get; private set; } - - public string LocalTempPath { get; private set; } - - public string ApplicationVirtualPath => "/"; - - public bool IsDebugMode => true; - - public bool IsHosted => false; - - public Version IISVersion => new Version(0, 0); // TODO not necessary IIS - - public string MapPath(string path) => Path.Combine(ApplicationPhysicalPath, path); - - public string ToAbsolute(string virtualPath, string root) => virtualPath.TrimStart('~'); - - public void RegisterObject(IRegisteredObject registeredObject) - { - } - - public void UnregisterObject(IRegisteredObject registeredObject) - { - } - } -} diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs new file mode 100644 index 0000000000..2823761afd --- /dev/null +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -0,0 +1,51 @@ +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using System.Linq; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Core.Runtime; +using Umbraco.Tests.Integration.Implementations; + +namespace Umbraco.Tests.Integration +{ + [TestFixture] + public class RuntimeTests + { + [Test] + public void BootCoreRuntime() + { + // MSDI + var services = new ServiceCollection(); + + // LightInject / Umbraco + var umbracoContainer = RegisterFactory.CreateFrom(services, out var lightInjectServiceProvider); + + // Dependencies needed for Core Runtime + var testHelper = new TestHelper(); + + var coreRuntime = new CoreRuntime(testHelper.GetConfigs(), testHelper.GetUmbracoVersion(), + testHelper.IOHelper, testHelper.Logger, testHelper.Profiler, testHelper.UmbracoBootPermissionChecker, + testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo(), testHelper.DbProviderFactoryCreator, + testHelper.MainDom, testHelper.GetTypeFinder()); + + var factory = coreRuntime.Boot(umbracoContainer); + + Assert.IsTrue(coreRuntime.MainDom.IsMainDom); + Assert.IsNull(coreRuntime.State.BootFailedException); + Assert.AreEqual(RuntimeLevel.Install, coreRuntime.State.Level); + Assert.IsTrue(MyComposer.IsComposed); + } + } + + [RuntimeLevel(MinLevel = RuntimeLevel.Install)] + public class MyComposer : IUserComposer + { + public void Compose(Composition composition) + { + IsComposed = true; + } + + public static bool IsComposed { get; private set; } + } +} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index 5d8ae11ea2..55b3e8cdca 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -20,6 +20,7 @@ + diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 5698d41009..2bbdd1534e 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -50,7 +50,7 @@ namespace Umbraco.Tests.Routing public class TestRuntime : WebRuntime { public TestRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) - : base(configs, umbracoVersion, ioHelper, Mock.Of(), Mock.Of(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom) + : base(configs, umbracoVersion, ioHelper, Mock.Of(), Mock.Of(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder()) { } diff --git a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs index 9fb77ef59d..c230976c98 100644 --- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs +++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs @@ -120,15 +120,11 @@ namespace Umbraco.Tests.Runtimes public class TestRuntime : CoreRuntime { public TestRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) - :base(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom) + :base(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder()) { } - // override because we cannot use Assembly.GetEntryAssembly in Nunit tests since that is always null - protected override ITypeFinder GetTypeFinder() - => new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly)); - // must override the database factory // else BootFailedException because U cannot connect to the configured db protected internal override IUmbracoDatabaseFactory GetDatabaseFactory() diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs index a6e91cc448..a22d69d68b 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -43,6 +43,11 @@ namespace Umbraco.Tests.TestHelpers private static TestHelperInternal _testHelperInternal = new TestHelperInternal(); private class TestHelperInternal : TestHelperBase { + public TestHelperInternal() : base(typeof(TestHelperInternal).Assembly) + { + + } + public override IDbProviderFactoryCreator DbProviderFactoryCreator { get; } = new UmbracoDbProviderFactoryCreator(Constants.DbProviderNames.SqlCe); public override IBulkSqlInsertProvider BulkSqlInsertProvider { get; } = new SqlCeBulkSqlInsertProvider(); diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreIpResolver.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreIpResolver.cs index 8f231191f2..cee43757d8 100644 --- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreIpResolver.cs +++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreIpResolver.cs @@ -3,7 +3,7 @@ using Umbraco.Net; namespace Umbraco.Web.BackOffice.AspNetCore { - internal class AspNetIpResolver : IIpResolver + public class AspNetIpResolver : IIpResolver { private readonly IHttpContextAccessor _httpContextAccessor; diff --git a/src/Umbraco.Web/Runtime/WebRuntime.cs b/src/Umbraco.Web/Runtime/WebRuntime.cs index ea08dc9135..b4679715f0 100644 --- a/src/Umbraco.Web/Runtime/WebRuntime.cs +++ b/src/Umbraco.Web/Runtime/WebRuntime.cs @@ -33,8 +33,9 @@ namespace Umbraco.Web.Runtime IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, IDbProviderFactoryCreator dbProviderFactoryCreator, - IMainDom mainDom): - base(configs, umbracoVersion, ioHelper, logger, profiler ,new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom) + IMainDom mainDom, + ITypeFinder typeFinder): + base(configs, umbracoVersion, ioHelper, logger, profiler ,new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, typeFinder) { Profiler = GetWebProfiler(); diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index 97f06d3c0f..93d3a6210e 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -30,7 +30,7 @@ namespace Umbraco.Web var mainDom = new MainDom(logger, hostingEnvironment, mainDomLock); - return new WebRuntime(configs, umbracoVersion, ioHelper, logger, profiler, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom); + return new WebRuntime(configs, umbracoVersion, ioHelper, logger, profiler, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, GetTypeFinder()); } } } diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs index a4979777da..6456e8ca1f 100644 --- a/src/Umbraco.Web/UmbracoApplicationBase.cs +++ b/src/Umbraco.Web/UmbracoApplicationBase.cs @@ -23,12 +23,10 @@ namespace Umbraco.Web public abstract class UmbracoApplicationBase : HttpApplication { private IRuntime _runtime; - private IFactory _factory; protected UmbracoApplicationBase() { - if (!Umbraco.Composing.Current.IsInitialized) { var configFactory = new ConfigsFactory(); @@ -44,18 +42,41 @@ namespace Umbraco.Web var backOfficeInfo = new AspNetBackOfficeInfo(configs.Global(), ioHelper, logger, configFactory.WebRoutingSettings); var profiler = new LogProfiler(logger); Umbraco.Composing.Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler); + Logger = logger; } - } protected UmbracoApplicationBase(ILogger logger, Configs configs, IIOHelper ioHelper, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) - { + { if (!Umbraco.Composing.Current.IsInitialized) { + Logger = logger; Umbraco.Composing.Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler); } } + protected ILogger Logger { get; } + + /// + /// Gets a + /// + /// + protected virtual ITypeFinder GetTypeFinder() + // TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however + // this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now. + => new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider( + // GetEntryAssembly was actually an exposed API by request of the aspnetcore team which works in aspnet core because a website + // in that case is essentially an exe. However in netframework there is no entry assembly, things don't really work that way since + // the process that is running the site is iisexpress, so this returns null. The best we can do is fallback to GetExecutingAssembly() + // which will just return Umbraco.Infrastructure (currently with netframework) and for our purposes that is OK. + // If you are curious... There is really no way to get the entry assembly in netframework without the hosting website having it's own + // code compiled for the global.asax which is the entry point. Because the default global.asax for umbraco websites is just a file inheriting + // from Umbraco.Web.UmbracoApplication, the global.asax file gets dynamically compiled into a DLL in the dynamic folder (we can get an instance + // of that, but this doesn't really help us) but the actually entry execution is still Umbraco.Web. So that is the 'highest' level entry point + // assembly we can get and we can only get that if we put this code into the WebRuntime since the executing assembly is the 'current' one. + // For this purpose, it doesn't matter if it's Umbraco.Web or Umbraco.Infrastructure since all assemblies are in that same path and we are + // getting rid of netframework. + Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly())); /// /// Gets a runtime.