SEBWIN-219: Started implementing the configuration operation.
This commit is contained in:
parent
31d6d544d0
commit
39261f5222
13 changed files with 299 additions and 3 deletions
|
@ -19,7 +19,9 @@ namespace SafeExamBrowser.Configuration
|
|||
public string BrowserCachePath { get; set; }
|
||||
public string BrowserLogFile { 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 RuntimeLogFile { get; set; }
|
||||
|
|
|
@ -37,11 +37,21 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// </summary>
|
||||
string ClientLogFile { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The default file name for application settings.
|
||||
/// </summary>
|
||||
string DefaultSettingsFileName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The copyright information for the application (i.e. the executing assembly).
|
||||
/// </summary>
|
||||
string ProgramCopyright { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The path of the program data folder.
|
||||
/// </summary>
|
||||
string ProgramDataFolder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The program title of the application (i.e. the executing assembly).
|
||||
/// </summary>
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
Notification_LogTooltip,
|
||||
SplashScreen_EmptyClipboard,
|
||||
SplashScreen_InitializeBrowser,
|
||||
SplashScreen_InitializeConfiguration,
|
||||
SplashScreen_InitializeProcessMonitoring,
|
||||
SplashScreen_InitializeTaskbar,
|
||||
SplashScreen_InitializeWindowMonitoring,
|
||||
|
|
|
@ -6,10 +6,17 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Runtime
|
||||
{
|
||||
public interface IRuntimeController
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows to specify the application settings to be used during runtime.
|
||||
/// </summary>
|
||||
ISettings Settings { set; }
|
||||
|
||||
/// <summary>
|
||||
/// Wires up and starts the application event handling.
|
||||
/// </summary>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<Notification_LogTooltip>Application Log</Notification_LogTooltip>
|
||||
<SplashScreen_EmptyClipboard>Emptying clipboard</SplashScreen_EmptyClipboard>
|
||||
<SplashScreen_InitializeBrowser>Initializing browser</SplashScreen_InitializeBrowser>
|
||||
<SplashScreen_InitializeConfiguration>Initializing application configuration</SplashScreen_InitializeConfiguration>
|
||||
<SplashScreen_InitializeProcessMonitoring>Initializing process monitoring</SplashScreen_InitializeProcessMonitoring>
|
||||
<SplashScreen_InitializeTaskbar>Initializing taskbar</SplashScreen_InitializeTaskbar>
|
||||
<SplashScreen_InitializeWindowMonitoring>Initializing window monitoring</SplashScreen_InitializeWindowMonitoring>
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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 Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Runtime;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Runtime.Behaviour.Operations;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||
{
|
||||
[TestClass]
|
||||
public class ConfigurationOperationTests
|
||||
{
|
||||
private Mock<ILogger> logger;
|
||||
private Mock<IRuntimeController> controller;
|
||||
private Mock<IRuntimeInfo> info;
|
||||
private Mock<ISettingsRepository> repository;
|
||||
private Mock<ISplashScreen> splashScreen;
|
||||
|
||||
private ConfigurationOperation sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
logger = new Mock<ILogger>();
|
||||
controller = new Mock<IRuntimeController>();
|
||||
info = new Mock<IRuntimeInfo>();
|
||||
repository = new Mock<ISettingsRepository>();
|
||||
splashScreen = new Mock<ISplashScreen>();
|
||||
|
||||
info.SetupGet(r => r.AppDataFolder).Returns(@"C:\Not\Really\AppData");
|
||||
info.SetupGet(r => r.DefaultSettingsFileName).Returns("SettingsDummy.txt");
|
||||
info.SetupGet(r => r.ProgramDataFolder).Returns(@"C:\Not\Really\ProgramData");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailWithoutCommandLineArgs()
|
||||
{
|
||||
controller.SetupSet(c => c.Settings = It.IsAny<ISettings>());
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, null)
|
||||
{
|
||||
SplashScreen = splashScreen.Object
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, new string[] { })
|
||||
{
|
||||
SplashScreen = splashScreen.Object
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailWithInvalidUri()
|
||||
{
|
||||
var path = @"an/invalid\path.'*%yolo/()";
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, new [] { "blubb.exe", path })
|
||||
{
|
||||
SplashScreen = splashScreen.Object
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustUseCommandLineArgumentAs1stPrio()
|
||||
{
|
||||
var path = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
var location = Path.GetDirectoryName(GetType().Assembly.Location);
|
||||
|
||||
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
||||
info.SetupGet(r => r.AppDataFolder).Returns(location);
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, new[] { "blubb.exe", path })
|
||||
{
|
||||
SplashScreen = splashScreen.Object
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Once);
|
||||
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(path)))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustUseProgramDataAs2ndPrio()
|
||||
{
|
||||
var location = Path.GetDirectoryName(GetType().Assembly.Location);
|
||||
|
||||
info.SetupGet(r => r.ProgramDataFolder).Returns(location);
|
||||
info.SetupGet(r => r.AppDataFolder).Returns($@"{location}\WRONG");
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, null)
|
||||
{
|
||||
SplashScreen = splashScreen.Object
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Once);
|
||||
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustUseAppDataAs3rdPrio()
|
||||
{
|
||||
var location = Path.GetDirectoryName(GetType().Assembly.Location);
|
||||
|
||||
info.SetupGet(r => r.AppDataFolder).Returns(location);
|
||||
|
||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, null)
|
||||
{
|
||||
SplashScreen = splashScreen.Object
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Once);
|
||||
repository.Verify(r => r.Load(It.Is<Uri>(u => u.Equals(new Uri(Path.Combine(location, "SettingsDummy.txt"))))), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustFallbackToDefaultsAsLastPrio()
|
||||
{
|
||||
sut = new ConfigurationOperation(logger.Object, controller.Object, info.Object, repository.Object, null)
|
||||
{
|
||||
SplashScreen = splashScreen.Object
|
||||
};
|
||||
|
||||
sut.Perform();
|
||||
|
||||
controller.VerifySet(c => c.Settings = It.IsAny<ISettings>(), Times.Once);
|
||||
repository.Verify(r => r.LoadDefaults(), Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -80,6 +80,7 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Behaviour\Operations\ConfigurationOperationTests.cs" />
|
||||
<Compile Include="Behaviour\Operations\RuntimeControllerOperationTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
@ -97,6 +98,14 @@
|
|||
<Name>SafeExamBrowser.Runtime</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="SettingsDummy.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WRONG\SettingsDummy.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
|
1
SafeExamBrowser.Runtime.UnitTests/SettingsDummy.txt
Normal file
1
SafeExamBrowser.Runtime.UnitTests/SettingsDummy.txt
Normal file
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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 SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Runtime;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||
{
|
||||
internal class ConfigurationOperation : IOperation
|
||||
{
|
||||
private ILogger logger;
|
||||
private IRuntimeController controller;
|
||||
private IRuntimeInfo runtimeInfo;
|
||||
private ISettingsRepository repository;
|
||||
private string[] commandLineArgs;
|
||||
|
||||
public ISplashScreen SplashScreen { private get; set; }
|
||||
|
||||
public ConfigurationOperation(
|
||||
ILogger logger,
|
||||
IRuntimeController controller,
|
||||
IRuntimeInfo runtimeInfo,
|
||||
ISettingsRepository repository,
|
||||
string[] commandLineArgs)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.controller = controller;
|
||||
this.commandLineArgs = commandLineArgs;
|
||||
this.repository = repository;
|
||||
this.runtimeInfo = runtimeInfo;
|
||||
}
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("Initializing application configuration...");
|
||||
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeConfiguration);
|
||||
|
||||
var isValidUri = TryGetSettingsUri(out Uri uri);
|
||||
|
||||
if (isValidUri)
|
||||
{
|
||||
logger.Info($"Loading configuration from '{uri.AbsolutePath}'...");
|
||||
controller.Settings = repository.Load(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("No valid settings file specified nor found in PROGRAMDATA or APPDATA - loading default settings...");
|
||||
controller.Settings = repository.LoadDefaults();
|
||||
}
|
||||
|
||||
// TODO: Allow user to quit if in Configure Client mode - callback to terminate WPF application?
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
// Nothing to do here...
|
||||
}
|
||||
|
||||
private bool TryGetSettingsUri(out Uri uri)
|
||||
{
|
||||
var path = string.Empty;
|
||||
var isValidUri = false;
|
||||
var programDataSettings = Path.Combine(runtimeInfo.ProgramDataFolder, runtimeInfo.DefaultSettingsFileName);
|
||||
var appDataSettings = Path.Combine(runtimeInfo.AppDataFolder, runtimeInfo.DefaultSettingsFileName);
|
||||
|
||||
uri = null;
|
||||
|
||||
if (commandLineArgs?.Length > 1)
|
||||
{
|
||||
path = commandLineArgs[1];
|
||||
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
||||
logger.Info($"Found command-line argument for settings file: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}.");
|
||||
}
|
||||
|
||||
if (!isValidUri && File.Exists(programDataSettings))
|
||||
{
|
||||
path = programDataSettings;
|
||||
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
||||
logger.Info($"Found settings file in PROGRAMDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}.");
|
||||
}
|
||||
|
||||
if (!isValidUri && File.Exists(appDataSettings))
|
||||
{
|
||||
path = appDataSettings;
|
||||
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri);
|
||||
logger.Info($"Found settings file in APPDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}.");
|
||||
}
|
||||
|
||||
return isValidUri;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Runtime;
|
||||
|
||||
|
@ -15,6 +16,8 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
{
|
||||
private ILogger logger;
|
||||
|
||||
public ISettings Settings { private get; set; }
|
||||
|
||||
public RuntimeController(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using SafeExamBrowser.Configuration;
|
||||
using SafeExamBrowser.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
@ -34,9 +34,11 @@ namespace SafeExamBrowser.Runtime
|
|||
|
||||
internal void BuildObjectGraph()
|
||||
{
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
var logger = new Logger();
|
||||
var nativeMethods = new NativeMethods();
|
||||
var runtimeInfo = new RuntimeInfo();
|
||||
var settingsRepository = new SettingsRepository();
|
||||
var systemInfo = new SystemInfo();
|
||||
var uiFactory = new UserInterfaceFactory();
|
||||
|
||||
|
@ -51,8 +53,7 @@ namespace SafeExamBrowser.Runtime
|
|||
|
||||
StartupOperations = new Queue<IOperation>();
|
||||
StartupOperations.Enqueue(new I18nOperation(logger, text));
|
||||
// TODO
|
||||
//StartupOperations.Enqueue(new ConfigurationOperation());
|
||||
StartupOperations.Enqueue(new ConfigurationOperation(logger, runtimeController, runtimeInfo, settingsRepository, args));
|
||||
//StartupOperations.Enqueue(new KioskModeOperation());
|
||||
StartupOperations.Enqueue(new RuntimeControllerOperation(runtimeController, logger));
|
||||
}
|
||||
|
@ -70,7 +71,9 @@ namespace SafeExamBrowser.Runtime
|
|||
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");
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App.cs" />
|
||||
<Compile Include="Behaviour\Operations\ConfigurationOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\RuntimeControllerOperation.cs" />
|
||||
<Compile Include="CompositionRoot.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
|
|
Loading…
Reference in a new issue