Extended unit tests for client component.

This commit is contained in:
Damian Büchel 2021-07-22 14:21:06 +02:00
parent da2c709360
commit 66c28bd826
6 changed files with 361 additions and 12 deletions

View file

@ -28,6 +28,8 @@ using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Monitoring.Contracts.Applications; using SafeExamBrowser.Monitoring.Contracts.Applications;
using SafeExamBrowser.Monitoring.Contracts.Display; using SafeExamBrowser.Monitoring.Contracts.Display;
using SafeExamBrowser.Monitoring.Contracts.System; using SafeExamBrowser.Monitoring.Contracts.System;
using SafeExamBrowser.Server.Contracts;
using SafeExamBrowser.Server.Contracts.Data;
using SafeExamBrowser.Settings; using SafeExamBrowser.Settings;
using SafeExamBrowser.Settings.Monitoring; using SafeExamBrowser.Settings.Monitoring;
using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts;
@ -57,6 +59,7 @@ namespace SafeExamBrowser.Client.UnitTests
private Mock<IMessageBox> messageBox; private Mock<IMessageBox> messageBox;
private Mock<IOperationSequence> operationSequence; private Mock<IOperationSequence> operationSequence;
private Mock<IRuntimeProxy> runtimeProxy; private Mock<IRuntimeProxy> runtimeProxy;
private Mock<IServerProxy> server;
private Guid sessionId; private Guid sessionId;
private AppSettings settings; private AppSettings settings;
private Mock<Action> shutdown; private Mock<Action> shutdown;
@ -85,6 +88,7 @@ namespace SafeExamBrowser.Client.UnitTests
messageBox = new Mock<IMessageBox>(); messageBox = new Mock<IMessageBox>();
operationSequence = new Mock<IOperationSequence>(); operationSequence = new Mock<IOperationSequence>();
runtimeProxy = new Mock<IRuntimeProxy>(); runtimeProxy = new Mock<IRuntimeProxy>();
server = new Mock<IServerProxy>();
sessionId = Guid.NewGuid(); sessionId = Guid.NewGuid();
settings = new AppSettings(); settings = new AppSettings();
shutdown = new Mock<Action>(); shutdown = new Mock<Action>();
@ -120,6 +124,7 @@ namespace SafeExamBrowser.Client.UnitTests
context.AppConfig = appConfig; context.AppConfig = appConfig;
context.Browser = browser.Object; context.Browser = browser.Object;
context.ClientHost = clientHost.Object; context.ClientHost = clientHost.Object;
context.Server = server.Object;
context.SessionId = sessionId; context.SessionId = sessionId;
context.Settings = settings; context.Settings = settings;
} }
@ -192,6 +197,25 @@ namespace SafeExamBrowser.Client.UnitTests
Assert.IsTrue(boundsTaskbar == 4); Assert.IsTrue(boundsTaskbar == 4);
} }
[TestMethod]
public void ApplicationMonitor_MustPermitApplicationIfChosenByUserAfterFailedTermination()
{
var lockScreen = new Mock<ILockScreen>();
var result = new LockScreenResult();
lockScreen.Setup(l => l.WaitForResult()).Returns(result);
runtimeProxy.Setup(p => p.RequestShutdown()).Returns(new CommunicationResult(true));
uiFactory
.Setup(f => f.CreateLockScreen(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IEnumerable<LockScreenOption>>()))
.Returns(lockScreen.Object)
.Callback<string, string, IEnumerable<LockScreenOption>>((m, t, o) => result.OptionId = o.First().Id);
sut.TryStart();
applicationMonitor.Raise(m => m.TerminationFailed += null, new List<RunningApplication>());
runtimeProxy.Verify(p => p.RequestShutdown(), Times.Never);
}
[TestMethod] [TestMethod]
public void ApplicationMonitor_MustRequestShutdownIfChosenByUserAfterFailedTermination() public void ApplicationMonitor_MustRequestShutdownIfChosenByUserAfterFailedTermination()
{ {
@ -288,6 +312,21 @@ namespace SafeExamBrowser.Client.UnitTests
It.Is<IWindow>(w => w == lockScreen.Object)), Times.Exactly(attempt - 1)); It.Is<IWindow>(w => w == lockScreen.Object)), Times.Exactly(attempt - 1));
} }
[TestMethod]
public void Browser_MustHandleSessionIdentifierDetection()
{
var counter = 0;
var identifier = "abc123";
settings.SessionMode = SessionMode.Server;
server.Setup(s => s.SendSessionIdentifier(It.IsAny<string>())).Returns(() => new ServerResponse(++counter == 3));
sut.TryStart();
browser.Raise(b => b.SessionIdentifierDetected += null, identifier);
server.Verify(s => s.SendSessionIdentifier(It.Is<string>(id => id == identifier)), Times.Exactly(3));
}
[TestMethod] [TestMethod]
public void Browser_MustTerminateIfRequested() public void Browser_MustTerminateIfRequested()
{ {
@ -299,6 +338,26 @@ namespace SafeExamBrowser.Client.UnitTests
runtimeProxy.Verify(p => p.RequestShutdown(), Times.Once); runtimeProxy.Verify(p => p.RequestShutdown(), Times.Once);
} }
[TestMethod]
public void Communication_MustCorrectlyHandleExamSelection()
{
var args = new ExamSelectionRequestEventArgs
{
Exams = new List<(string id, string lms, string name, string url)> { ("", "", "", "") },
RequestId = Guid.NewGuid()
};
var dialog = new Mock<IExamSelectionDialog>();
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(new ExamSelectionDialogResult { Success = true });
uiFactory.Setup(f => f.CreateExamSelectionDialog(It.IsAny<IEnumerable<Exam>>())).Returns(dialog.Object);
sut.TryStart();
clientHost.Raise(c => c.ExamSelectionRequested += null, args);
runtimeProxy.Verify(p => p.SubmitExamSelectionResult(It.Is<Guid>(g => g == args.RequestId), true, null), Times.Once);
uiFactory.Verify(f => f.CreateExamSelectionDialog(It.IsAny<IEnumerable<Exam>>()), Times.Once);
}
[TestMethod] [TestMethod]
public void Communication_MustCorrectlyHandleMessageBoxRequest() public void Communication_MustCorrectlyHandleMessageBoxRequest()
{ {
@ -377,6 +436,22 @@ namespace SafeExamBrowser.Client.UnitTests
It.IsAny<IWindow>()), Times.Once); It.IsAny<IWindow>()), Times.Once);
} }
[TestMethod]
public void Communication_MustCorrectlyHandleServerCommunicationFailure()
{
var args = new ServerFailureActionRequestEventArgs { RequestId = Guid.NewGuid() };
var dialog = new Mock<IServerFailureDialog>();
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(new ServerFailureDialogResult());
uiFactory.Setup(f => f.CreateServerFailureDialog(It.IsAny<string>(), It.IsAny<bool>())).Returns(dialog.Object);
sut.TryStart();
clientHost.Raise(c => c.ServerFailureActionRequested += null, args);
runtimeProxy.Verify(r => r.SubmitServerFailureActionResult(It.Is<Guid>(g => g == args.RequestId), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Once);
uiFactory.Verify(f => f.CreateServerFailureDialog(It.IsAny<string>(), It.IsAny<bool>()), Times.Once);
}
[TestMethod] [TestMethod]
public void Communication_MustCorrectlyInitiateShutdown() public void Communication_MustCorrectlyInitiateShutdown()
{ {
@ -463,6 +538,21 @@ namespace SafeExamBrowser.Client.UnitTests
Assert.IsTrue(boundsTaskbar == 3); Assert.IsTrue(boundsTaskbar == 3);
} }
[TestMethod]
public void DisplayMonitor_MustShowLockScreenOnDisplayChange()
{
var lockScreen = new Mock<ILockScreen>();
displayMonitor.Setup(m => m.ValidateConfiguration(It.IsAny<DisplaySettings>())).Returns(new ValidationResult { IsAllowed = false });
lockScreen.Setup(l => l.WaitForResult()).Returns(new LockScreenResult());
uiFactory.Setup(f => f.CreateLockScreen(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IEnumerable<LockScreenOption>>())).Returns(lockScreen.Object);
sut.TryStart();
displayMonitor.Raise(d => d.DisplayChanged += null);
lockScreen.Verify(l => l.Show(), Times.Once);
}
[TestMethod] [TestMethod]
public void Operations_MustAskForAutomaticApplicationTermination() public void Operations_MustAskForAutomaticApplicationTermination()
{ {
@ -785,6 +875,17 @@ namespace SafeExamBrowser.Client.UnitTests
It.IsAny<IWindow>()), Times.Once); It.IsAny<IWindow>()), Times.Once);
} }
[TestMethod]
public void Server_MustInitiateShutdownOnEvent()
{
runtimeProxy.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true));
sut.TryStart();
server.Raise(s => s.TerminationRequested += null);
runtimeProxy.Verify(p => p.RequestShutdown(), Times.Once);
}
[TestMethod] [TestMethod]
public void Shutdown_MustAskUserToConfirm() public void Shutdown_MustAskUserToConfirm()
{ {
@ -1103,6 +1204,59 @@ namespace SafeExamBrowser.Client.UnitTests
browser.Verify(b => b.Start(), Times.Never); browser.Verify(b => b.Start(), Times.Never);
} }
[TestMethod]
public void SystemMonitor_MustShowLockScreenOnSessionSwitch()
{
var lockScreen = new Mock<ILockScreen>();
settings.Service.IgnoreService = true;
lockScreen.Setup(l => l.WaitForResult()).Returns(new LockScreenResult());
uiFactory.Setup(f => f.CreateLockScreen(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IEnumerable<LockScreenOption>>())).Returns(lockScreen.Object);
sut.TryStart();
systemMonitor.Raise(m => m.SessionSwitched += null);
lockScreen.Verify(l => l.Show(), Times.Once);
}
[TestMethod]
public void SystemMonitor_MustTerminateIfRequestedByUser()
{
var lockScreen = new Mock<ILockScreen>();
var result = new LockScreenResult();
settings.Service.IgnoreService = true;
lockScreen.Setup(l => l.WaitForResult()).Returns(result);
runtimeProxy.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true));
uiFactory
.Setup(f => f.CreateLockScreen(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IEnumerable<LockScreenOption>>()))
.Callback(new Action<string, string, IEnumerable<LockScreenOption>>((message, title, options) => result.OptionId = options.Last().Id))
.Returns(lockScreen.Object);
sut.TryStart();
systemMonitor.Raise(m => m.SessionSwitched += null);
lockScreen.Verify(l => l.Show(), Times.Once);
runtimeProxy.Verify(p => p.RequestShutdown(), Times.Once);
}
[TestMethod]
public void SystemMonitor_MustDoNothingIfSessionSwitchAllowed()
{
var lockScreen = new Mock<ILockScreen>();
settings.Service.IgnoreService = false;
settings.Service.DisableUserLock = false;
settings.Service.DisableUserSwitch = false;
lockScreen.Setup(l => l.WaitForResult()).Returns(new LockScreenResult());
uiFactory.Setup(f => f.CreateLockScreen(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IEnumerable<LockScreenOption>>())).Returns(lockScreen.Object);
sut.TryStart();
systemMonitor.Raise(m => m.SessionSwitched += null);
lockScreen.Verify(l => l.Show(), Times.Never);
}
[TestMethod] [TestMethod]
public void TerminationActivator_MustCorrectlyInitiateShutdown() public void TerminationActivator_MustCorrectlyInitiateShutdown()
{ {

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2021 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.Client.Operations;
using SafeExamBrowser.Core.Contracts.Notifications;
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Proctoring.Contracts;
using SafeExamBrowser.Settings;
using SafeExamBrowser.Settings.Proctoring;
using SafeExamBrowser.UserInterface.Contracts;
using SafeExamBrowser.UserInterface.Contracts.Shell;
namespace SafeExamBrowser.Client.UnitTests.Operations
{
[TestClass]
public class ProctoringOperationTests
{
private Mock<IActionCenter> actionCenter;
private ClientContext context;
private Mock<IProctoringController> controller;
private Mock<ILogger> logger;
private Mock<INotification> notification;
private AppSettings settings;
private Mock<ITaskbar> taskbar;
private Mock<IUserInterfaceFactory> uiFactory;
private ProctoringOperation sut;
[TestInitialize]
public void Initialize()
{
actionCenter = new Mock<IActionCenter>();
context = new ClientContext();
controller = new Mock<IProctoringController>();
logger = new Mock<ILogger>();
notification = new Mock<INotification>();
settings = new AppSettings();
taskbar = new Mock<ITaskbar>();
uiFactory = new Mock<IUserInterfaceFactory>();
context.Settings = settings;
sut = new ProctoringOperation(actionCenter.Object, context, controller.Object, logger.Object, notification.Object, taskbar.Object, uiFactory.Object);
}
[TestMethod]
public void Perform_MustInitializeProctoringCorrectly()
{
settings.Proctoring.Enabled = true;
settings.Proctoring.ShowTaskbarNotification = true;
Assert.AreEqual(OperationResult.Success, sut.Perform());
actionCenter.Verify(a => a.AddNotificationControl(It.IsAny<INotificationControl>()), Times.Once);
controller.Verify(c => c.Initialize(It.Is<ProctoringSettings>(s => s == settings.Proctoring)));
notification.VerifyNoOtherCalls();
taskbar.Verify(t => t.AddNotificationControl(It.IsAny<INotificationControl>()), Times.Once);
uiFactory.Verify(u => u.CreateNotificationControl(It.Is<INotification>(n => n == notification.Object), Location.ActionCenter), Times.Once);
uiFactory.Verify(u => u.CreateNotificationControl(It.Is<INotification>(n => n == notification.Object), Location.Taskbar), Times.Once);
}
[TestMethod]
public void Perform_MustDoNothingIfNotEnabled()
{
settings.Proctoring.Enabled = false;
Assert.AreEqual(OperationResult.Success, sut.Perform());
actionCenter.VerifyNoOtherCalls();
controller.VerifyNoOtherCalls();
notification.VerifyNoOtherCalls();
taskbar.VerifyNoOtherCalls();
uiFactory.VerifyNoOtherCalls();
}
[TestMethod]
public void Revert_MustFinalizeProctoringCorrectly()
{
settings.Proctoring.Enabled = true;
Assert.AreEqual(OperationResult.Success, sut.Revert());
actionCenter.VerifyNoOtherCalls();
controller.Verify(c => c.Terminate(), Times.Once);
notification.Verify(n => n.Terminate(), Times.Once);
taskbar.VerifyNoOtherCalls();
uiFactory.VerifyNoOtherCalls();
}
[TestMethod]
public void Revert_MustDoNothingIfNotEnabled()
{
settings.Proctoring.Enabled = false;
Assert.AreEqual(OperationResult.Success, sut.Revert());
actionCenter.VerifyNoOtherCalls();
controller.VerifyNoOtherCalls();
notification.VerifyNoOtherCalls();
taskbar.VerifyNoOtherCalls();
uiFactory.VerifyNoOtherCalls();
}
}
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2021 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.Client.Operations;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Server.Contracts;
using SafeExamBrowser.Settings;
using SafeExamBrowser.Settings.Server;
namespace SafeExamBrowser.Client.UnitTests.Operations
{
[TestClass]
public class ServerOperationTests
{
private AppConfig appConfig;
private ClientContext context;
private Mock<ILogger> logger;
private Mock<IServerProxy> server;
private AppSettings settings;
private ServerOperation sut;
[TestInitialize]
public void Initialize()
{
appConfig = new AppConfig();
context = new ClientContext();
logger = new Mock<ILogger>();
server = new Mock<IServerProxy>();
settings = new AppSettings();
context.AppConfig = appConfig;
context.Settings = settings;
sut = new ServerOperation(context, logger.Object, server.Object);
}
[TestMethod]
public void Perform_MustInitializeCorrectly()
{
settings.SessionMode = SessionMode.Server;
Assert.AreEqual(OperationResult.Success, sut.Perform());
server.Verify(s => s.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<ServerSettings>()), Times.Once);
server.Verify(s => s.StartConnectivity(), Times.Once);
}
[TestMethod]
public void Perform_MustDoNothingIfNotActive()
{
settings.SessionMode = SessionMode.Normal;
Assert.AreEqual(OperationResult.Success, sut.Perform());
server.VerifyNoOtherCalls();
}
[TestMethod]
public void Revert_MustFinalizeCorrectly()
{
settings.SessionMode = SessionMode.Server;
Assert.AreEqual(OperationResult.Success, sut.Revert());
server.Verify(s => s.StopConnectivity(), Times.Once);
}
[TestMethod]
public void Revert_MustDoNothingIfNotActive()
{
settings.SessionMode = SessionMode.Normal;
Assert.AreEqual(OperationResult.Success, sut.Revert());
server.VerifyNoOtherCalls();
}
}
}

View file

@ -99,7 +99,9 @@
<Compile Include="Operations\DisplayMonitorOperationTests.cs" /> <Compile Include="Operations\DisplayMonitorOperationTests.cs" />
<Compile Include="Operations\KeyboardInterceptorOperationTests.cs" /> <Compile Include="Operations\KeyboardInterceptorOperationTests.cs" />
<Compile Include="Operations\MouseInterceptorOperationTests.cs" /> <Compile Include="Operations\MouseInterceptorOperationTests.cs" />
<Compile Include="Operations\ProctoringOperationTests.cs" />
<Compile Include="Operations\RuntimeConnectionOperationTests.cs" /> <Compile Include="Operations\RuntimeConnectionOperationTests.cs" />
<Compile Include="Operations\ServerOperationTests.cs" />
<Compile Include="Operations\ShellOperationTests.cs" /> <Compile Include="Operations\ShellOperationTests.cs" />
<Compile Include="Communication\ClientHostTests.cs" /> <Compile Include="Communication\ClientHostTests.cs" />
<Compile Include="Notifications\AboutNotificationControllerTests.cs" /> <Compile Include="Notifications\AboutNotificationControllerTests.cs" />
@ -161,6 +163,10 @@
<Project>{6d563a30-366d-4c35-815b-2c9e6872278b}</Project> <Project>{6d563a30-366d-4c35-815b-2c9e6872278b}</Project>
<Name>SafeExamBrowser.Monitoring.Contracts</Name> <Name>SafeExamBrowser.Monitoring.Contracts</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\SafeExamBrowser.Proctoring.Contracts\SafeExamBrowser.Proctoring.Contracts.csproj">
<Project>{8e52bd1c-0540-4f16-b181-6665d43f7a7b}</Project>
<Name>SafeExamBrowser.Proctoring.Contracts</Name>
</ProjectReference>
<ProjectReference Include="..\SafeExamBrowser.Server.Contracts\SafeExamBrowser.Server.Contracts.csproj"> <ProjectReference Include="..\SafeExamBrowser.Server.Contracts\SafeExamBrowser.Server.Contracts.csproj">
<Project>{db701e6f-bddc-4cec-b662-335a9dc11809}</Project> <Project>{db701e6f-bddc-4cec-b662-335a9dc11809}</Project>
<Name>SafeExamBrowser.Server.Contracts</Name> <Name>SafeExamBrowser.Server.Contracts</Name>

View file

@ -258,7 +258,7 @@ namespace SafeExamBrowser.Client
private IOperation BuildServerOperation() private IOperation BuildServerOperation()
{ {
var server = new ServerProxy(context.AppConfig, ModuleLogger(nameof(ServerProxy)), powerSupply, wirelessAdapter); var server = new ServerProxy(context.AppConfig, ModuleLogger(nameof(ServerProxy)), powerSupply, wirelessAdapter);
var operation = new ServerOperation(actionCenter, context, logger, server, taskbar); var operation = new ServerOperation(context, logger, server);
context.Server = server; context.Server = server;

View file

@ -12,31 +12,21 @@ using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Server.Contracts; using SafeExamBrowser.Server.Contracts;
using SafeExamBrowser.Settings; using SafeExamBrowser.Settings;
using SafeExamBrowser.UserInterface.Contracts.Shell;
namespace SafeExamBrowser.Client.Operations namespace SafeExamBrowser.Client.Operations
{ {
internal class ServerOperation : ClientOperation internal class ServerOperation : ClientOperation
{ {
private readonly IActionCenter actionCenter;
private readonly ILogger logger; private readonly ILogger logger;
private readonly IServerProxy server; private readonly IServerProxy server;
private readonly ITaskbar taskbar;
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } } public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
public override event StatusChangedEventHandler StatusChanged; public override event StatusChangedEventHandler StatusChanged;
public ServerOperation( public ServerOperation(ClientContext context, ILogger logger, IServerProxy server) : base(context)
IActionCenter actionCenter,
ClientContext context,
ILogger logger,
IServerProxy server,
ITaskbar taskbar) : base(context)
{ {
this.actionCenter = actionCenter;
this.logger = logger; this.logger = logger;
this.server = server; this.server = server;
this.taskbar = taskbar;
} }
public override OperationResult Perform() public override OperationResult Perform()