diff --git a/SafeExamBrowser.Contracts/Communication/Hosts/IServiceHost.cs b/SafeExamBrowser.Contracts/Communication/Hosts/IServiceHost.cs
new file mode 100644
index 00000000..c19bdf4c
--- /dev/null
+++ b/SafeExamBrowser.Contracts/Communication/Hosts/IServiceHost.cs
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+namespace SafeExamBrowser.Contracts.Communication.Hosts
+{
+ ///
+ /// Defines the functionality of the communication host for the service application component.
+ ///
+ public interface IServiceHost : ICommunicationHost
+ {
+ }
+}
diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj
index 88d2ab3a..24cd39b1 100644
--- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj
+++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj
@@ -59,6 +59,7 @@
+
diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs
index f139e73e..806351ba 100644
--- a/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs
+++ b/SafeExamBrowser.Runtime.UnitTests/Operations/ConfigurationOperationTests.cs
@@ -58,7 +58,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
{
var settings = new Settings { ConfigurationMode = ConfigurationMode.Exam };
var url = @"http://www.safeexambrowser.org/whatever.seb";
- var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), FILE_NAME);
+ var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
appConfig.AppDataFilePath = location;
appConfig.ProgramDataFilePath = location;
@@ -76,7 +76,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustUseProgramDataAs2ndPrio()
{
- var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), FILE_NAME);
+ var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
var settings = default(Settings);
appConfig.ProgramDataFilePath = location;
@@ -93,7 +93,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
[TestMethod]
public void Perform_MustUseAppDataAs3rdPrio()
{
- var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), FILE_NAME);
+ var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
var settings = default(Settings);
appConfig.AppDataFilePath = location;
@@ -107,7 +107,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
}
[TestMethod]
- public void Perform_MustCorrectlyHandleBrowserResource()
+ public void Perform_MustTestdatalyHandleBrowserResource()
{
var settings = new Settings { ConfigurationMode = ConfigurationMode.Exam };
var url = @"http://www.safeexambrowser.org/whatever.seb";
@@ -281,7 +281,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
var settings = new Settings { AdminPasswordHash = "9876", ConfigurationMode = ConfigurationMode.ConfigureClient };
var url = @"http://www.safeexambrowser.org/whatever.seb";
- appConfig.AppDataFilePath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), FILE_NAME);
+ appConfig.AppDataFilePath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
repository.Setup(r => r.TryLoadSettings(It.IsAny(), out settings, It.IsAny())).Returns(LoadStatus.Success);
repository.Setup(r => r.TryLoadSettings(It.Is(u => u.LocalPath.Contains(FILE_NAME)), out localSettings, It.IsAny())).Returns(LoadStatus.Success);
@@ -331,16 +331,14 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
}
[TestMethod]
- public void Perform_MustSucceedIfAdminPasswordCorrect()
+ public void Perform_MustSucceedIfAdminPasswordTestdata()
{
var password = "test";
var currentSettings = new Settings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
var nextSettings = new Settings { AdminPasswordHash = "9876", ConfigurationMode = ConfigurationMode.ConfigureClient };
var url = @"http://www.safeexambrowser.org/whatever.seb";
- appConfig.AppDataFilePath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), FILE_NAME);
nextSession.SetupGet(s => s.Settings).Returns(nextSettings);
-
hashAlgorithm.Setup(h => h.GenerateHashFor(It.Is(p => p == password))).Returns(currentSettings.AdminPasswordHash);
repository.Setup(r => r.TryLoadSettings(It.IsAny(), out currentSettings, It.IsAny())).Returns(LoadStatus.Success);
repository.Setup(r => r.TryLoadSettings(It.Is(u => u.AbsoluteUri == url), out nextSettings, It.IsAny())).Returns(LoadStatus.Success);
@@ -370,9 +368,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
var nextSettings = new Settings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.ConfigureClient };
var url = @"http://www.safeexambrowser.org/whatever.seb";
- appConfig.AppDataFilePath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), FILE_NAME);
nextSession.SetupGet(s => s.Settings).Returns(nextSettings);
-
repository.Setup(r => r.TryLoadSettings(It.IsAny(), out currentSettings, It.IsAny())).Returns(LoadStatus.Success);
repository.Setup(r => r.TryLoadSettings(It.Is(u => u.AbsoluteUri == url), out nextSettings, It.IsAny())).Returns(LoadStatus.Success);
repository.Setup(r => r.ConfigureClientWith(It.IsAny(), It.IsAny())).Returns(SaveStatus.Success);
@@ -394,7 +390,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
}
[TestMethod]
- public void Perform_MustSucceedIfSettingsPasswordCorrect()
+ public void Perform_MustSucceedIfSettingsPasswordTestdata()
{
var password = "test";
var settings = new Settings { ConfigurationMode = ConfigurationMode.Exam };
@@ -424,7 +420,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
public void Perform_MustUseCurrentPasswordIfAvailable()
{
var url = @"http://www.safeexambrowser.org/whatever.seb";
- var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), FILE_NAME);
+ var location = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
var settings = new Settings { AdminPasswordHash = "1234", ConfigurationMode = ConfigurationMode.Exam };
appConfig.AppDataFilePath = location;
@@ -455,7 +451,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
var nextSettings = new Settings { AdminPasswordHash = "9876", ConfigurationMode = ConfigurationMode.ConfigureClient };
var url = @"http://www.safeexambrowser.org/whatever.seb";
- appConfig.AppDataFilePath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), FILE_NAME);
+ appConfig.AppDataFilePath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), nameof(Operations), "Testdata", FILE_NAME);
nextSession.SetupGet(s => s.Settings).Returns(nextSettings);
hashAlgorithm.Setup(h => h.GenerateHashFor(It.Is(p => p == password))).Returns(currentSettings.AdminPasswordHash);
@@ -501,11 +497,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
}
[TestMethod]
- public void Repeat_MustPerformForExamWithCorrectUri()
+ public void Repeat_MustPerformForExamWithTestdataUri()
{
var currentSettings = new Settings();
var location = Path.GetDirectoryName(GetType().Assembly.Location);
- var resource = new Uri(Path.Combine(location, nameof(Operations), FILE_NAME));
+ var resource = new Uri(Path.Combine(location, nameof(Operations), "Testdata", FILE_NAME));
var settings = new Settings { ConfigurationMode = ConfigurationMode.Exam };
currentSession.SetupGet(s => s.Settings).Returns(currentSettings);
@@ -523,11 +519,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
}
[TestMethod]
- public void Repeat_MustPerformForClientConfigurationWithCorrectUri()
+ public void Repeat_MustPerformForClientConfigurationWithTestdataUri()
{
var currentSettings = new Settings();
var location = Path.GetDirectoryName(GetType().Assembly.Location);
- var resource = new Uri(Path.Combine(location, nameof(Operations), FILE_NAME));
+ var resource = new Uri(Path.Combine(location, nameof(Operations), "Testdata", FILE_NAME));
var settings = new Settings { ConfigurationMode = ConfigurationMode.ConfigureClient };
currentSession.SetupGet(s => s.Settings).Returns(currentSettings);
@@ -572,7 +568,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
{
var currentSettings = new Settings();
var location = Path.GetDirectoryName(GetType().Assembly.Location);
- var resource = new Uri(Path.Combine(location, nameof(Operations), FILE_NAME));
+ var resource = new Uri(Path.Combine(location, nameof(Operations), "Testdata", FILE_NAME));
var settings = new Settings { ConfigurationMode = ConfigurationMode.ConfigureClient };
currentSession.SetupGet(s => s.Settings).Returns(currentSettings);
diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/SebClientSettings.seb b/SafeExamBrowser.Runtime.UnitTests/Operations/Testdata/SebClientSettings.seb
similarity index 100%
rename from SafeExamBrowser.Runtime.UnitTests/Operations/SebClientSettings.seb
rename to SafeExamBrowser.Runtime.UnitTests/Operations/Testdata/SebClientSettings.seb
diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/WRONG/SebClientSettings.seb b/SafeExamBrowser.Runtime.UnitTests/Operations/WRONG/SebClientSettings.seb
deleted file mode 100644
index 5f282702..00000000
--- a/SafeExamBrowser.Runtime.UnitTests/Operations/WRONG/SebClientSettings.seb
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/SafeExamBrowser.Runtime.UnitTests/SafeExamBrowser.Runtime.UnitTests.csproj b/SafeExamBrowser.Runtime.UnitTests/SafeExamBrowser.Runtime.UnitTests.csproj
index cdca3e7f..ecf0bb3c 100644
--- a/SafeExamBrowser.Runtime.UnitTests/SafeExamBrowser.Runtime.UnitTests.csproj
+++ b/SafeExamBrowser.Runtime.UnitTests/SafeExamBrowser.Runtime.UnitTests.csproj
@@ -121,10 +121,7 @@
-
- Always
-
-
+
Always
diff --git a/SafeExamBrowser.Runtime/SessionContext.cs b/SafeExamBrowser.Runtime/SessionContext.cs
index 5b64eb4d..4efeeb89 100644
--- a/SafeExamBrowser.Runtime/SessionContext.cs
+++ b/SafeExamBrowser.Runtime/SessionContext.cs
@@ -21,41 +21,41 @@ namespace SafeExamBrowser.Runtime
///
/// The currently active .
///
- public KioskMode? ActiveMode { get; set; }
+ internal KioskMode? ActiveMode { get; set; }
///
/// The currently running client process.
///
- public IProcess ClientProcess { get; set; }
+ internal IProcess ClientProcess { get; set; }
///
/// The communication proxy for the currently running client process.
///
- public IClientProxy ClientProxy { get; set; }
+ internal IClientProxy ClientProxy { get; set; }
///
/// The configuration of the currently active session.
///
- public ISessionConfiguration Current { get; set; }
+ internal ISessionConfiguration Current { get; set; }
///
/// The new desktop, if is currently active.
///
- public IDesktop NewDesktop { get; set; }
+ internal IDesktop NewDesktop { get; set; }
///
/// The configuration of the next session to be activated.
///
- public ISessionConfiguration Next { get; set; }
+ internal ISessionConfiguration Next { get; set; }
///
/// The original desktop, if is currently active.
///
- public IDesktop OriginalDesktop { get; set; }
+ internal IDesktop OriginalDesktop { get; set; }
///
/// The path of the configuration file to be used for reconfiguration.
///
- public string ReconfigurationFilePath { get; set; }
+ internal string ReconfigurationFilePath { get; set; }
}
}
diff --git a/SafeExamBrowser.Service.UnitTests/SafeExamBrowser.Service.UnitTests.csproj b/SafeExamBrowser.Service.UnitTests/SafeExamBrowser.Service.UnitTests.csproj
index 39cae989..79b9e3ac 100644
--- a/SafeExamBrowser.Service.UnitTests/SafeExamBrowser.Service.UnitTests.csproj
+++ b/SafeExamBrowser.Service.UnitTests/SafeExamBrowser.Service.UnitTests.csproj
@@ -57,21 +57,49 @@
MinimumRecommendedRules.ruleset
+
+ ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll
+
..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
+
+ ..\packages\Moq.4.11.0\lib\net45\Moq.dll
+
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ ..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
+
+
+
+
+ {47da5933-bef8-4729-94e6-abde2db12262}
+ SafeExamBrowser.Contracts
+
+
+ {fa3c6692-dfed-4afa-bd58-9a3da2753c78}
+ SafeExamBrowser.Service
+
+
+
+
+
+
diff --git a/SafeExamBrowser.Service.UnitTests/ServiceControllerTests.cs b/SafeExamBrowser.Service.UnitTests/ServiceControllerTests.cs
new file mode 100644
index 00000000..f96e0ca4
--- /dev/null
+++ b/SafeExamBrowser.Service.UnitTests/ServiceControllerTests.cs
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using SafeExamBrowser.Contracts.Communication.Hosts;
+using SafeExamBrowser.Contracts.Core.OperationModel;
+
+namespace SafeExamBrowser.Service.UnitTests
+{
+ [TestClass]
+ public class ServiceControllerTests
+ {
+ private Mock bootstrapSequence;
+ private SessionContext sessionContext;
+ private Mock sessionSequence;
+ private Mock serviceHost;
+ private ServiceController sut;
+
+ [TestInitialize]
+ public void Initialize()
+ {
+ bootstrapSequence = new Mock();
+ sessionContext = new SessionContext();
+ sessionSequence = new Mock();
+ serviceHost = new Mock();
+
+ sut = new ServiceController(bootstrapSequence.Object, sessionSequence.Object, serviceHost.Object, sessionContext);
+ }
+
+ [TestMethod]
+ public void Start_MustOnlyPerformBootstrapSequence()
+ {
+ bootstrapSequence.Setup(b => b.TryPerform()).Returns(OperationResult.Success);
+ sessionSequence.Setup(b => b.TryPerform()).Returns(OperationResult.Success);
+ sessionContext.Current = null;
+
+ var success = sut.TryStart();
+
+ bootstrapSequence.Verify(b => b.TryPerform(), Times.Once);
+ bootstrapSequence.Verify(b => b.TryRevert(), Times.Never);
+ sessionSequence.Verify(b => b.TryPerform(), Times.Never);
+ sessionSequence.Verify(b => b.TryRepeat(), Times.Never);
+ sessionSequence.Verify(b => b.TryRevert(), Times.Never);
+
+ Assert.IsTrue(success);
+ }
+
+ [TestMethod]
+ public void Stop_MustRevertSessionThenBootstrapSequence()
+ {
+ var order = 0;
+ var bootstrap = 0;
+ var session = 0;
+
+ sut.TryStart();
+
+ bootstrapSequence.Reset();
+ sessionSequence.Reset();
+
+ bootstrapSequence.Setup(b => b.TryRevert()).Returns(OperationResult.Success).Callback(() => bootstrap = ++order);
+ sessionSequence.Setup(b => b.TryRevert()).Returns(OperationResult.Success).Callback(() => session = ++order);
+
+ sut.Terminate();
+
+ bootstrapSequence.Verify(b => b.TryPerform(), Times.Never);
+ bootstrapSequence.Verify(b => b.TryRevert(), Times.Once);
+ sessionSequence.Verify(b => b.TryPerform(), Times.Never);
+ sessionSequence.Verify(b => b.TryRepeat(), Times.Never);
+ sessionSequence.Verify(b => b.TryRevert(), Times.Once);
+
+ Assert.AreEqual(1, session);
+ Assert.AreEqual(2, bootstrap);
+ }
+
+ [TestMethod]
+ public void Stop_MustNotRevertSessionSequenceIfNoSessionRunning()
+ {
+ var order = 0;
+ var bootstrap = 0;
+ var session = 0;
+
+ sut.TryStart();
+
+ bootstrapSequence.Reset();
+ sessionSequence.Reset();
+
+ bootstrapSequence.Setup(b => b.TryRevert()).Returns(OperationResult.Success).Callback(() => bootstrap = ++order);
+ sessionSequence.Setup(b => b.TryRevert()).Returns(OperationResult.Success).Callback(() => session = ++order);
+ sessionContext.Current = null;
+
+ sut.Terminate();
+
+ bootstrapSequence.Verify(b => b.TryPerform(), Times.Never);
+ bootstrapSequence.Verify(b => b.TryRevert(), Times.Once);
+ sessionSequence.Verify(b => b.TryPerform(), Times.Never);
+ sessionSequence.Verify(b => b.TryRepeat(), Times.Never);
+ sessionSequence.Verify(b => b.TryRevert(), Times.Never);
+
+ Assert.AreEqual(0, session);
+ Assert.AreEqual(1, bootstrap);
+ }
+ }
+}
diff --git a/SafeExamBrowser.Service.UnitTests/packages.config b/SafeExamBrowser.Service.UnitTests/packages.config
index 2f7c5a18..26fb3b97 100644
--- a/SafeExamBrowser.Service.UnitTests/packages.config
+++ b/SafeExamBrowser.Service.UnitTests/packages.config
@@ -1,5 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/SafeExamBrowser.Service/Communication/ServiceHost.cs b/SafeExamBrowser.Service/Communication/ServiceHost.cs
new file mode 100644
index 00000000..624ddcbd
--- /dev/null
+++ b/SafeExamBrowser.Service/Communication/ServiceHost.cs
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+using System;
+using SafeExamBrowser.Communication.Hosts;
+using SafeExamBrowser.Contracts.Communication.Data;
+using SafeExamBrowser.Contracts.Communication.Hosts;
+using SafeExamBrowser.Contracts.Logging;
+
+namespace SafeExamBrowser.Service.Communication
+{
+ internal class ServiceHost : BaseHost, IServiceHost
+ {
+ internal ServiceHost(string address, IHostObjectFactory factory, ILogger logger, int timeout_ms) : base(address, factory, logger, timeout_ms)
+ {
+ }
+
+ protected override bool OnConnect(Guid? token)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override void OnDisconnect()
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override Response OnReceive(Message message)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override Response OnReceive(SimpleMessagePurport message)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/SafeExamBrowser.Service/CompositionRoot.cs b/SafeExamBrowser.Service/CompositionRoot.cs
index fa14dedf..c3880af2 100644
--- a/SafeExamBrowser.Service/CompositionRoot.cs
+++ b/SafeExamBrowser.Service/CompositionRoot.cs
@@ -7,10 +7,16 @@
*/
using System;
+using System.Collections.Generic;
using System.IO;
+using SafeExamBrowser.Communication.Hosts;
+using SafeExamBrowser.Contracts.Core.OperationModel;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Service;
+using SafeExamBrowser.Core.OperationModel;
+using SafeExamBrowser.Core.Operations;
using SafeExamBrowser.Logging;
+using SafeExamBrowser.Service.Communication;
namespace SafeExamBrowser.Service
{
@@ -22,11 +28,30 @@ namespace SafeExamBrowser.Service
internal void BuildObjectGraph()
{
- logger = new Logger();
+ const string SERVICE_ADDRESS = "net.pipe://localhost/safeexambrowser/service";
+ const int FIVE_SECONDS = 5000;
InitializeLogging();
- ServiceController = new ServiceController();
+ var serviceHost = new ServiceHost(SERVICE_ADDRESS, new HostObjectFactory(), new ModuleLogger(logger, nameof(ServiceHost)), FIVE_SECONDS);
+ var sessionContext = new SessionContext();
+
+ var bootstrapOperations = new Queue();
+ var sessionOperations = new Queue();
+
+ // TODO: bootstrapOperations.Enqueue(new RestoreOperation());
+ bootstrapOperations.Enqueue(new CommunicationHostOperation(serviceHost, logger));
+
+ // sessionOperations.Enqueue(new RuntimeConnectionOperation());
+ // sessionOperations.Enqueue(new LogOperation());
+ // sessionOperations.Enqueue(new RegistryOperation());
+ // sessionOperations.Enqueue(new WindowsUpdateOperation());
+ // sessionOperations.Enqueue(new SessionActivationOperation());
+
+ var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
+ var sessionSequence = new RepeatableOperationSequence(logger, sessionOperations);
+
+ ServiceController = new ServiceController(bootstrapSequence, sessionSequence, serviceHost, sessionContext);
}
internal void LogStartupInformation()
@@ -37,6 +62,7 @@ namespace SafeExamBrowser.Service
internal void LogShutdownInformation()
{
+ logger?.Log(string.Empty);
logger?.Log($"# Service terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
@@ -48,9 +74,10 @@ namespace SafeExamBrowser.Service
var logFilePath = Path.Combine(logFolder, $"{logFilePrefix}_Service.log");
var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), logFilePath);
- logFileWriter.Initialize();
+ logger = new Logger();
logger.LogLevel = LogLevel.Debug;
logger.Subscribe(logFileWriter);
+ logFileWriter.Initialize();
}
}
}
diff --git a/SafeExamBrowser.Service/Installer.cs b/SafeExamBrowser.Service/Installer.cs
index 99efedb9..12eae4c7 100644
--- a/SafeExamBrowser.Service/Installer.cs
+++ b/SafeExamBrowser.Service/Installer.cs
@@ -25,7 +25,7 @@ namespace SafeExamBrowser.Service
service = new ServiceInstaller();
service.Description = "Performs operations which require elevated privileges.";
service.DisplayName = "Safe Exam Browser Service";
- service.ServiceName = nameof(SafeExamBrowser.Service);
+ service.ServiceName = nameof(SafeExamBrowser);
service.StartType = ServiceStartMode.Automatic;
Installers.Add(process);
diff --git a/SafeExamBrowser.Service/Properties/AssemblyInfo.cs b/SafeExamBrowser.Service/Properties/AssemblyInfo.cs
index 22ac2c99..340618bb 100644
--- a/SafeExamBrowser.Service/Properties/AssemblyInfo.cs
+++ b/SafeExamBrowser.Service/Properties/AssemblyInfo.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -14,6 +15,7 @@ using System.Runtime.InteropServices;
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
+[assembly: InternalsVisibleTo("SafeExamBrowser.Service.UnitTests")]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("fa3c6692-dfed-4afa-bd58-9a3da2753c78")]
diff --git a/SafeExamBrowser.Service/SafeExamBrowser.Service.csproj b/SafeExamBrowser.Service/SafeExamBrowser.Service.csproj
index 1a193fed..60c8368f 100644
--- a/SafeExamBrowser.Service/SafeExamBrowser.Service.csproj
+++ b/SafeExamBrowser.Service/SafeExamBrowser.Service.csproj
@@ -59,6 +59,7 @@
+
Component
@@ -68,19 +69,31 @@
+
+
+ {c9416a62-0623-4d38-96aa-92516b32f02f}
+ SafeExamBrowser.Communication
+
{47da5933-bef8-4729-94e6-abde2db12262}
SafeExamBrowser.Contracts
+
+ {3d6fdbb6-a4af-4626-bb2b-bf329d44f9cc}
+ SafeExamBrowser.Core
+
{e107026c-2011-4552-a7d8-3a0d37881df6}
SafeExamBrowser.Logging
+
+
+
\ No newline at end of file
diff --git a/SafeExamBrowser.Service/Service.cs b/SafeExamBrowser.Service/Service.cs
index 5e218414..e8b2b38a 100644
--- a/SafeExamBrowser.Service/Service.cs
+++ b/SafeExamBrowser.Service/Service.cs
@@ -18,7 +18,7 @@ namespace SafeExamBrowser.Service
public Service()
{
CanPauseAndContinue = false;
- ServiceName = nameof(SafeExamBrowser.Service);
+ ServiceName = nameof(SafeExamBrowser);
}
public static void Main()
diff --git a/SafeExamBrowser.Service/ServiceController.cs b/SafeExamBrowser.Service/ServiceController.cs
index 847dece5..1bcd22a6 100644
--- a/SafeExamBrowser.Service/ServiceController.cs
+++ b/SafeExamBrowser.Service/ServiceController.cs
@@ -6,20 +6,59 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+using SafeExamBrowser.Contracts.Communication.Hosts;
+using SafeExamBrowser.Contracts.Core.OperationModel;
using SafeExamBrowser.Contracts.Service;
namespace SafeExamBrowser.Service
{
internal class ServiceController : IServiceController
{
+ private IOperationSequence bootstrapSequence;
+ private IRepeatableOperationSequence sessionSequence;
+ private IServiceHost serviceHost;
+ private SessionContext sessionContext;
+
+ private object Session
+ {
+ get { return sessionContext.Current; }
+ }
+
+ private bool SessionIsRunning
+ {
+ get { return Session != null; }
+ }
+
+ public ServiceController(
+ IOperationSequence bootstrapSequence,
+ IRepeatableOperationSequence sessionSequence,
+ IServiceHost serviceHost,
+ SessionContext sessionContext)
+ {
+ this.bootstrapSequence = bootstrapSequence;
+ this.sessionSequence = sessionSequence;
+ this.serviceHost = serviceHost;
+ this.sessionContext = sessionContext;
+ }
+
public bool TryStart()
{
- return true;
+ var result = bootstrapSequence.TryPerform();
+ var success = result == OperationResult.Success;
+
+ return success;
}
public void Terminate()
{
+ var result = default(OperationResult);
+ if (SessionIsRunning)
+ {
+ result = sessionSequence.TryRevert();
+ }
+
+ result = bootstrapSequence.TryRevert();
}
}
}
diff --git a/SafeExamBrowser.Service/SessionContext.cs b/SafeExamBrowser.Service/SessionContext.cs
new file mode 100644
index 00000000..3600d69b
--- /dev/null
+++ b/SafeExamBrowser.Service/SessionContext.cs
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+namespace SafeExamBrowser.Service
+{
+ ///
+ /// Holds all configuration and runtime data required for the session handling.
+ ///
+ internal class SessionContext
+ {
+ ///
+ /// The configuration of the currently active session.
+ ///
+ internal object Current { get; set; }
+
+ ///
+ /// The configuration of the next session to be activated.
+ ///
+ internal object Next { get; set; }
+ }
+}