From 66c28bd8269175a9903cc297fecd57ca844ea735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20B=C3=BCchel?= Date: Thu, 22 Jul 2021 14:21:06 +0200 Subject: [PATCH] Extended unit tests for client component. --- .../ClientControllerTests.cs | 154 ++++++++++++++++++ .../Operations/ProctoringOperationTests.cs | 111 +++++++++++++ .../Operations/ServerOperationTests.cs | 88 ++++++++++ .../SafeExamBrowser.Client.UnitTests.csproj | 6 + SafeExamBrowser.Client/CompositionRoot.cs | 2 +- .../Operations/ServerOperation.cs | 12 +- 6 files changed, 361 insertions(+), 12 deletions(-) create mode 100644 SafeExamBrowser.Client.UnitTests/Operations/ProctoringOperationTests.cs create mode 100644 SafeExamBrowser.Client.UnitTests/Operations/ServerOperationTests.cs diff --git a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs index a5e212dc..a0472d0b 100644 --- a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs +++ b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs @@ -28,6 +28,8 @@ using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Monitoring.Contracts.Applications; using SafeExamBrowser.Monitoring.Contracts.Display; using SafeExamBrowser.Monitoring.Contracts.System; +using SafeExamBrowser.Server.Contracts; +using SafeExamBrowser.Server.Contracts.Data; using SafeExamBrowser.Settings; using SafeExamBrowser.Settings.Monitoring; using SafeExamBrowser.UserInterface.Contracts; @@ -57,6 +59,7 @@ namespace SafeExamBrowser.Client.UnitTests private Mock messageBox; private Mock operationSequence; private Mock runtimeProxy; + private Mock server; private Guid sessionId; private AppSettings settings; private Mock shutdown; @@ -85,6 +88,7 @@ namespace SafeExamBrowser.Client.UnitTests messageBox = new Mock(); operationSequence = new Mock(); runtimeProxy = new Mock(); + server = new Mock(); sessionId = Guid.NewGuid(); settings = new AppSettings(); shutdown = new Mock(); @@ -120,6 +124,7 @@ namespace SafeExamBrowser.Client.UnitTests context.AppConfig = appConfig; context.Browser = browser.Object; context.ClientHost = clientHost.Object; + context.Server = server.Object; context.SessionId = sessionId; context.Settings = settings; } @@ -192,6 +197,25 @@ namespace SafeExamBrowser.Client.UnitTests Assert.IsTrue(boundsTaskbar == 4); } + [TestMethod] + public void ApplicationMonitor_MustPermitApplicationIfChosenByUserAfterFailedTermination() + { + var lockScreen = new Mock(); + 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(), It.IsAny(), It.IsAny>())) + .Returns(lockScreen.Object) + .Callback>((m, t, o) => result.OptionId = o.First().Id); + + sut.TryStart(); + applicationMonitor.Raise(m => m.TerminationFailed += null, new List()); + + runtimeProxy.Verify(p => p.RequestShutdown(), Times.Never); + } + [TestMethod] public void ApplicationMonitor_MustRequestShutdownIfChosenByUserAfterFailedTermination() { @@ -288,6 +312,21 @@ namespace SafeExamBrowser.Client.UnitTests It.Is(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())).Returns(() => new ServerResponse(++counter == 3)); + + sut.TryStart(); + browser.Raise(b => b.SessionIdentifierDetected += null, identifier); + + server.Verify(s => s.SendSessionIdentifier(It.Is(id => id == identifier)), Times.Exactly(3)); + } + [TestMethod] public void Browser_MustTerminateIfRequested() { @@ -299,6 +338,26 @@ namespace SafeExamBrowser.Client.UnitTests 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(); + + dialog.Setup(d => d.Show(It.IsAny())).Returns(new ExamSelectionDialogResult { Success = true }); + uiFactory.Setup(f => f.CreateExamSelectionDialog(It.IsAny>())).Returns(dialog.Object); + + sut.TryStart(); + clientHost.Raise(c => c.ExamSelectionRequested += null, args); + + runtimeProxy.Verify(p => p.SubmitExamSelectionResult(It.Is(g => g == args.RequestId), true, null), Times.Once); + uiFactory.Verify(f => f.CreateExamSelectionDialog(It.IsAny>()), Times.Once); + } + [TestMethod] public void Communication_MustCorrectlyHandleMessageBoxRequest() { @@ -377,6 +436,22 @@ namespace SafeExamBrowser.Client.UnitTests It.IsAny()), Times.Once); } + [TestMethod] + public void Communication_MustCorrectlyHandleServerCommunicationFailure() + { + var args = new ServerFailureActionRequestEventArgs { RequestId = Guid.NewGuid() }; + var dialog = new Mock(); + + dialog.Setup(d => d.Show(It.IsAny())).Returns(new ServerFailureDialogResult()); + uiFactory.Setup(f => f.CreateServerFailureDialog(It.IsAny(), It.IsAny())).Returns(dialog.Object); + + sut.TryStart(); + clientHost.Raise(c => c.ServerFailureActionRequested += null, args); + + runtimeProxy.Verify(r => r.SubmitServerFailureActionResult(It.Is(g => g == args.RequestId), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + uiFactory.Verify(f => f.CreateServerFailureDialog(It.IsAny(), It.IsAny()), Times.Once); + } + [TestMethod] public void Communication_MustCorrectlyInitiateShutdown() { @@ -463,6 +538,21 @@ namespace SafeExamBrowser.Client.UnitTests Assert.IsTrue(boundsTaskbar == 3); } + [TestMethod] + public void DisplayMonitor_MustShowLockScreenOnDisplayChange() + { + var lockScreen = new Mock(); + + displayMonitor.Setup(m => m.ValidateConfiguration(It.IsAny())).Returns(new ValidationResult { IsAllowed = false }); + lockScreen.Setup(l => l.WaitForResult()).Returns(new LockScreenResult()); + uiFactory.Setup(f => f.CreateLockScreen(It.IsAny(), It.IsAny(), It.IsAny>())).Returns(lockScreen.Object); + + sut.TryStart(); + displayMonitor.Raise(d => d.DisplayChanged += null); + + lockScreen.Verify(l => l.Show(), Times.Once); + } + [TestMethod] public void Operations_MustAskForAutomaticApplicationTermination() { @@ -785,6 +875,17 @@ namespace SafeExamBrowser.Client.UnitTests It.IsAny()), 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] public void Shutdown_MustAskUserToConfirm() { @@ -1103,6 +1204,59 @@ namespace SafeExamBrowser.Client.UnitTests browser.Verify(b => b.Start(), Times.Never); } + [TestMethod] + public void SystemMonitor_MustShowLockScreenOnSessionSwitch() + { + var lockScreen = new Mock(); + + settings.Service.IgnoreService = true; + lockScreen.Setup(l => l.WaitForResult()).Returns(new LockScreenResult()); + uiFactory.Setup(f => f.CreateLockScreen(It.IsAny(), It.IsAny(), It.IsAny>())).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(); + 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(), It.IsAny(), It.IsAny>())) + .Callback(new Action>((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(); + + 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(), It.IsAny(), It.IsAny>())).Returns(lockScreen.Object); + + sut.TryStart(); + systemMonitor.Raise(m => m.SessionSwitched += null); + + lockScreen.Verify(l => l.Show(), Times.Never); + } + [TestMethod] public void TerminationActivator_MustCorrectlyInitiateShutdown() { diff --git a/SafeExamBrowser.Client.UnitTests/Operations/ProctoringOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ProctoringOperationTests.cs new file mode 100644 index 00000000..2ad40ae4 --- /dev/null +++ b/SafeExamBrowser.Client.UnitTests/Operations/ProctoringOperationTests.cs @@ -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 actionCenter; + private ClientContext context; + private Mock controller; + private Mock logger; + private Mock notification; + private AppSettings settings; + private Mock taskbar; + private Mock uiFactory; + + private ProctoringOperation sut; + + [TestInitialize] + public void Initialize() + { + actionCenter = new Mock(); + context = new ClientContext(); + controller = new Mock(); + logger = new Mock(); + notification = new Mock(); + settings = new AppSettings(); + taskbar = new Mock(); + uiFactory = new Mock(); + + 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()), Times.Once); + controller.Verify(c => c.Initialize(It.Is(s => s == settings.Proctoring))); + notification.VerifyNoOtherCalls(); + taskbar.Verify(t => t.AddNotificationControl(It.IsAny()), Times.Once); + uiFactory.Verify(u => u.CreateNotificationControl(It.Is(n => n == notification.Object), Location.ActionCenter), Times.Once); + uiFactory.Verify(u => u.CreateNotificationControl(It.Is(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(); + } + } +} diff --git a/SafeExamBrowser.Client.UnitTests/Operations/ServerOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ServerOperationTests.cs new file mode 100644 index 00000000..e6f37a77 --- /dev/null +++ b/SafeExamBrowser.Client.UnitTests/Operations/ServerOperationTests.cs @@ -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 logger; + private Mock server; + private AppSettings settings; + + private ServerOperation sut; + + [TestInitialize] + public void Initialize() + { + appConfig = new AppConfig(); + context = new ClientContext(); + logger = new Mock(); + server = new Mock(); + 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(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), 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(); + } + } +} diff --git a/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj b/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj index 0687fea5..e07f4618 100644 --- a/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj +++ b/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj @@ -99,7 +99,9 @@ + + @@ -161,6 +163,10 @@ {6d563a30-366d-4c35-815b-2c9e6872278b} SafeExamBrowser.Monitoring.Contracts + + {8e52bd1c-0540-4f16-b181-6665d43f7a7b} + SafeExamBrowser.Proctoring.Contracts + {db701e6f-bddc-4cec-b662-335a9dc11809} SafeExamBrowser.Server.Contracts diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index d9790ccd..415131c7 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -258,7 +258,7 @@ namespace SafeExamBrowser.Client private IOperation BuildServerOperation() { 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; diff --git a/SafeExamBrowser.Client/Operations/ServerOperation.cs b/SafeExamBrowser.Client/Operations/ServerOperation.cs index 573e6421..a296dc4c 100644 --- a/SafeExamBrowser.Client/Operations/ServerOperation.cs +++ b/SafeExamBrowser.Client/Operations/ServerOperation.cs @@ -12,31 +12,21 @@ using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Server.Contracts; using SafeExamBrowser.Settings; -using SafeExamBrowser.UserInterface.Contracts.Shell; namespace SafeExamBrowser.Client.Operations { internal class ServerOperation : ClientOperation { - private readonly IActionCenter actionCenter; private readonly ILogger logger; private readonly IServerProxy server; - private readonly ITaskbar taskbar; public override event ActionRequiredEventHandler ActionRequired { add { } remove { } } public override event StatusChangedEventHandler StatusChanged; - public ServerOperation( - IActionCenter actionCenter, - ClientContext context, - ILogger logger, - IServerProxy server, - ITaskbar taskbar) : base(context) + public ServerOperation(ClientContext context, ILogger logger, IServerProxy server) : base(context) { - this.actionCenter = actionCenter; this.logger = logger; this.server = server; - this.taskbar = taskbar; } public override OperationResult Perform()