diff --git a/SafeExamBrowser.Client.UnitTests/Operations/ApplicationOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ApplicationOperationTests.cs index 97813441..7a336e5a 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/ApplicationOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/ApplicationOperationTests.cs @@ -6,17 +6,376 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; +using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using SafeExamBrowser.Applications.Contracts; +using SafeExamBrowser.Client.Operations; +using SafeExamBrowser.Client.Operations.Events; +using SafeExamBrowser.Core.Contracts.OperationModel; +using SafeExamBrowser.Core.Contracts.OperationModel.Events; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.Monitoring.Contracts.Applications; +using SafeExamBrowser.Settings; +using SafeExamBrowser.Settings.Applications; namespace SafeExamBrowser.Client.UnitTests.Operations { [TestClass] public class ApplicationOperationTests { - [TestMethod] - public void TODO() + private ClientContext context; + private Mock factory; + private Mock monitor; + private Mock logger; + private Mock text; + + private ApplicationOperation sut; + + [TestInitialize] + public void Initialize() { - Assert.Fail(); + context = new ClientContext(); + factory = new Mock(); + monitor = new Mock(); + logger = new Mock(); + text = new Mock(); + + context.Settings = new AppSettings(); + + sut = new ApplicationOperation(context, factory.Object, monitor.Object, logger.Object, text.Object); + } + + [TestMethod] + public void Perform_MustAbortIfUserDeniesAutoTermination() + { + var initialization = new InitializationResult(); + var args = default(ActionRequiredEventArgs); + + initialization.RunningApplications.Add(new RunningApplication(default(string))); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(initialization); + sut.ActionRequired += (a) => + { + args = a; + + if (a is ApplicationTerminationEventArgs t) + { + t.TerminateProcesses = false; + } + }; + + var result = sut.Perform(); + + monitor.Verify(m => m.Initialize(It.Is(s => s == context.Settings.Applications)), Times.Once); + monitor.VerifyNoOtherCalls(); + + Assert.AreEqual(OperationResult.Aborted, result); + Assert.IsInstanceOfType(args, typeof(ApplicationTerminationEventArgs)); + } + + [TestMethod] + public void Perform_MustAbortIfUserCancelsApplicationLocationSelection() + { + var application = new Mock().Object; + var applicationSettings = new WhitelistApplication { AllowCustomPath = true }; + var args = default(ActionRequiredEventArgs); + + context.Settings.Applications.Whitelist.Add(applicationSettings); + factory.Setup(f => f.TryCreate(It.IsAny(), out application)).Returns(FactoryResult.NotFound); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(new InitializationResult()); + sut.ActionRequired += (a) => + { + args = a; + + if (a is ApplicationNotFoundEventArgs n) + { + n.Success = false; + } + }; + + var result = sut.Perform(); + + factory.Verify(f => f.TryCreate(It.Is(a => a == applicationSettings), out application), Times.Once); + + Assert.AreEqual(OperationResult.Success, result); + Assert.IsInstanceOfType(args, typeof(ApplicationInitializationFailedEventArgs)); + } + + [TestMethod] + public void Perform_MustAllowUserToChooseApplicationLocation() + { + var application = new Mock().Object; + var applicationSettings = new WhitelistApplication { AllowCustomPath = true }; + var args = default(ActionRequiredEventArgs); + var attempt = 0; + var correct = new Random().Next(1, 50); + var factoryResult = new Func(() => ++attempt == correct ? FactoryResult.Success : FactoryResult.NotFound); + + context.Settings.Applications.Whitelist.Add(applicationSettings); + factory.Setup(f => f.TryCreate(It.IsAny(), out application)).Returns(factoryResult); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(new InitializationResult()); + sut.ActionRequired += (a) => + { + args = a; + + if (a is ApplicationNotFoundEventArgs n) + { + n.Success = true; + } + }; + + var result = sut.Perform(); + + factory.Verify(f => f.TryCreate(It.Is(a => a == applicationSettings), out application), Times.Exactly(correct)); + + Assert.AreEqual(OperationResult.Success, result); + Assert.IsInstanceOfType(args, typeof(ApplicationNotFoundEventArgs)); + } + + [TestMethod] + public void Perform_MustDenyApplicationLocationSelection() + { + var application = new Mock().Object; + var applicationSettings = new WhitelistApplication { AllowCustomPath = false }; + var args = default(ActionRequiredEventArgs); + + context.Settings.Applications.Whitelist.Add(applicationSettings); + factory.Setup(f => f.TryCreate(It.IsAny(), out application)).Returns(FactoryResult.NotFound); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(new InitializationResult()); + sut.ActionRequired += (a) => + { + args = a; + + if (a is ApplicationNotFoundEventArgs) + { + Assert.Fail(); + } + }; + + var result = sut.Perform(); + + factory.Verify(f => f.TryCreate(It.Is(a => a == applicationSettings), out application), Times.Once); + + Assert.AreEqual(OperationResult.Success, result); + Assert.IsInstanceOfType(args, typeof(ApplicationInitializationFailedEventArgs)); + } + + [TestMethod] + public void Perform_MustFailIfAutoTerminationFails() + { + var initialization = new InitializationResult(); + var args = default(ActionRequiredEventArgs); + + initialization.FailedAutoTerminations.Add(new RunningApplication(default(string))); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(initialization); + sut.ActionRequired += (a) => args = a; + + var result = sut.Perform(); + + monitor.Verify(m => m.Initialize(It.Is(s => s == context.Settings.Applications)), Times.Once); + monitor.VerifyNoOtherCalls(); + + Assert.AreEqual(OperationResult.Failed, result); + Assert.IsInstanceOfType(args, typeof(ApplicationTerminationFailedEventArgs)); + } + + [TestMethod] + public void Perform_MustFailIfTerminationFails() + { + var application = new RunningApplication(default(string)); + var initialization = new InitializationResult(); + var args = new List(); + + initialization.RunningApplications.Add(application); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(initialization); + monitor.Setup(m => m.TryTerminate(It.IsAny())).Returns(false); + sut.ActionRequired += (a) => + { + args.Add(a); + + if (a is ApplicationTerminationEventArgs t) + { + t.TerminateProcesses = true; + } + }; + + var result = sut.Perform(); + + monitor.Verify(m => m.Initialize(It.Is(s => s == context.Settings.Applications)), Times.Once); + monitor.Verify(m => m.TryTerminate(It.Is(a => a == application)), Times.Once); + + Assert.AreEqual(OperationResult.Failed, result); + Assert.IsInstanceOfType(args[0], typeof(ApplicationTerminationEventArgs)); + Assert.IsInstanceOfType(args[1], typeof(ApplicationTerminationFailedEventArgs)); + } + + [TestMethod] + public void Perform_MustIndicateApplicationInitializationFailure() + { + var application = new Mock().Object; + var applicationSettings = new WhitelistApplication(); + var args = default(ActionRequiredEventArgs); + + context.Settings.Applications.Whitelist.Add(applicationSettings); + factory.Setup(f => f.TryCreate(It.IsAny(), out application)).Returns(FactoryResult.Error); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(new InitializationResult()); + sut.ActionRequired += (a) => args = a; + + var result = sut.Perform(); + + factory.Verify(f => f.TryCreate(It.Is(a => a == applicationSettings), out application), Times.Once); + + Assert.AreEqual(OperationResult.Success, result); + Assert.IsInstanceOfType(args, typeof(ApplicationInitializationFailedEventArgs)); + } + + [TestMethod] + public void Perform_MustInitializeApplications() + { + var application1 = new Mock().Object; + var application2 = new Mock().Object; + var application3 = new Mock().Object; + var application1Settings = new WhitelistApplication(); + var application2Settings = new WhitelistApplication(); + var application3Settings = new WhitelistApplication(); + + context.Settings.Applications.Whitelist.Add(application1Settings); + context.Settings.Applications.Whitelist.Add(application2Settings); + context.Settings.Applications.Whitelist.Add(application3Settings); + factory.Setup(f => f.TryCreate(It.Is(a => a == application1Settings), out application1)).Returns(FactoryResult.Success); + factory.Setup(f => f.TryCreate(It.Is(a => a == application2Settings), out application2)).Returns(FactoryResult.Success); + factory.Setup(f => f.TryCreate(It.Is(a => a == application3Settings), out application3)).Returns(FactoryResult.Success); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(new InitializationResult()); + + var result = sut.Perform(); + + factory.Verify(f => f.TryCreate(It.Is(a => a == application1Settings), out application1), Times.Once); + factory.Verify(f => f.TryCreate(It.Is(a => a == application1Settings), out application2), Times.Once); + factory.Verify(f => f.TryCreate(It.Is(a => a == application1Settings), out application3), Times.Once); + monitor.Verify(m => m.Initialize(It.Is(s => s == context.Settings.Applications)), Times.Once); + monitor.Verify(m => m.TryTerminate(It.IsAny()), Times.Never); + + Assert.AreEqual(OperationResult.Success, result); + } + + [TestMethod] + public void Perform_MustNotStartMonitorWithoutKioskMode() + { + context.Settings.KioskMode = KioskMode.None; + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(new InitializationResult()); + + var result = sut.Perform(); + + monitor.Verify(m => m.Start(), Times.Never); + Assert.AreEqual(OperationResult.Success, result); + } + + [TestMethod] + public void Perform_MustStartMonitorWithKioskMode() + { + context.Settings.KioskMode = KioskMode.CreateNewDesktop; + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(new InitializationResult()); + + var result = sut.Perform(); + + monitor.Verify(m => m.Start(), Times.Once); + Assert.AreEqual(OperationResult.Success, result); + + context.Settings.KioskMode = KioskMode.DisableExplorerShell; + monitor.Reset(); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(new InitializationResult()); + + result = sut.Perform(); + + monitor.Verify(m => m.Start(), Times.Once); + Assert.AreEqual(OperationResult.Success, result); + } + + [TestMethod] + public void Perform_MustTerminateRunningApplications() + { + var application1 = new RunningApplication(default(string)); + var application2 = new RunningApplication(default(string)); + var application3 = new RunningApplication(default(string)); + var initialization = new InitializationResult(); + var args = default(ActionRequiredEventArgs); + + initialization.RunningApplications.Add(application1); + initialization.RunningApplications.Add(application2); + initialization.RunningApplications.Add(application3); + monitor.Setup(m => m.Initialize(It.IsAny())).Returns(initialization); + monitor.Setup(m => m.TryTerminate(It.IsAny())).Returns(true); + sut.ActionRequired += (a) => + { + args = a; + + if (a is ApplicationTerminationEventArgs t) + { + t.TerminateProcesses = true; + } + }; + + var result = sut.Perform(); + + monitor.Verify(m => m.Initialize(It.Is(s => s == context.Settings.Applications)), Times.Once); + monitor.Verify(m => m.TryTerminate(It.Is(a => a == application1)), Times.Once); + monitor.Verify(m => m.TryTerminate(It.Is(a => a == application2)), Times.Once); + monitor.Verify(m => m.TryTerminate(It.Is(a => a == application3)), Times.Once); + + Assert.AreEqual(OperationResult.Success, result); + Assert.IsInstanceOfType(args, typeof(ApplicationTerminationEventArgs)); + } + + [TestMethod] + public void Revert_MustNotStopMonitorWithoutKioskMode() + { + context.Settings.KioskMode = KioskMode.None; + + var result = sut.Revert(); + + monitor.Verify(m => m.Stop(), Times.Never); + Assert.AreEqual(OperationResult.Success, result); + } + + [TestMethod] + public void Revert_MustStopMonitorWithKioskMode() + { + context.Settings.KioskMode = KioskMode.CreateNewDesktop; + + var result = sut.Revert(); + + monitor.Verify(m => m.Stop(), Times.Once); + Assert.AreEqual(OperationResult.Success, result); + + context.Settings.KioskMode = KioskMode.DisableExplorerShell; + monitor.Reset(); + + result = sut.Revert(); + + monitor.Verify(m => m.Stop(), Times.Once); + Assert.AreEqual(OperationResult.Success, result); + } + + [TestMethod] + public void Revert_MustTerminateApplications() + { + var application1 = new Mock(); + var application2 = new Mock(); + var application3 = new Mock(); + + context.Applications.Add(application1.Object); + context.Applications.Add(application2.Object); + context.Applications.Add(application3.Object); + + var result = sut.Revert(); + + application1.Verify(a => a.Terminate(), Times.Once); + application2.Verify(a => a.Terminate(), Times.Once); + application3.Verify(a => a.Terminate(), Times.Once); + + Assert.AreEqual(OperationResult.Success, result); } } }