/* * 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 Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Contracts.Behaviour.OperationModel; using SafeExamBrowser.Contracts.Communication.Data; using SafeExamBrowser.Contracts.Communication.Hosts; using SafeExamBrowser.Contracts.Communication.Proxies; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.WindowsApi; using SafeExamBrowser.Runtime.Behaviour.Operations; namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations { [TestClass] public class ClientOperationTests { private Action clientReady; private Action terminated; private Mock configuration; private Mock proxy; private Mock logger; private Mock process; private Mock processFactory; private Mock proxyFactory; private Mock runtimeHost; private RuntimeInfo runtimeInfo; private Mock session; private ClientOperation sut; [TestInitialize] public void Initialize() { configuration = new Mock(); clientReady = new Action(() => runtimeHost.Raise(h => h.ClientReady += null)); logger = new Mock(); process = new Mock(); processFactory = new Mock(); proxy = new Mock(); proxyFactory = new Mock(); runtimeHost = new Mock(); runtimeInfo = new RuntimeInfo(); session = new Mock(); terminated = new Action(() => { runtimeHost.Raise(h => h.ClientDisconnected += null); process.Raise(p => p.Terminated += null, 0); }); configuration.SetupGet(c => c.CurrentSession).Returns(session.Object); configuration.SetupGet(c => c.RuntimeInfo).Returns(runtimeInfo); proxyFactory.Setup(f => f.CreateClientProxy(It.IsAny())).Returns(proxy.Object); sut = new ClientOperation(configuration.Object, logger.Object, processFactory.Object, proxyFactory.Object, runtimeHost.Object, 0); } [TestMethod] public void MustStartClientWhenPerforming() { var result = default(OperationResult); var response = new AuthenticationResponse { ProcessId = 1234 }; process.SetupGet(p => p.Id).Returns(response.ProcessId); processFactory.Setup(f => f.StartNew(It.IsAny(), It.IsAny())).Returns(process.Object).Callback(clientReady); proxy.Setup(p => p.RequestAuthentication()).Returns(response); proxy.Setup(p => p.Connect(It.IsAny(), true)).Returns(true); result = sut.Perform(); session.VerifySet(s => s.ClientProcess = process.Object, Times.Once); session.VerifySet(s => s.ClientProxy = proxy.Object, Times.Once); Assert.AreEqual(OperationResult.Success, result); } [TestMethod] public void MustStartClientWhenRepeating() { var result = default(OperationResult); var response = new AuthenticationResponse { ProcessId = 1234 }; process.SetupGet(p => p.Id).Returns(response.ProcessId); processFactory.Setup(f => f.StartNew(It.IsAny(), It.IsAny())).Returns(process.Object).Callback(clientReady); proxy.Setup(p => p.RequestAuthentication()).Returns(response); proxy.Setup(p => p.Connect(It.IsAny(), true)).Returns(true); result = sut.Repeat(); session.VerifySet(s => s.ClientProcess = process.Object, Times.Once); session.VerifySet(s => s.ClientProxy = proxy.Object, Times.Once); Assert.AreEqual(OperationResult.Success, result); } [TestMethod] public void MustFailStartupIfClientNotStartedWithinTimeout() { var result = default(OperationResult); result = sut.Perform(); session.VerifySet(s => s.ClientProcess = process.Object, Times.Never); session.VerifySet(s => s.ClientProxy = proxy.Object, Times.Never); Assert.AreEqual(OperationResult.Failed, result); } [TestMethod] public void MustFailStartupIfConnectionToClientNotEstablished() { var result = default(OperationResult); processFactory.Setup(f => f.StartNew(It.IsAny(), It.IsAny())).Returns(process.Object).Callback(clientReady); proxy.Setup(p => p.Connect(It.IsAny(), true)).Returns(false); result = sut.Perform(); session.VerifySet(s => s.ClientProcess = process.Object, Times.Never); session.VerifySet(s => s.ClientProxy = proxy.Object, Times.Never); Assert.AreEqual(OperationResult.Failed, result); } [TestMethod] public void MustFailStartupIfAuthenticationNotSuccessful() { var result = default(OperationResult); var response = new AuthenticationResponse { ProcessId = -1 }; process.SetupGet(p => p.Id).Returns(1234); processFactory.Setup(f => f.StartNew(It.IsAny(), It.IsAny())).Returns(process.Object).Callback(clientReady); proxy.Setup(p => p.RequestAuthentication()).Returns(response); proxy.Setup(p => p.Connect(It.IsAny(), true)).Returns(true); result = sut.Perform(); session.VerifySet(s => s.ClientProcess = process.Object, Times.Never); session.VerifySet(s => s.ClientProxy = proxy.Object, Times.Never); Assert.AreEqual(OperationResult.Failed, result); } [TestMethod] public void MustStopClientWhenReverting() { proxy.Setup(p => p.Disconnect()).Callback(terminated); PerformNormally(); sut.Revert(); proxy.Verify(p => p.InitiateShutdown(), Times.Once); proxy.Verify(p => p.Disconnect(), Times.Once); process.Verify(p => p.Kill(), Times.Never); session.VerifySet(s => s.ClientProcess = null, Times.Once); session.VerifySet(s => s.ClientProxy = null, Times.Once); } [TestMethod] public void MustKillClientIfStoppingFailed() { process.Setup(p => p.Kill()).Callback(() => process.SetupGet(p => p.HasTerminated).Returns(true)); PerformNormally(); sut.Revert(); process.Verify(p => p.Kill(), Times.AtLeastOnce); session.VerifySet(s => s.ClientProcess = null, Times.Once); session.VerifySet(s => s.ClientProxy = null, Times.Once); } [TestMethod] public void MustAttemptToKillFiveTimesThenAbort() { PerformNormally(); sut.Revert(); process.Verify(p => p.Kill(), Times.Exactly(5)); session.VerifySet(s => s.ClientProcess = null, Times.Never); session.VerifySet(s => s.ClientProxy = null, Times.Never); } [TestMethod] public void MustNotStopClientIfAlreadyTerminated() { process.SetupGet(p => p.HasTerminated).Returns(true); sut.Revert(); proxy.Verify(p => p.InitiateShutdown(), Times.Never); proxy.Verify(p => p.Disconnect(), Times.Never); process.Verify(p => p.Kill(), Times.Never); session.VerifySet(s => s.ClientProcess = null, Times.Never); session.VerifySet(s => s.ClientProxy = null, Times.Never); } private void PerformNormally() { var response = new AuthenticationResponse { ProcessId = 1234 }; process.SetupGet(p => p.Id).Returns(response.ProcessId); processFactory.Setup(f => f.StartNew(It.IsAny(), It.IsAny())).Returns(process.Object).Callback(clientReady); proxy.Setup(p => p.RequestAuthentication()).Returns(response); proxy.Setup(p => p.Connect(It.IsAny(), true)).Returns(true); sut.Perform(); } } }