SEBWIN-219: Implemented draft of communication operation and runtime communication host.
This commit is contained in:
parent
c10e141e7f
commit
8cd0659a22
32 changed files with 626 additions and 170 deletions
|
@ -58,7 +58,7 @@ namespace SafeExamBrowser.Client
|
|||
browserInfo = new BrowserApplicationInfo();
|
||||
logger = new Logger();
|
||||
nativeMethods = new NativeMethods();
|
||||
settings = new SettingsRepository().LoadDefaults();
|
||||
settings = new ConfigurationRepository().LoadDefaultSettings();
|
||||
systemInfo = new SystemInfo();
|
||||
uiFactory = new UserInterfaceFactory();
|
||||
|
||||
|
|
87
SafeExamBrowser.Configuration/ConfigurationRepository.cs
Normal file
87
SafeExamBrowser.Configuration/ConfigurationRepository.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 System.IO;
|
||||
using System.Reflection;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
public class ConfigurationRepository : IConfigurationRepository
|
||||
{
|
||||
private RuntimeInfo runtimeInfo;
|
||||
|
||||
public ISettings CurrentSettings { get; private set; }
|
||||
|
||||
public IRuntimeInfo RuntimeInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
if (runtimeInfo == null)
|
||||
{
|
||||
InitializeRuntimeInfo();
|
||||
}
|
||||
|
||||
return runtimeInfo;
|
||||
}
|
||||
}
|
||||
|
||||
public ISettings LoadSettings(Uri path)
|
||||
{
|
||||
// TODO
|
||||
|
||||
return LoadDefaultSettings();
|
||||
}
|
||||
|
||||
public ISettings LoadDefaultSettings()
|
||||
{
|
||||
var settings = new Settings.Settings();
|
||||
|
||||
// TODO
|
||||
settings.ServicePolicy = ServicePolicy.Optional;
|
||||
|
||||
CurrentSettings = settings;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
private void InitializeRuntimeInfo()
|
||||
{
|
||||
var appDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(SafeExamBrowser));
|
||||
var baseAddress = "net.pipe://localhost/safeexambrowser";
|
||||
var clientId = Guid.NewGuid();
|
||||
var executable = Assembly.GetEntryAssembly();
|
||||
var runtimeId = Guid.NewGuid();
|
||||
var startTime = DateTime.Now;
|
||||
var logFolder = Path.Combine(appDataFolder, "Logs");
|
||||
var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
|
||||
|
||||
runtimeInfo = new RuntimeInfo
|
||||
{
|
||||
ApplicationStartTime = startTime,
|
||||
AppDataFolder = appDataFolder,
|
||||
BrowserCachePath = Path.Combine(appDataFolder, "Cache"),
|
||||
BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt"),
|
||||
ClientId = Guid.NewGuid(),
|
||||
ClientAddress = $"{baseAddress}/client/{clientId}",
|
||||
ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt"),
|
||||
DefaultSettingsFileName = "SebClientSettings.seb",
|
||||
ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright,
|
||||
ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser)),
|
||||
ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title,
|
||||
ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion,
|
||||
RuntimeId = Guid.NewGuid(),
|
||||
RuntimeAddress = $"{baseAddress}/runtime/{runtimeId}",
|
||||
RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt"),
|
||||
ServiceAddress = $"{baseAddress}/service"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,12 +18,17 @@ namespace SafeExamBrowser.Configuration
|
|||
public DateTime ApplicationStartTime { get; set; }
|
||||
public string BrowserCachePath { get; set; }
|
||||
public string BrowserLogFile { get; set; }
|
||||
public string ClientAddress { get; set; }
|
||||
public Guid ClientId { get; set; }
|
||||
public string ClientLogFile { get; set; }
|
||||
public string DefaultSettingsFileName { get; set; }
|
||||
public string ProgramCopyright { get; set; }
|
||||
public string ProgramDataFolder { get; set; }
|
||||
public string ProgramTitle { get; set; }
|
||||
public string ProgramVersion { get; set; }
|
||||
public string RuntimeAddress { get; set; }
|
||||
public Guid RuntimeId { get; set; }
|
||||
public string RuntimeLogFile { get; set; }
|
||||
public string ServiceAddress { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
<Compile Include="Settings\MouseSettings.cs" />
|
||||
<Compile Include="Settings\Settings.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Settings\SettingsRepository.cs" />
|
||||
<Compile Include="ConfigurationRepository.cs" />
|
||||
<Compile Include="SystemInfo.cs" />
|
||||
<Compile Include="Settings\TaskbarSettings.cs" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.Configuration.Settings;
|
||||
|
||||
namespace SafeExamBrowser.Configuration.Settings
|
||||
{
|
||||
public class SettingsRepository : ISettingsRepository
|
||||
{
|
||||
public ISettings Current { get; private set; }
|
||||
|
||||
public ISettings Load(Uri path)
|
||||
{
|
||||
// TODO
|
||||
|
||||
return LoadDefaults();
|
||||
}
|
||||
|
||||
public ISettings LoadDefaults()
|
||||
{
|
||||
var settings = new Settings();
|
||||
|
||||
// TODO
|
||||
settings.ServicePolicy = ServicePolicy.Optional;
|
||||
|
||||
Current = settings;
|
||||
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Behaviour
|
||||
{
|
||||
public interface IRuntimeController
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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
|
||||
{
|
||||
public interface ICommunicationHost
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the host is running and ready for communication.
|
||||
/// </summary>
|
||||
bool IsRunning { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Starts the host and opens it for communication.
|
||||
/// </summary>
|
||||
void Start();
|
||||
|
||||
/// <summary>
|
||||
/// Closes and terminates the host.
|
||||
/// </summary>
|
||||
void Stop();
|
||||
}
|
||||
}
|
15
SafeExamBrowser.Contracts/Communication/IRuntimeHost.cs
Normal file
15
SafeExamBrowser.Contracts/Communication/IRuntimeHost.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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
|
||||
{
|
||||
public interface IRuntimeHost : ICommunicationHost
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -7,26 +7,32 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Configuration.Settings
|
||||
namespace SafeExamBrowser.Contracts.Configuration
|
||||
{
|
||||
public interface ISettingsRepository
|
||||
public interface IConfigurationRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the current settings, i.e. the last ones which were loaded. If no settings have been loaded yet, this property will
|
||||
/// be <c>null</c>.
|
||||
/// be <c>null</c>!
|
||||
/// </summary>
|
||||
ISettings Current { get; }
|
||||
ISettings CurrentSettings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The runtime information for the currently running application instance.
|
||||
/// </summary>
|
||||
IRuntimeInfo RuntimeInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load settings from the specified path.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ArgumentException">Thrown if the given path cannot be resolved to a settings file.</exception>
|
||||
ISettings Load(Uri path);
|
||||
/// <exception cref="ArgumentException">Thrown if the given path cannot be resolved to a settings file.</exception>
|
||||
ISettings LoadSettings(Uri path);
|
||||
|
||||
/// <summary>
|
||||
/// Loads the default settings.
|
||||
/// </summary>
|
||||
ISettings LoadDefaults();
|
||||
ISettings LoadDefaultSettings();
|
||||
}
|
||||
}
|
|
@ -32,6 +32,22 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// </summary>
|
||||
string BrowserLogFile { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The communication address of the client component.
|
||||
///
|
||||
/// TODO: Will need to be updated for each new client instance!
|
||||
///
|
||||
/// </summary>
|
||||
string ClientAddress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for the currently running client instance.
|
||||
///
|
||||
/// TODO: Will need to be updated for each new client instance!
|
||||
///
|
||||
/// </summary>
|
||||
Guid ClientId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The file path under which the log of the client component is to be stored.
|
||||
/// </summary>
|
||||
|
@ -62,9 +78,24 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// </summary>
|
||||
string ProgramVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The communication address of the runtime component.
|
||||
/// </summary>
|
||||
string RuntimeAddress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for the currently running runtime instance.
|
||||
/// </summary>
|
||||
Guid RuntimeId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The file path under which the log of the runtime component is to be stored.
|
||||
/// </summary>
|
||||
string RuntimeLogFile { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The communication address of the service component.
|
||||
/// </summary>
|
||||
string ServiceAddress { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,12 +35,15 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
ProgressIndicator_InitializeTaskbar,
|
||||
ProgressIndicator_InitializeWindowMonitoring,
|
||||
ProgressIndicator_InitializeWorkingArea,
|
||||
ProgressIndicator_RestartCommunicationHost,
|
||||
ProgressIndicator_RestoreWorkingArea,
|
||||
ProgressIndicator_RevertKioskMode,
|
||||
ProgressIndicator_ShutdownProcedure,
|
||||
ProgressIndicator_StartCommunicationHost,
|
||||
ProgressIndicator_StartEventHandling,
|
||||
ProgressIndicator_StartKeyboardInterception,
|
||||
ProgressIndicator_StartMouseInterception,
|
||||
ProgressIndicator_StopCommunicationHost,
|
||||
ProgressIndicator_StopEventHandling,
|
||||
ProgressIndicator_StopKeyboardInterception,
|
||||
ProgressIndicator_StopMouseInterception,
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
<Compile Include="Behaviour\Operations\IOperationSequence.cs" />
|
||||
<Compile Include="Communication\ICommunication.cs" />
|
||||
<Compile Include="Communication\IClientProxy.cs" />
|
||||
<Compile Include="Communication\ICommunicationHost.cs" />
|
||||
<Compile Include="Communication\IRuntimeHost.cs" />
|
||||
<Compile Include="Communication\IRuntimeProxy.cs" />
|
||||
<Compile Include="Communication\IServiceProxy.cs" />
|
||||
<Compile Include="Communication\Messages\IMessage.cs" />
|
||||
|
@ -78,7 +80,7 @@
|
|||
<Compile Include="Configuration\Settings\IKeyboardSettings.cs" />
|
||||
<Compile Include="Configuration\Settings\IMouseSettings.cs" />
|
||||
<Compile Include="Configuration\Settings\ISettings.cs" />
|
||||
<Compile Include="Configuration\Settings\ISettingsRepository.cs" />
|
||||
<Compile Include="Configuration\IConfigurationRepository.cs" />
|
||||
<Compile Include="Configuration\Settings\ITaskbarSettings.cs" />
|
||||
<Compile Include="Configuration\Settings\KioskMode.cs" />
|
||||
<Compile Include="Configuration\Settings\ServicePolicy.cs" />
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Behaviour.Operations;
|
||||
|
||||
namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
|
||||
{
|
||||
[TestClass]
|
||||
public class CommunicationOperationTests
|
||||
{
|
||||
private Mock<ICommunicationHost> hostMock;
|
||||
private Mock<ILogger> loggerMock;
|
||||
private CommunicationOperation sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
hostMock = new Mock<ICommunicationHost>();
|
||||
loggerMock = new Mock<ILogger>();
|
||||
|
||||
sut = new CommunicationOperation(hostMock.Object, loggerMock.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustRestartHostOnRepeat()
|
||||
{
|
||||
var order = 0;
|
||||
var stop = 0;
|
||||
var start = 0;
|
||||
|
||||
hostMock.Setup(h => h.Stop()).Callback(() => stop = ++order);
|
||||
hostMock.Setup(h => h.Start()).Callback(() => start = ++order);
|
||||
|
||||
sut.Repeat();
|
||||
|
||||
hostMock.Verify(h => h.Stop(), Times.Once);
|
||||
hostMock.Verify(h => h.Start(), Times.Once);
|
||||
|
||||
Assert.AreEqual(stop, 1);
|
||||
Assert.AreEqual(start, 2);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustStartHostOnPerform()
|
||||
{
|
||||
sut.Perform();
|
||||
|
||||
hostMock.Verify(h => h.Start(), Times.Once);
|
||||
hostMock.Verify(h => h.Stop(), Times.Never);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustStopHostOnRevert()
|
||||
{
|
||||
sut.Revert();
|
||||
|
||||
hostMock.Verify(h => h.Stop(), Times.Once);
|
||||
hostMock.Verify(h => h.Start(), Times.Never);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,29 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
|
|||
loggerMock = new Mock<ILogger>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustCreateCopyOfOperationQueue()
|
||||
{
|
||||
var operationA = new Mock<IOperation>();
|
||||
var operationB = new Mock<IOperation>();
|
||||
var operationC = new Mock<IOperation>();
|
||||
var operations = new Queue<IOperation>();
|
||||
|
||||
operations.Enqueue(operationA.Object);
|
||||
operations.Enqueue(operationB.Object);
|
||||
operations.Enqueue(operationC.Object);
|
||||
|
||||
var sut = new OperationSequence(loggerMock.Object, operations);
|
||||
|
||||
operations.Clear();
|
||||
|
||||
sut.TryPerform();
|
||||
|
||||
operationA.Verify(o => o.Perform(), Times.Once);
|
||||
operationB.Verify(o => o.Perform(), Times.Once);
|
||||
operationC.Verify(o => o.Perform(), Times.Once);
|
||||
}
|
||||
|
||||
#region Perform Tests
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Behaviour\Operations\CommunicationOperationTests.cs" />
|
||||
<Compile Include="Behaviour\Operations\I18nOperationTests.cs" />
|
||||
<Compile Include="Behaviour\Operations\OperationSequenceTests.cs" />
|
||||
<Compile Include="I18n\TextTests.cs" />
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 SafeExamBrowser.Contracts.Behaviour.Operations;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour.Operations
|
||||
{
|
||||
public class CommunicationOperation : IOperation
|
||||
{
|
||||
private ICommunicationHost host;
|
||||
private ILogger logger;
|
||||
|
||||
public bool Abort { get; private set; }
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
||||
public CommunicationOperation(ICommunicationHost host, ILogger logger)
|
||||
{
|
||||
this.host = host;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("Starting communication host...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartCommunicationHost);
|
||||
|
||||
host.Start();
|
||||
}
|
||||
|
||||
public void Repeat()
|
||||
{
|
||||
if (!host.IsRunning)
|
||||
{
|
||||
logger.Info("Restarting communication host...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_RestartCommunicationHost);
|
||||
|
||||
host.Stop();
|
||||
host.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
logger.Info("Stopping communication host...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopCommunicationHost);
|
||||
|
||||
host.Stop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
|
|||
|
||||
if (!success)
|
||||
{
|
||||
Revert();
|
||||
Revert(true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -74,8 +74,8 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
|
|||
|
||||
try
|
||||
{
|
||||
Initialize();
|
||||
success = Revert(false);
|
||||
Initialize(true);
|
||||
success = Revert();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -154,7 +154,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
|
|||
return true;
|
||||
}
|
||||
|
||||
private bool Revert(bool regress = true)
|
||||
private bool Revert(bool regress = false)
|
||||
{
|
||||
var success = true;
|
||||
|
||||
|
|
91
SafeExamBrowser.Core/Communication/BaseHost.cs
Normal file
91
SafeExamBrowser.Core/Communication/BaseHost.cs
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 System.ServiceModel;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication
|
||||
{
|
||||
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
|
||||
public abstract class BaseHost : ICommunication, ICommunicationHost
|
||||
{
|
||||
private string address;
|
||||
private ILogger logger;
|
||||
private ServiceHost host;
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
get { return host?.State == CommunicationState.Opened; }
|
||||
}
|
||||
|
||||
public BaseHost(string address, ILogger logger)
|
||||
{
|
||||
this.address = address;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public abstract IConnectResponse Connect(Guid? token = null);
|
||||
public abstract void Disconnect(IMessage message);
|
||||
public abstract IResponse Send(IMessage message);
|
||||
|
||||
public void Start()
|
||||
{
|
||||
host = new ServiceHost(this);
|
||||
host.AddServiceEndpoint(typeof(ICommunication), new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), address);
|
||||
host.Closed += Host_Closed;
|
||||
host.Closing += Host_Closing;
|
||||
host.Faulted += Host_Faulted;
|
||||
host.Opened += Host_Opened;
|
||||
host.Opening += Host_Opening;
|
||||
host.UnknownMessageReceived += Host_UnknownMessageReceived;
|
||||
host.Open();
|
||||
|
||||
logger.Debug($"Successfully started communication host for endpoint '{address}'.");
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
host?.Close();
|
||||
logger.Debug($"Terminated communication host for endpoint '{address}'.");
|
||||
}
|
||||
|
||||
private void Host_Closed(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host has been closed.");
|
||||
}
|
||||
|
||||
private void Host_Closing(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host is closing...");
|
||||
}
|
||||
|
||||
private void Host_Faulted(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host has faulted!");
|
||||
}
|
||||
|
||||
private void Host_Opened(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host has been opened.");
|
||||
}
|
||||
|
||||
private void Host_Opening(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host is opening...");
|
||||
}
|
||||
|
||||
private void Host_UnknownMessageReceived(object sender, UnknownMessageReceivedEventArgs e)
|
||||
{
|
||||
logger.Debug($"Communication host has received an unknown message: {e?.Message}.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
protected Guid? CommunicationToken { get; private set; }
|
||||
protected ILogger Logger { get; private set; }
|
||||
|
||||
public BaseProxy(ILogger logger, string address)
|
||||
public BaseProxy(string address, ILogger logger)
|
||||
{
|
||||
this.address = address;
|
||||
this.Logger = logger;
|
||||
|
@ -34,9 +34,11 @@ namespace SafeExamBrowser.Core.Communication
|
|||
var endpoint = new EndpointAddress(address);
|
||||
|
||||
channel = ChannelFactory<ICommunication>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), endpoint);
|
||||
(channel as ICommunicationObject).Closed += CommunicationHostProxy_Closed;
|
||||
(channel as ICommunicationObject).Closing += CommunicationHostProxy_Closing;
|
||||
(channel as ICommunicationObject).Faulted += CommunicationHostProxy_Faulted;
|
||||
(channel as ICommunicationObject).Closed += BaseProxy_Closed;
|
||||
(channel as ICommunicationObject).Closing += BaseProxy_Closing;
|
||||
(channel as ICommunicationObject).Faulted += BaseProxy_Faulted;
|
||||
(channel as ICommunicationObject).Opened += BaseProxy_Opened;
|
||||
(channel as ICommunicationObject).Opening += BaseProxy_Opening;
|
||||
|
||||
var response = channel.Connect(token);
|
||||
|
||||
|
@ -84,21 +86,31 @@ namespace SafeExamBrowser.Core.Communication
|
|||
return channel != null && (channel as ICommunicationObject).State == CommunicationState.Opened;
|
||||
}
|
||||
|
||||
private void CommunicationHostProxy_Closed(object sender, EventArgs e)
|
||||
private void BaseProxy_Closed(object sender, EventArgs e)
|
||||
{
|
||||
Logger.Debug("Communication channel has been closed.");
|
||||
}
|
||||
|
||||
private void CommunicationHostProxy_Closing(object sender, EventArgs e)
|
||||
private void BaseProxy_Closing(object sender, EventArgs e)
|
||||
{
|
||||
Logger.Debug("Communication channel is closing.");
|
||||
Logger.Debug("Communication channel is closing...");
|
||||
}
|
||||
|
||||
private void CommunicationHostProxy_Faulted(object sender, EventArgs e)
|
||||
private void BaseProxy_Faulted(object sender, EventArgs e)
|
||||
{
|
||||
Logger.Debug("Communication channel has faulted!");
|
||||
}
|
||||
|
||||
private void BaseProxy_Opened(object sender, EventArgs e)
|
||||
{
|
||||
Logger.Debug("Communication channel has been opened.");
|
||||
}
|
||||
|
||||
private void BaseProxy_Opening(object sender, EventArgs e)
|
||||
{
|
||||
Logger.Debug("Communication channel is opening...");
|
||||
}
|
||||
|
||||
private string GetChannelState()
|
||||
{
|
||||
return channel == null ? "null" : $"in state '{(channel as ICommunicationObject).State}'";
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
{
|
||||
public bool Ignore { private get; set; }
|
||||
|
||||
public ServiceProxy(ILogger logger, string address) : base(logger, address)
|
||||
public ServiceProxy(string address, ILogger logger) : base(address, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,9 @@
|
|||
<Entry key="ProgressIndicator_InitializeWorkingArea">
|
||||
Initializing working area
|
||||
</Entry>
|
||||
<Entry key="ProgressIndicator_RestartCommunicationHost">
|
||||
Restarting communication host
|
||||
</Entry>
|
||||
<Entry key="ProgressIndicator_RestoreWorkingArea">
|
||||
Restoring working area
|
||||
</Entry>
|
||||
|
@ -69,6 +72,9 @@
|
|||
<Entry key="ProgressIndicator_ShutdownProcedure">
|
||||
Initiating shutdown procedure
|
||||
</Entry>
|
||||
<Entry key="ProgressIndicator_StartCommunicationHost">
|
||||
Starting communication host
|
||||
</Entry>
|
||||
<Entry key="ProgressIndicator_StartEventHandling">
|
||||
Starting event handling
|
||||
</Entry>
|
||||
|
@ -78,6 +84,9 @@
|
|||
<Entry key="ProgressIndicator_StartMouseInterception">
|
||||
Starting mouse interception
|
||||
</Entry>
|
||||
<Entry key="ProgressIndicator_StopCommunicationHost">
|
||||
Stopping communication host
|
||||
</Entry>
|
||||
<Entry key="ProgressIndicator_StopEventHandling">
|
||||
Stopping event handling
|
||||
</Entry>
|
||||
|
|
|
@ -55,9 +55,11 @@
|
|||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Behaviour\Operations\CommunicationOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\I18nOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\OperationSequence.cs" />
|
||||
<Compile Include="Communication\BaseProxy.cs" />
|
||||
<Compile Include="Communication\BaseHost.cs" />
|
||||
<Compile Include="Communication\Messages\Message.cs" />
|
||||
<Compile Include="Communication\ServiceProxy.cs" />
|
||||
<Compile Include="Logging\DefaultLogFormatter.cs" />
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
private Mock<ILogger> logger;
|
||||
private Mock<IRuntimeInfo> info;
|
||||
private Mock<ISettingsRepository> repository;
|
||||
private Mock<IConfigurationRepository> repository;
|
||||
private Mock<ISettings> settings;
|
||||
private Mock<IText> text;
|
||||
private Mock<IUserInterfaceFactory> uiFactory;
|
||||
|
@ -35,7 +35,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
logger = new Mock<ILogger>();
|
||||
info = new Mock<IRuntimeInfo>();
|
||||
repository = new Mock<ISettingsRepository>();
|
||||
repository = new Mock<IConfigurationRepository>();
|
||||
settings = new Mock<ISettings>();
|
||||
text = new Mock<IText>();
|
||||
uiFactory = new Mock<IUserInterfaceFactory>();
|
||||
|
@ -43,24 +43,24 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
info.SetupGet(i => i.AppDataFolder).Returns(@"C:\Not\Really\AppData");
|
||||
info.SetupGet(i => i.DefaultSettingsFileName).Returns("SettingsDummy.txt");
|
||||
info.SetupGet(i => i.ProgramDataFolder).Returns(@"C:\Not\Really\ProgramData");
|
||||
repository.Setup(r => r.Load(It.IsAny<Uri>())).Returns(settings.Object);
|
||||
repository.Setup(r => r.LoadDefaults()).Returns(settings.Object);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>())).Returns(settings.Object);
|
||||
repository.Setup(r => r.LoadDefaultSettings()).Returns(settings.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailWithoutCommandLineArgs()
|
||||
{
|
||||
repository.Setup(r => r.LoadDefaults());
|
||||
repository.Setup(r => r.LoadDefaultSettings());
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new string[] { });
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, new string[] { });
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadDefaults(), Times.Exactly(2));
|
||||
repository.Verify(r => r.LoadDefaultSettings(), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -68,7 +68,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
var path = @"an/invalid\path.'*%yolo/()";
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path });
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path });
|
||||
|
||||
sut.Perform();
|
||||
}
|
||||
|
@ -82,11 +82,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
||||
info.SetupGet(r => r.AppDataFolder).Returns(location);
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", path });
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", path });
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(path)))), Times.Once);
|
||||
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(path)))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -97,11 +97,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
||||
info.SetupGet(r => r.AppDataFolder).Returns($@"{location}\WRONG");
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -111,21 +111,21 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
|
||||
info.SetupGet(r => r.AppDataFolder).Returns(location);
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
repository.Verify(r => r.LoadSettings(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustFallbackToDefaultsAsLastPrio()
|
||||
{
|
||||
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
repository.Verify(r => r.LoadDefaults(), Times.Once);
|
||||
repository.Verify(r => r.LoadDefaultSettings(), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -136,7 +136,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
||||
uiFactory.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.Yes);
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
|
@ -148,7 +148,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
uiFactory.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.No);
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
|
||||
sut = new ConfigurationOperation(repository.Object, logger.Object, info.Object, text.Object, uiFactory.Object, null);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public class KioskModeOperationTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void Todo()
|
||||
public void TODO()
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ using System;
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
@ -23,7 +24,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
private Mock<ILogger> logger;
|
||||
private Mock<IServiceProxy> service;
|
||||
private Mock<ISettingsRepository> settings;
|
||||
private Mock<IConfigurationRepository> configuration;
|
||||
private Mock<IProgressIndicator> progressIndicator;
|
||||
private Mock<IText> text;
|
||||
private ServiceOperation sut;
|
||||
|
@ -33,23 +34,23 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
logger = new Mock<ILogger>();
|
||||
service = new Mock<IServiceProxy>();
|
||||
settings = new Mock<ISettingsRepository>();
|
||||
configuration = new Mock<IConfigurationRepository>();
|
||||
progressIndicator = new Mock<IProgressIndicator>();
|
||||
text = new Mock<IText>();
|
||||
|
||||
sut = new ServiceOperation(logger.Object, service.Object, settings.Object, text.Object);
|
||||
sut = new ServiceOperation(configuration.Object, logger.Object, service.Object, text.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustConnectToService()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
|
@ -60,22 +61,22 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public void MustNotFailIfServiceNotAvailable()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
}
|
||||
|
@ -84,7 +85,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public void MustAbortIfServiceMandatoryAndNotAvailable()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
|
@ -95,7 +96,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public void MustNotAbortIfServiceOptionalAndNotAvailable()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
|
@ -107,13 +108,13 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public void MustDisconnectWhenReverting()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
@ -126,7 +127,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
service.Setup(s => s.Disconnect()).Throws<Exception>();
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
@ -138,25 +139,25 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public void MustNotDisconnnectIfNotAvailable()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
||||
settings.SetupGet(s => s.Current.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
|
|
@ -19,9 +19,9 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
{
|
||||
internal class ConfigurationOperation : IOperation
|
||||
{
|
||||
private IConfigurationRepository repository;
|
||||
private ILogger logger;
|
||||
private IRuntimeInfo runtimeInfo;
|
||||
private ISettingsRepository repository;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
private string[] commandLineArgs;
|
||||
|
@ -30,16 +30,16 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
||||
public ConfigurationOperation(
|
||||
IConfigurationRepository repository,
|
||||
ILogger logger,
|
||||
IRuntimeInfo runtimeInfo,
|
||||
ISettingsRepository repository,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory,
|
||||
string[] commandLineArgs)
|
||||
{
|
||||
this.repository = repository;
|
||||
this.logger = logger;
|
||||
this.commandLineArgs = commandLineArgs;
|
||||
this.repository = repository;
|
||||
this.runtimeInfo = runtimeInfo;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
|
@ -56,7 +56,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
if (isValidUri)
|
||||
{
|
||||
logger.Info($"Loading configuration from '{uri.AbsolutePath}'...");
|
||||
settings = repository.Load(uri);
|
||||
settings = repository.LoadSettings(uri);
|
||||
|
||||
if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient && UserWantsToAbortStartup())
|
||||
{
|
||||
|
@ -67,7 +67,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
else
|
||||
{
|
||||
logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
||||
settings = repository.LoadDefaults();
|
||||
settings = repository.LoadDefaultSettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Behaviour.Operations;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
@ -17,21 +18,21 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
internal class KioskModeOperation : IOperation
|
||||
{
|
||||
private ILogger logger;
|
||||
private ISettingsRepository settingsRepository;
|
||||
private IConfigurationRepository configuration;
|
||||
private KioskMode kioskMode;
|
||||
|
||||
public bool Abort { get; private set; }
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
||||
public KioskModeOperation(ILogger logger, ISettingsRepository settingsRepository)
|
||||
public KioskModeOperation(ILogger logger, IConfigurationRepository configuration)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.settingsRepository = settingsRepository;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
kioskMode = settingsRepository.Current.KioskMode;
|
||||
kioskMode = configuration.CurrentSettings.KioskMode;
|
||||
|
||||
logger.Info($"Initializing kiosk mode '{kioskMode}'...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeKioskMode);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
using System;
|
||||
using SafeExamBrowser.Contracts.Behaviour.Operations;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
@ -20,19 +21,19 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
{
|
||||
private bool serviceAvailable;
|
||||
private bool serviceMandatory;
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IServiceProxy service;
|
||||
private ISettingsRepository settingsRepository;
|
||||
private IText text;
|
||||
|
||||
public bool Abort { get; private set; }
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
||||
public ServiceOperation(ILogger logger, IServiceProxy service, ISettingsRepository settingsRepository, IText text)
|
||||
public ServiceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy service, IText text)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.service = service;
|
||||
this.logger = logger;
|
||||
this.settingsRepository = settingsRepository;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
@ -43,7 +44,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
|
||||
try
|
||||
{
|
||||
serviceMandatory = settingsRepository.Current.ServicePolicy == ServicePolicy.Mandatory;
|
||||
serviceMandatory = configuration.CurrentSettings.ServicePolicy == ServicePolicy.Mandatory;
|
||||
serviceAvailable = service.Connect();
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -20,36 +20,41 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
{
|
||||
internal class RuntimeController : IRuntimeController
|
||||
{
|
||||
private bool initialized;
|
||||
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IOperationSequence bootstrapSequence;
|
||||
private IOperationSequence sessionSequence;
|
||||
private IRuntimeHost runtimeHost;
|
||||
private IRuntimeInfo runtimeInfo;
|
||||
private IRuntimeWindow runtimeWindow;
|
||||
private IServiceProxy serviceProxy;
|
||||
private ISettingsRepository settingsRepository;
|
||||
private ISplashScreen splashScreen;
|
||||
private Action terminationCallback;
|
||||
private Action shutdown;
|
||||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
||||
|
||||
public RuntimeController(
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IOperationSequence bootstrapSequence,
|
||||
IOperationSequence sessionSequence,
|
||||
IRuntimeHost runtimeHost,
|
||||
IRuntimeInfo runtimeInfo,
|
||||
IServiceProxy serviceProxy,
|
||||
ISettingsRepository settingsRepository,
|
||||
Action terminationCallback,
|
||||
Action shutdown,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.logger = logger;
|
||||
this.bootstrapSequence = bootstrapSequence;
|
||||
this.sessionSequence = sessionSequence;
|
||||
this.runtimeHost = runtimeHost;
|
||||
this.runtimeInfo = runtimeInfo;
|
||||
this.serviceProxy = serviceProxy;
|
||||
this.settingsRepository = settingsRepository;
|
||||
this.terminationCallback = terminationCallback;
|
||||
this.shutdown = shutdown;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
}
|
||||
|
@ -58,19 +63,16 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
{
|
||||
logger.Info("--- Initiating startup procedure ---");
|
||||
|
||||
runtimeWindow = uiFactory.CreateRuntimeWindow(runtimeInfo, text);
|
||||
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text);
|
||||
splashScreen.Show();
|
||||
|
||||
bootstrapSequence.ProgressIndicator = splashScreen;
|
||||
|
||||
var success = bootstrapSequence.TryPerform();
|
||||
initialized = bootstrapSequence.TryPerform();
|
||||
|
||||
System.Threading.Thread.Sleep(5000);
|
||||
|
||||
if (success)
|
||||
if (initialized)
|
||||
{
|
||||
runtimeWindow = uiFactory.CreateRuntimeWindow(runtimeInfo, text);
|
||||
|
||||
logger.Info("--- Application successfully initialized! ---");
|
||||
logger.Log(string.Empty);
|
||||
logger.Subscribe(runtimeWindow);
|
||||
|
@ -85,17 +87,19 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
logger.Log(string.Empty);
|
||||
}
|
||||
|
||||
return success;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
StopSession();
|
||||
// TODO: Necessary here? Move to App.cs as private "started" flag if not...
|
||||
if (!initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// - Disconnect from service
|
||||
// - Terminate runtime communication host
|
||||
// - Revert kiosk mode (or do that when stopping session?)
|
||||
// TODO: Only if session is running!
|
||||
StopSession();
|
||||
|
||||
logger.Unsubscribe(runtimeWindow);
|
||||
runtimeWindow?.Close();
|
||||
|
@ -104,6 +108,10 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
logger.Log(string.Empty);
|
||||
logger.Info("--- Initiating shutdown procedure ---");
|
||||
|
||||
// TODO:
|
||||
// - Disconnect from service
|
||||
// - Terminate runtime communication host
|
||||
// - Revert kiosk mode (or do that when stopping session?)
|
||||
var success = bootstrapSequence.TryRevert();
|
||||
|
||||
if (success)
|
||||
|
@ -137,25 +145,28 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
|
||||
if (success)
|
||||
{
|
||||
|
||||
// TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
// TODO: Remove!
|
||||
System.Threading.Thread.Sleep(5000);
|
||||
|
||||
runtimeWindow.HideProgressBar();
|
||||
runtimeWindow.UpdateText(TextKey.RuntimeWindow_ApplicationRunning);
|
||||
|
||||
if (settingsRepository.Current.KioskMode == KioskMode.DisableExplorerShell)
|
||||
if (configuration.CurrentSettings.KioskMode == KioskMode.DisableExplorerShell)
|
||||
{
|
||||
runtimeWindow.Hide();
|
||||
}
|
||||
|
||||
// TODO: Remove!
|
||||
System.Threading.Thread.Sleep(5000);
|
||||
|
||||
terminationCallback.Invoke();
|
||||
shutdown.Invoke();
|
||||
}
|
||||
|
||||
private void StopSession()
|
||||
|
@ -163,12 +174,26 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
logger.Info("Stopping current session...");
|
||||
runtimeWindow.Show();
|
||||
runtimeWindow.BringToForeground();
|
||||
runtimeWindow.ShowProgressBar();
|
||||
runtimeWindow.UpdateText(TextKey.RuntimeWindow_StopSession, true);
|
||||
|
||||
// TODO:
|
||||
// - Terminate client (or does it terminate itself?)
|
||||
// - Finalize session with service
|
||||
// - Stop event handling and close session
|
||||
var success = sessionSequence.TryRevert();
|
||||
|
||||
// TODO: Remove!
|
||||
System.Threading.Thread.Sleep(5000);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
42
SafeExamBrowser.Runtime/Communication/RuntimeHost.cs
Normal file
42
SafeExamBrowser.Runtime/Communication/RuntimeHost.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Communication;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Communication
|
||||
{
|
||||
internal class RuntimeHost : BaseHost, IRuntimeHost
|
||||
{
|
||||
public RuntimeHost(string address, ILogger logger) : base(address, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IConnectResponse Connect(Guid? token = null)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Disconnect(IMessage message)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IResponse Send(IMessage message)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,11 +8,8 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using SafeExamBrowser.Configuration;
|
||||
using SafeExamBrowser.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Behaviour.Operations;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
@ -23,6 +20,7 @@ using SafeExamBrowser.Core.I18n;
|
|||
using SafeExamBrowser.Core.Logging;
|
||||
using SafeExamBrowser.Runtime.Behaviour;
|
||||
using SafeExamBrowser.Runtime.Behaviour.Operations;
|
||||
using SafeExamBrowser.Runtime.Communication;
|
||||
using SafeExamBrowser.UserInterface.Classic;
|
||||
using SafeExamBrowser.WindowsApi;
|
||||
|
||||
|
@ -31,7 +29,7 @@ namespace SafeExamBrowser.Runtime
|
|||
internal class CompositionRoot
|
||||
{
|
||||
private ILogger logger;
|
||||
private RuntimeInfo runtimeInfo;
|
||||
private IRuntimeInfo runtimeInfo;
|
||||
private ISystemInfo systemInfo;
|
||||
|
||||
internal IRuntimeController RuntimeController { get; private set; }
|
||||
|
@ -42,30 +40,30 @@ namespace SafeExamBrowser.Runtime
|
|||
var bootstrapOperations = new Queue<IOperation>();
|
||||
var sessionOperations = new Queue<IOperation>();
|
||||
var nativeMethods = new NativeMethods();
|
||||
var settingsRepository = new SettingsRepository();
|
||||
var configuration = new ConfigurationRepository();
|
||||
var uiFactory = new UserInterfaceFactory();
|
||||
|
||||
logger = new Logger();
|
||||
runtimeInfo = new RuntimeInfo();
|
||||
runtimeInfo = configuration.RuntimeInfo;
|
||||
systemInfo = new SystemInfo();
|
||||
|
||||
InitializeRuntimeInfo();
|
||||
InitializeLogging();
|
||||
|
||||
var text = new Text(logger);
|
||||
var serviceProxy = new ServiceProxy(new ModuleLogger(logger, typeof(ServiceProxy)), "net.pipe://localhost/safeexambrowser/service");
|
||||
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, new ModuleLogger(logger, typeof(RuntimeHost)));
|
||||
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy)));
|
||||
|
||||
bootstrapOperations.Enqueue(new I18nOperation(logger, text));
|
||||
// TODO: RuntimeHostOperation here (is IBootstrapOperation -> only performed once per runtime!)
|
||||
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
|
||||
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(logger, runtimeInfo, settingsRepository, text, uiFactory, args));
|
||||
sessionOperations.Enqueue(new ServiceOperation(logger, serviceProxy, settingsRepository, text));
|
||||
sessionOperations.Enqueue(new KioskModeOperation(logger, settingsRepository));
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeInfo, text, uiFactory, args));
|
||||
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
|
||||
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
|
||||
|
||||
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||
var boostrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
||||
|
||||
RuntimeController = new RuntimeController(logger, bootstrapSequence, sessionSequence, runtimeInfo, serviceProxy, settingsRepository, Application.Current.Shutdown, text, uiFactory);
|
||||
RuntimeController = new RuntimeController(configuration, logger, boostrapSequence, sessionSequence, runtimeHost, runtimeInfo, serviceProxy, Application.Current.Shutdown, text, uiFactory);
|
||||
}
|
||||
|
||||
internal void LogStartupInformation()
|
||||
|
@ -84,28 +82,7 @@ namespace SafeExamBrowser.Runtime
|
|||
|
||||
internal void LogShutdownInformation()
|
||||
{
|
||||
logger?.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
}
|
||||
|
||||
private void InitializeRuntimeInfo()
|
||||
{
|
||||
var appDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(SafeExamBrowser));
|
||||
var executable = Assembly.GetEntryAssembly();
|
||||
var startTime = DateTime.Now;
|
||||
var logFolder = Path.Combine(appDataFolder, "Logs");
|
||||
var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
|
||||
|
||||
runtimeInfo.ApplicationStartTime = startTime;
|
||||
runtimeInfo.AppDataFolder = appDataFolder;
|
||||
runtimeInfo.BrowserCachePath = Path.Combine(appDataFolder, "Cache");
|
||||
runtimeInfo.BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt");
|
||||
runtimeInfo.ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt");
|
||||
runtimeInfo.DefaultSettingsFileName = "SebClientSettings.seb";
|
||||
runtimeInfo.ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;
|
||||
runtimeInfo.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser));
|
||||
runtimeInfo.ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title;
|
||||
runtimeInfo.ProgramVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
runtimeInfo.RuntimeLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.txt");
|
||||
logger?.Log($"# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
}
|
||||
|
||||
private void InitializeLogging()
|
||||
|
|
|
@ -90,6 +90,7 @@
|
|||
<Compile Include="Behaviour\Operations\ConfigurationOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\KioskModeOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\ServiceOperation.cs" />
|
||||
<Compile Include="Communication\RuntimeHost.cs" />
|
||||
<Compile Include="CompositionRoot.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
|
|
Loading…
Reference in a new issue