diff --git a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj index ed7a2783e3..54ee9a72db 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -80,6 +80,7 @@ + diff --git a/src/Tgstation.Server.Host.Startup/Tgstation.Server.Host.Startup.csproj b/src/Tgstation.Server.Host.Startup/Tgstation.Server.Host.Startup.csproj index 13866885f6..126b5970dd 100644 --- a/src/Tgstation.Server.Host.Startup/Tgstation.Server.Host.Startup.csproj +++ b/src/Tgstation.Server.Host.Startup/Tgstation.Server.Host.Startup.csproj @@ -17,4 +17,8 @@ latest + + + + diff --git a/src/Tgstation.Server.Host.Watchdog/IActiveAssemblyDeleter.cs b/src/Tgstation.Server.Host.Watchdog/IActiveAssemblyDeleter.cs deleted file mode 100644 index 70c5762154..0000000000 --- a/src/Tgstation.Server.Host.Watchdog/IActiveAssemblyDeleter.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Tgstation.Server.Host.Watchdog -{ - /// - /// For deleting s used by the program - /// - interface IActiveAssemblyDeleter - { - /// - /// Deletes an that is in use by the runtime - /// - /// The of the to delete - void DeleteActiveAssembly(string assemblyPath); - } -} \ No newline at end of file diff --git a/src/Tgstation.Server.Host.Watchdog/IActiveLibraryDeleter.cs b/src/Tgstation.Server.Host.Watchdog/IActiveLibraryDeleter.cs new file mode 100644 index 0000000000..34cbef1010 --- /dev/null +++ b/src/Tgstation.Server.Host.Watchdog/IActiveLibraryDeleter.cs @@ -0,0 +1,14 @@ +namespace Tgstation.Server.Host.Watchdog +{ + /// + /// For deleting libraries used by the program + /// + interface IActiveLibraryDeleter + { + /// + /// Deletes a library that is in use by the runtime + /// + /// The path of the library to delete + void DeleteActiveLibrary(string assemblyPath); + } +} \ No newline at end of file diff --git a/src/Tgstation.Server.Host.Watchdog/IsolatedServerFactory.cs b/src/Tgstation.Server.Host.Watchdog/IsolatedServerFactory.cs index b51de730e9..0b83b829be 100644 --- a/src/Tgstation.Server.Host.Watchdog/IsolatedServerFactory.cs +++ b/src/Tgstation.Server.Host.Watchdog/IsolatedServerFactory.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Loader; @@ -30,14 +32,26 @@ namespace Tgstation.Server.Host.Watchdog /// A new public IServer CreateServer(string[] args, string updatePath) { - var assembly = LoadFromAssemblyPath(assemblyPath); - //find the IServerFactory implementation + //help here: https://stackoverflow.com/questions/40908568/assembly-loading-in-net-core - var serverFactoryInterfaceType = typeof(IServerFactory); - var serverFactoryImplementationType = assembly.GetTypes().Where(x => serverFactoryInterfaceType.IsAssignableFrom(x)).First(); + var oldCd = Environment.CurrentDirectory; + Directory.SetCurrentDirectory(Path.GetDirectoryName(assemblyPath)); + try + { + var assembly = LoadFromAssemblyPath(assemblyPath); - var serverFactory = (IServerFactory)Activator.CreateInstance(serverFactoryImplementationType); - return serverFactory.CreateServer(args, updatePath); + //find the IServerFactory implementation + var serverFactoryInterfaceType = typeof(IServerFactory); + var serverFactoryImplementationType = assembly.GetTypes().Where(x => serverFactoryInterfaceType.IsAssignableFrom(x)).First(); + + var serverFactory = (IServerFactory)Activator.CreateInstance(serverFactoryImplementationType); + + return serverFactory.CreateServer(args, updatePath); + } + finally + { + Directory.SetCurrentDirectory(oldCd); + } } //honestly have no idea what this is for, but the examples i see just return null and it seems to work just fine diff --git a/src/Tgstation.Server.Host.Watchdog/PosixActiveAssemblyDeleter.cs b/src/Tgstation.Server.Host.Watchdog/PosixActiveAssemblyDeleter.cs deleted file mode 100644 index e626ecddf4..0000000000 --- a/src/Tgstation.Server.Host.Watchdog/PosixActiveAssemblyDeleter.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.IO; -using System.Reflection; - -namespace Tgstation.Server.Host.Watchdog -{ - /// - /// See for POSIX systems - /// - sealed class PosixActiveAssemblyDeleter : IActiveAssemblyDeleter - { - /// - public void DeleteActiveAssembly(string assemblyPath) => File.Delete(assemblyPath ?? throw new ArgumentNullException(nameof(assemblyPath))); //glory of inodes - } -} diff --git a/src/Tgstation.Server.Host.Watchdog/PosixActiveLibraryDeleter.cs b/src/Tgstation.Server.Host.Watchdog/PosixActiveLibraryDeleter.cs new file mode 100644 index 0000000000..c07b80572d --- /dev/null +++ b/src/Tgstation.Server.Host.Watchdog/PosixActiveLibraryDeleter.cs @@ -0,0 +1,14 @@ +using System; +using System.IO; + +namespace Tgstation.Server.Host.Watchdog +{ + /// + /// See for POSIX systems + /// + sealed class PosixActiveLibraryDeleter : IActiveLibraryDeleter + { + /// + public void DeleteActiveLibrary(string assemblyPath) => Directory.Delete(assemblyPath ?? throw new ArgumentNullException(nameof(assemblyPath)), true); //glory of inodes + } +} diff --git a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj index 70e1a609ed..0b09864c0e 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -23,7 +23,6 @@ - diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index 07372198e5..e1bad698f4 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using System; using System.IO; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Host.Startup; @@ -10,15 +11,11 @@ namespace Tgstation.Server.Host.Watchdog /// sealed class Watchdog : IWatchdog { - /// - /// The initial for the - /// - readonly IServerFactory initialServerFactory; /// - /// The for the + /// The for the /// - readonly IActiveAssemblyDeleter activeAssemblyDeleter; + readonly IActiveLibraryDeleter activeLibraryDeleter; /// /// The for the @@ -33,14 +30,12 @@ namespace Tgstation.Server.Host.Watchdog /// /// Construct a /// - /// The value of - /// The value of + /// The value of /// The value of /// The value of - public Watchdog(IServerFactory initialServerFactory, IActiveAssemblyDeleter activeAssemblyDeleter, IIsolatedAssemblyContextFactory isolatedAssemblyLoader, ILogger logger) + public Watchdog(IActiveLibraryDeleter activeLibraryDeleter, IIsolatedAssemblyContextFactory isolatedAssemblyLoader, ILogger logger) { - this.initialServerFactory = initialServerFactory ?? throw new ArgumentNullException(nameof(initialServerFactory)); - this.activeAssemblyDeleter = activeAssemblyDeleter ?? throw new ArgumentNullException(nameof(activeAssemblyDeleter)); + this.activeLibraryDeleter = activeLibraryDeleter ?? throw new ArgumentNullException(nameof(activeLibraryDeleter)); this.isolatedAssemblyLoader = isolatedAssemblyLoader ?? throw new ArgumentNullException(nameof(isolatedAssemblyLoader)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); } @@ -48,48 +43,43 @@ namespace Tgstation.Server.Host.Watchdog /// public async Task RunAsync(string[] args, CancellationToken cancellationToken) { + const string DefaultAssemblyPath = "Default"; + + var assemblyStoragePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "lib"); + var assemblyName = String.Join(".", nameof(Tgstation), nameof(Server), nameof(Host), "dll"); + logger.LogInformation("Host watchdog starting..."); + + var nextAssemblyPath = Path.GetFullPath(Path.Combine(assemblyStoragePath, DefaultAssemblyPath)); + string lastAssemblyPath = null; try { - //first run the host we started with - logger.LogTrace("Running with initial server factory..."); - var serverFactory = initialServerFactory; - logger.LogTrace("Determining location of host assembly..."); - var assemblyPath = serverFactory.GetType().Assembly.Location; - logger.LogDebug("Path to initial host assembly: {0}", assemblyPath); - var assemblyName = Path.GetFileName(assemblyPath); - const string UpdatePath = "Updates"; - var newAssemblyDirectory = Path.Combine(Path.GetDirectoryName(assemblyPath), UpdatePath); - - var firstIteration = true; - do + while (!cancellationToken.IsCancellationRequested) using (logger.BeginScope("Host invocation")) { + logger.LogTrace("Atttempting to create new server factory..."); Guid updateGuid; - using (var server = serverFactory.CreateServer(args, newAssemblyDirectory)) - { - logger.LogTrace("Running server..."); - await server.RunAsync(cancellationToken).ConfigureAwait(false); - logger.LogInformation("Active host exited."); + { //forces serverFactory out of the picture once the scope ends + var serverFactory = isolatedAssemblyLoader.CreateIsolatedServerFactory(Path.Combine(nextAssemblyPath, assemblyName)); + using (var server = serverFactory.CreateServer(args, assemblyStoragePath)) + { + logger.LogTrace("Running server..."); + await server.RunAsync(cancellationToken).ConfigureAwait(false); + logger.LogInformation("Active host exited."); - if (!server.UpdateGuid.HasValue) - break; - updateGuid = server.UpdateGuid.Value; + if (!server.UpdateGuid.HasValue) + break; + updateGuid = server.UpdateGuid.Value; + } } logger.LogInformation("Update path is set to \"{0}\", attempting host assembly hotswap...", updateGuid); GC.Collect(Int32.MaxValue, GCCollectionMode.Forced, true, true); - if (!firstIteration) - { - logger.LogTrace("Deleting old host assembly"); - //TODO: make this use directories - //activeAssemblyDeleter.DeleteActiveAssembly(newAssemblyDirectory); - } - logger.LogTrace("Atttempting to create new server factory..."); - serverFactory = isolatedAssemblyLoader.CreateIsolatedServerFactory(Path.Combine(newAssemblyDirectory, updateGuid.ToString(), assemblyName)); - firstIteration = false; + + activeLibraryDeleter.DeleteActiveLibrary(nextAssemblyPath); + + nextAssemblyPath = Path.Combine(assemblyStoragePath, updateGuid.ToString()); } - while (!cancellationToken.IsCancellationRequested); } catch (OperationCanceledException) { @@ -98,6 +88,11 @@ namespace Tgstation.Server.Host.Watchdog catch (Exception e) { logger.LogCritical("Error running host assembly! Exception: {0}", e); + nextAssemblyPath = lastAssemblyPath ?? DefaultAssemblyPath; //don't wanna save a critfailed assembly + } + if (nextAssemblyPath != DefaultAssemblyPath) + { + logger.LogInformation("Setting next default host assembly path to {0}...", nextAssemblyPath); } logger.LogInformation("Host watchdog exiting..."); } diff --git a/src/Tgstation.Server.Host.Watchdog/WatchdogFactory.cs b/src/Tgstation.Server.Host.Watchdog/WatchdogFactory.cs index 8e2ac94dce..f9c11a511c 100644 --- a/src/Tgstation.Server.Host.Watchdog/WatchdogFactory.cs +++ b/src/Tgstation.Server.Host.Watchdog/WatchdogFactory.cs @@ -10,6 +10,6 @@ namespace Tgstation.Server.Host.Watchdog { /// [ExcludeFromCodeCoverage] - public IWatchdog CreateWatchdog(ILoggerFactory loggerFactory) => new Watchdog(new ServerFactory(), RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? (IActiveAssemblyDeleter)new WindowsActiveAssemblyDeleter() : new PosixActiveAssemblyDeleter(), new IsolatedAssemblyContextFactory(), loggerFactory?.CreateLogger() ?? throw new ArgumentNullException(nameof(loggerFactory))); + public IWatchdog CreateWatchdog(ILoggerFactory loggerFactory) => new Watchdog(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? (IActiveLibraryDeleter)new WindowsActiveLibraryDeleter() : new PosixActiveLibraryDeleter(), new IsolatedAssemblyContextFactory(), loggerFactory?.CreateLogger() ?? throw new ArgumentNullException(nameof(loggerFactory))); } } diff --git a/src/Tgstation.Server.Host.Watchdog/WindowsActiveAssemblyDeleter.cs b/src/Tgstation.Server.Host.Watchdog/WindowsActiveAssemblyDeleter.cs deleted file mode 100644 index a926cfc51d..0000000000 --- a/src/Tgstation.Server.Host.Watchdog/WindowsActiveAssemblyDeleter.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Runtime.InteropServices; - -namespace Tgstation.Server.Host.Watchdog -{ - /// - /// See for Windows systems - /// - sealed class WindowsActiveAssemblyDeleter : IActiveAssemblyDeleter - { - /// - /// Set a file located at to be deleted on reboot - /// - /// The file to delete on reboot - [ExcludeFromCodeCoverage] - static void DeleteFileOnReboot(string path) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !NativeMethods.MoveFileEx(path, null, NativeMethods.MoveFileFlags.DelayUntilReboot)) - throw new Win32Exception(Marshal.GetLastWin32Error()); - } - - /// - public void DeleteActiveAssembly(string assemblyPath) - { - if (assemblyPath == null) - throw new ArgumentNullException(nameof(assemblyPath)); - - //Can't use Path.GetTempFileName() because it may cross drives, which won't actually rename the file - var tmpLocation = String.Concat(assemblyPath, Guid.NewGuid()); - File.Move(assemblyPath, tmpLocation); - DeleteFileOnReboot(tmpLocation); - } - } -} diff --git a/src/Tgstation.Server.Host.Watchdog/WindowsActiveLibraryDeleter.cs b/src/Tgstation.Server.Host.Watchdog/WindowsActiveLibraryDeleter.cs new file mode 100644 index 0000000000..a2a98b4bac --- /dev/null +++ b/src/Tgstation.Server.Host.Watchdog/WindowsActiveLibraryDeleter.cs @@ -0,0 +1,36 @@ +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; + +namespace Tgstation.Server.Host.Watchdog +{ + /// + /// See for Windows systems + /// + sealed class WindowsActiveLibraryDeleter : IActiveLibraryDeleter + { + /// + /// Set a directory located at to be deleted on reboot + /// + /// The file to delete on reboot + [ExcludeFromCodeCoverage] + static void DeleteDirectoryOnReboot(string path) + { + if (!NativeMethods.MoveFileEx(path, null, NativeMethods.MoveFileFlags.DelayUntilReboot)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + /// + public void DeleteActiveLibrary(string assemblyPath) + { + if (assemblyPath == null) + throw new ArgumentNullException(nameof(assemblyPath)); + + var tmpLocation = Path.Combine(Path.GetDirectoryName(assemblyPath), Guid.NewGuid().ToString()); + Directory.Move(assemblyPath, tmpLocation); + DeleteDirectoryOnReboot(tmpLocation); + } + } +} diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index 42f9cafeae..e01c600962 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -56,6 +56,7 @@ namespace Tgstation.Server.Host [ExcludeFromCodeCoverage] public async Task RunAsync(CancellationToken cancellationToken) { + Console.WriteLine("Hello world!"); using (cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) using (var webHost = webHostBuilder .UseStartup() diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedAssemblyContextFactory.cs b/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedAssemblyContextFactory.cs deleted file mode 100644 index 2f2e2d0f7d..0000000000 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedAssemblyContextFactory.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Tgstation.Server.Host.Watchdog.Tests -{ - /// - /// Tests for - /// - [TestClass] - public sealed class TestIsolatedAssemblyContextFactory - { - [TestMethod] - public void TestServerFactoryCreation() - { - var contextFactory = new IsolatedAssemblyContextFactory(); - Assert.IsNotNull(contextFactory.CreateIsolatedServerFactory(typeof(ServerFactory).Assembly.Location)); - } - } -} diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedServerFactory.cs b/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedServerFactory.cs deleted file mode 100644 index 384139308b..0000000000 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedServerFactory.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; - -namespace Tgstation.Server.Host.Watchdog.Tests -{ - /// - /// Tests for - /// - [TestClass] - public sealed class TestIsolatedServerFactory - { - [TestMethod] - public void TestConstruction() - { - Assert.ThrowsException(() => new IsolatedServerFactory(null)); - var isf = new IsolatedServerFactory(typeof(ServerFactory).Assembly.Location); - } - - [TestMethod] - public void TestLoading() - { - var isf = new IsolatedServerFactory(typeof(ServerFactory).Assembly.Location); - Assert.IsNotNull(isf.CreateServer(Array.Empty(), String.Empty)); - } - } -} diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/TestPosixActiveAssemblyDeleter.cs b/tests/Tgstation.Server.Host.Watchdog.Tests/TestPosixActiveAssemblyDeleter.cs deleted file mode 100644 index 9f77307950..0000000000 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/TestPosixActiveAssemblyDeleter.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.IO; - -namespace Tgstation.Server.Host.Watchdog.Tests -{ - /// - /// Tests for - /// - [TestClass] - public sealed class TestPosixActiveAssemblyDeleter - { - [TestMethod] - public void TestAssemblyDeletion() - { - var ourAssembly = GetType().Assembly; - var fakeAssemblyPath = String.Concat(ourAssembly.Location, Guid.NewGuid()); - File.Copy(ourAssembly.Location, fakeAssemblyPath); - - try - { - var deleter = new PosixActiveAssemblyDeleter(); - deleter.DeleteActiveAssembly(fakeAssemblyPath); - Assert.IsFalse(File.Exists(fakeAssemblyPath)); - } - catch - { - File.Delete(fakeAssemblyPath); - throw; - } - } - - [TestMethod] - public void TestNullInvoke() - { - var deleter = new PosixActiveAssemblyDeleter(); - Assert.ThrowsException(() => deleter.DeleteActiveAssembly(null)); - } - } -} diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs b/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs index 8f233120d5..15685e68e4 100644 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs +++ b/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs @@ -14,15 +14,13 @@ namespace Tgstation.Server.Host.Watchdog.Tests [TestMethod] public void TestConstruction() { - Assert.ThrowsException(() => new Watchdog(null, null, null, null)); - var mockServerFactory = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockServerFactory.Object, null, null, null)); - var mockActiveAssemblyDeleter = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockServerFactory.Object, mockActiveAssemblyDeleter.Object, null, null)); + Assert.ThrowsException(() => new Watchdog(null, null, null)); + var mockActiveAssemblyDeleter = new Mock(); + Assert.ThrowsException(() => new Watchdog(mockActiveAssemblyDeleter.Object, null, null)); var mockIsolatedServerContextFactory = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockServerFactory.Object, mockActiveAssemblyDeleter.Object, mockIsolatedServerContextFactory.Object, null)); + Assert.ThrowsException(() => new Watchdog(mockActiveAssemblyDeleter.Object, mockIsolatedServerContextFactory.Object, null)); var mockLogger = new LoggerFactory().CreateLogger(); - var wd = new Watchdog(mockServerFactory.Object, mockActiveAssemblyDeleter.Object, mockIsolatedServerContextFactory.Object, mockLogger); + var wd = new Watchdog(mockActiveAssemblyDeleter.Object, mockIsolatedServerContextFactory.Object, mockLogger); } class MockServerFactory : IServerFactory @@ -37,11 +35,11 @@ namespace Tgstation.Server.Host.Watchdog.Tests { var mockServer = new Mock(); var mockServerFactory = new MockServerFactory(mockServer.Object); - var mockActiveAssemblyDeleter = new Mock(); + var mockActiveAssemblyDeleter = new Mock(); var mockIsolatedServerContextFactory = new Mock(); var mockLogger = new LoggerFactory().CreateLogger(); - var wd = new Watchdog(mockServerFactory, mockActiveAssemblyDeleter.Object, mockIsolatedServerContextFactory.Object, mockLogger); + var wd = new Watchdog(mockActiveAssemblyDeleter.Object, mockIsolatedServerContextFactory.Object, mockLogger); using (var cts = new CancellationTokenSource()) { diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWindowsActiveAssemblyDeleter.cs b/tests/Tgstation.Server.Host.Watchdog.Tests/TestWindowsActiveAssemblyDeleter.cs deleted file mode 100644 index 70e0a326c9..0000000000 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWindowsActiveAssemblyDeleter.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.ComponentModel; -using System.IO; - -namespace Tgstation.Server.Host.Watchdog.Tests -{ - /// - /// Tests for - /// - [TestClass] - public sealed class TestWindowsActiveAssemblyDeleter - { - [TestMethod] - public void TestAssemblyDeletion() - { - var ourAssembly = GetType().Assembly; - var fakeAssemblyPath = String.Concat(ourAssembly.Location, Guid.NewGuid()); - File.Copy(ourAssembly.Location, fakeAssemblyPath); - - try - { - var deleter = new WindowsActiveAssemblyDeleter(); - try - { - deleter.DeleteActiveAssembly(fakeAssemblyPath); - } - catch (Win32Exception e) - { - Assert.AreEqual(e.NativeErrorCode, 5); - } - Assert.IsFalse(File.Exists(fakeAssemblyPath)); - } - catch - { - File.Delete(fakeAssemblyPath); - throw; - } - } - - [TestMethod] - public void TestNullInvoke() - { - var deleter = new WindowsActiveAssemblyDeleter(); - Assert.ThrowsException(() => deleter.DeleteActiveAssembly(null)); - } - } -} diff --git a/tgstation-server.sln b/tgstation-server.sln index 6b4c152ebc..779617bbd2 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -52,6 +52,9 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Tests", "tests\Tgstation.Server.Host.Tests\Tgstation.Server.Host.Tests.csproj", "{A3362FF6-550F-480F-859E-8EC1EB6EAB31}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Watchdog", "src\Tgstation.Server.Host.Watchdog\Tgstation.Server.Host.Watchdog.csproj", "{5D2D682C-6BF0-439C-850B-6AB945BBEAEA}" + ProjectSection(ProjectDependencies) = postProject + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A} = {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A} + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Watchdog.Tests", "tests\Tgstation.Server.Host.Watchdog.Tests\Tgstation.Server.Host.Watchdog.Tests.csproj", "{7500F776-4384-4B5F-A8D8-22461CAD108B}" EndProject