SEBWIN-219: Extended unit test coverage of runtime operations.
This commit is contained in:
parent
6efa7bed81
commit
eb5fc50fea
10 changed files with 470 additions and 32 deletions
|
@ -7,30 +7,30 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
//using Moq;
|
||||||
using SafeExamBrowser.Client.Behaviour;
|
//using SafeExamBrowser.Client.Behaviour;
|
||||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
//using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
//using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
//using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.Monitoring;
|
//using SafeExamBrowser.Contracts.Monitoring;
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
//using SafeExamBrowser.Contracts.UserInterface;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
//using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Client.UnitTests
|
namespace SafeExamBrowser.Client.UnitTests
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class ClientControllerTests
|
public class ClientControllerTests
|
||||||
{
|
{
|
||||||
private Mock<IDisplayMonitor> displayMonitorMock;
|
//private Mock<IDisplayMonitor> displayMonitorMock;
|
||||||
private Mock<ILogger> loggerMock;
|
//private Mock<ILogger> loggerMock;
|
||||||
private Mock<IProcessMonitor> processMonitorMock;
|
//private Mock<IProcessMonitor> processMonitorMock;
|
||||||
private Mock<IOperationSequence> operationSequenceMock;
|
//private Mock<IOperationSequence> operationSequenceMock;
|
||||||
private Mock<IRuntimeProxy> runtimeProxyMock;
|
//private Mock<IRuntimeProxy> runtimeProxyMock;
|
||||||
private Mock<ITaskbar> taskbarMock;
|
//private Mock<ITaskbar> taskbarMock;
|
||||||
private Mock<IUserInterfaceFactory> uiFactoryMock;
|
//private Mock<IUserInterfaceFactory> uiFactoryMock;
|
||||||
private Mock<IWindowMonitor> windowMonitorMock;
|
//private Mock<IWindowMonitor> windowMonitorMock;
|
||||||
|
|
||||||
private ClientController sut;
|
//private ClientController sut;
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TODO()
|
public void TODO()
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace SafeExamBrowser.Contracts.Behaviour.OperationModel
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that the operation has been aborted due to an expected condition, e.g. as result of a user decision.
|
/// Indicates that the operation has been aborted due to an expected condition, e.g. as result of a user decision.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Aborted,
|
Aborted = 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that the operation has failed due to an invalid or unexpected condition.
|
/// Indicates that the operation has failed due to an invalid or unexpected condition.
|
||||||
|
|
|
@ -0,0 +1,216 @@
|
||||||
|
/*
|
||||||
|
* 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<IConfigurationRepository> configuration;
|
||||||
|
private Mock<IClientProxy> proxy;
|
||||||
|
private Mock<ILogger> logger;
|
||||||
|
private Mock<IProcess> process;
|
||||||
|
private Mock<IProcessFactory> processFactory;
|
||||||
|
private Mock<IProxyFactory> proxyFactory;
|
||||||
|
private Mock<IRuntimeHost> runtimeHost;
|
||||||
|
private RuntimeInfo runtimeInfo;
|
||||||
|
private Mock<ISessionData> session;
|
||||||
|
private ClientOperation sut;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
configuration = new Mock<IConfigurationRepository>();
|
||||||
|
clientReady = new Action(() => runtimeHost.Raise(h => h.ClientReady += null));
|
||||||
|
logger = new Mock<ILogger>();
|
||||||
|
process = new Mock<IProcess>();
|
||||||
|
processFactory = new Mock<IProcessFactory>();
|
||||||
|
proxy = new Mock<IClientProxy>();
|
||||||
|
proxyFactory = new Mock<IProxyFactory>();
|
||||||
|
runtimeHost = new Mock<IRuntimeHost>();
|
||||||
|
runtimeInfo = new RuntimeInfo();
|
||||||
|
session = new Mock<ISessionData>();
|
||||||
|
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<string>())).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<string>(), It.IsAny<string[]>())).Returns(process.Object).Callback(clientReady);
|
||||||
|
proxy.Setup(p => p.RequestAuthentication()).Returns(response);
|
||||||
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), 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<string>(), It.IsAny<string[]>())).Returns(process.Object).Callback(clientReady);
|
||||||
|
proxy.Setup(p => p.RequestAuthentication()).Returns(response);
|
||||||
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), 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<string>(), It.IsAny<string[]>())).Returns(process.Object).Callback(clientReady);
|
||||||
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), 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<string>(), It.IsAny<string[]>())).Returns(process.Object).Callback(clientReady);
|
||||||
|
proxy.Setup(p => p.RequestAuthentication()).Returns(response);
|
||||||
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), 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<string>(), It.IsAny<string[]>())).Returns(process.Object).Callback(clientReady);
|
||||||
|
proxy.Setup(p => p.RequestAuthentication()).Returns(response);
|
||||||
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), true)).Returns(true);
|
||||||
|
|
||||||
|
sut.Perform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* 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.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 ClientTerminationOperationTests
|
||||||
|
{
|
||||||
|
private Action clientReady;
|
||||||
|
private Mock<IConfigurationRepository> configuration;
|
||||||
|
private Mock<IClientProxy> proxy;
|
||||||
|
private Mock<ILogger> logger;
|
||||||
|
private Mock<IProcess> process;
|
||||||
|
private Mock<IProcessFactory> processFactory;
|
||||||
|
private Mock<IProxyFactory> proxyFactory;
|
||||||
|
private Mock<IRuntimeHost> runtimeHost;
|
||||||
|
private RuntimeInfo runtimeInfo;
|
||||||
|
private Mock<ISessionData> session;
|
||||||
|
private ClientTerminationOperation sut;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
configuration = new Mock<IConfigurationRepository>();
|
||||||
|
clientReady = new Action(() => runtimeHost.Raise(h => h.ClientReady += null));
|
||||||
|
logger = new Mock<ILogger>();
|
||||||
|
process = new Mock<IProcess>();
|
||||||
|
processFactory = new Mock<IProcessFactory>();
|
||||||
|
proxy = new Mock<IClientProxy>();
|
||||||
|
proxyFactory = new Mock<IProxyFactory>();
|
||||||
|
runtimeHost = new Mock<IRuntimeHost>();
|
||||||
|
runtimeInfo = new RuntimeInfo();
|
||||||
|
session = new Mock<ISessionData>();
|
||||||
|
|
||||||
|
configuration.SetupGet(c => c.CurrentSession).Returns(session.Object);
|
||||||
|
configuration.SetupGet(c => c.RuntimeInfo).Returns(runtimeInfo);
|
||||||
|
proxyFactory.Setup(f => f.CreateClientProxy(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
|
sut = new ClientTerminationOperation(configuration.Object, logger.Object, processFactory.Object, proxyFactory.Object, runtimeHost.Object, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustDoNothingOnPerform()
|
||||||
|
{
|
||||||
|
sut.Perform();
|
||||||
|
|
||||||
|
processFactory.VerifyNoOtherCalls();
|
||||||
|
proxy.VerifyNoOtherCalls();
|
||||||
|
proxyFactory.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustDoNothingOnRevert()
|
||||||
|
{
|
||||||
|
sut.Revert();
|
||||||
|
|
||||||
|
process.VerifyNoOtherCalls();
|
||||||
|
proxy.VerifyNoOtherCalls();
|
||||||
|
runtimeHost.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustStartClientOnRepeat()
|
||||||
|
{
|
||||||
|
// TODO: Extract static fields from operation -> allows unit testing of this requirement etc.!
|
||||||
|
Assert.Fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,11 +21,13 @@ using SafeExamBrowser.Runtime.Behaviour.Operations;
|
||||||
namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class ServiceConnectionOperationTests
|
public class ServiceOperationTests
|
||||||
{
|
{
|
||||||
private Mock<ILogger> logger;
|
private Mock<ILogger> logger;
|
||||||
private Mock<IServiceProxy> service;
|
private Mock<IServiceProxy> service;
|
||||||
private Mock<IConfigurationRepository> configuration;
|
private Mock<IConfigurationRepository> configuration;
|
||||||
|
private Mock<ISessionData> session;
|
||||||
|
private Settings settings;
|
||||||
private Mock<IProgressIndicator> progressIndicator;
|
private Mock<IProgressIndicator> progressIndicator;
|
||||||
private Mock<IText> text;
|
private Mock<IText> text;
|
||||||
private ServiceOperation sut;
|
private ServiceOperation sut;
|
||||||
|
@ -36,9 +38,14 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
logger = new Mock<ILogger>();
|
logger = new Mock<ILogger>();
|
||||||
service = new Mock<IServiceProxy>();
|
service = new Mock<IServiceProxy>();
|
||||||
configuration = new Mock<IConfigurationRepository>();
|
configuration = new Mock<IConfigurationRepository>();
|
||||||
|
session = new Mock<ISessionData>();
|
||||||
|
settings = new Settings();
|
||||||
progressIndicator = new Mock<IProgressIndicator>();
|
progressIndicator = new Mock<IProgressIndicator>();
|
||||||
text = new Mock<IText>();
|
text = new Mock<IText>();
|
||||||
|
|
||||||
|
configuration.SetupGet(c => c.CurrentSession).Returns(session.Object);
|
||||||
|
configuration.SetupGet(c => c.CurrentSettings).Returns(settings);
|
||||||
|
|
||||||
sut = new ServiceOperation(configuration.Object, logger.Object, service.Object, text.Object);
|
sut = new ServiceOperation(configuration.Object, logger.Object, service.Object, text.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +65,26 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
service.Verify(s => s.Connect(null, true), Times.Exactly(2));
|
service.Verify(s => s.Connect(null, true), Times.Exactly(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustStartSessionIfConnected()
|
||||||
|
{
|
||||||
|
service.Setup(s => s.Connect(null, true)).Returns(true);
|
||||||
|
|
||||||
|
sut.Perform();
|
||||||
|
|
||||||
|
service.Verify(s => s.StartSession(It.IsAny<Guid>(), It.IsAny<Settings>()), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustNotStartSessionIfNotConnected()
|
||||||
|
{
|
||||||
|
service.Setup(s => s.Connect(null, true)).Returns(false);
|
||||||
|
|
||||||
|
sut.Perform();
|
||||||
|
|
||||||
|
service.Verify(s => s.StartSession(It.IsAny<Guid>(), It.IsAny<Settings>()), Times.Never);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustNotFailIfServiceNotAvailable()
|
public void MustNotFailIfServiceNotAvailable()
|
||||||
{
|
{
|
||||||
|
@ -124,6 +151,28 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
service.Verify(s => s.Disconnect(), Times.Exactly(2));
|
service.Verify(s => s.Disconnect(), Times.Exactly(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustStopSessionWhenReverting()
|
||||||
|
{
|
||||||
|
service.Setup(s => s.Connect(null, true)).Returns(true);
|
||||||
|
|
||||||
|
sut.Perform();
|
||||||
|
sut.Revert();
|
||||||
|
|
||||||
|
service.Verify(s => s.StopSession(It.IsAny<Guid>()), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustNotStopSessionWhenRevertingAndNotConnected()
|
||||||
|
{
|
||||||
|
service.Setup(s => s.Connect(null, true)).Returns(false);
|
||||||
|
|
||||||
|
sut.Perform();
|
||||||
|
sut.Revert();
|
||||||
|
|
||||||
|
service.Verify(s => s.StopSession(It.IsAny<Guid>()), Times.Never);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustNotFailWhenDisconnecting()
|
public void MustNotFailWhenDisconnecting()
|
||||||
{
|
{
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* 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.Communication.Hosts;
|
||||||
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Runtime.Behaviour.Operations;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class SessionInitializationOperationTests
|
||||||
|
{
|
||||||
|
private SessionInitializationOperation sut;
|
||||||
|
private Mock<IConfigurationRepository> configuration;
|
||||||
|
private Mock<ILogger> logger;
|
||||||
|
private Mock<IRuntimeHost> runtimeHost;
|
||||||
|
private RuntimeInfo runtimeInfo;
|
||||||
|
private Mock<ISessionData> session;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
configuration = new Mock<IConfigurationRepository>();
|
||||||
|
logger = new Mock<ILogger>();
|
||||||
|
runtimeHost = new Mock<IRuntimeHost>();
|
||||||
|
runtimeInfo = new RuntimeInfo();
|
||||||
|
session = new Mock<ISessionData>();
|
||||||
|
|
||||||
|
configuration.SetupGet(c => c.CurrentSession).Returns(session.Object);
|
||||||
|
configuration.SetupGet(c => c.RuntimeInfo).Returns(runtimeInfo);
|
||||||
|
|
||||||
|
sut = new SessionInitializationOperation(configuration.Object, logger.Object, runtimeHost.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustInitializeConfigurationOnPerform()
|
||||||
|
{
|
||||||
|
var token = Guid.NewGuid();
|
||||||
|
|
||||||
|
session.SetupGet(s => s.StartupToken).Returns(token);
|
||||||
|
|
||||||
|
sut.Perform();
|
||||||
|
|
||||||
|
configuration.Verify(c => c.InitializeSessionConfiguration(), Times.Once);
|
||||||
|
runtimeHost.VerifySet(r => r.StartupToken = token, Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustInitializeConfigurationOnRepeat()
|
||||||
|
{
|
||||||
|
var token = Guid.NewGuid();
|
||||||
|
|
||||||
|
session.SetupGet(s => s.StartupToken).Returns(token);
|
||||||
|
|
||||||
|
sut.Repeat();
|
||||||
|
|
||||||
|
configuration.Verify(c => c.InitializeSessionConfiguration(), Times.Once);
|
||||||
|
runtimeHost.VerifySet(r => r.StartupToken = token, Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustDoNothingOnRevert()
|
||||||
|
{
|
||||||
|
sut.Revert();
|
||||||
|
|
||||||
|
configuration.VerifyNoOtherCalls();
|
||||||
|
logger.VerifyNoOtherCalls();
|
||||||
|
runtimeHost.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,7 +82,10 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Behaviour\Operations\ConfigurationOperationTests.cs" />
|
<Compile Include="Behaviour\Operations\ConfigurationOperationTests.cs" />
|
||||||
<Compile Include="Behaviour\Operations\KioskModeOperationTests.cs" />
|
<Compile Include="Behaviour\Operations\KioskModeOperationTests.cs" />
|
||||||
<Compile Include="Behaviour\Operations\ServiceConnectionOperationTests.cs" />
|
<Compile Include="Behaviour\Operations\ServiceOperationTests.cs" />
|
||||||
|
<Compile Include="Behaviour\Operations\ClientOperationTests.cs" />
|
||||||
|
<Compile Include="Behaviour\Operations\ClientTerminationOperationTests.cs" />
|
||||||
|
<Compile Include="Behaviour\Operations\SessionInitializationOperationTests.cs" />
|
||||||
<Compile Include="Behaviour\RuntimeControllerTests.cs" />
|
<Compile Include="Behaviour\RuntimeControllerTests.cs" />
|
||||||
<Compile Include="Communication\RuntimeHostTests.cs" />
|
<Compile Include="Communication\RuntimeHostTests.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
{
|
{
|
||||||
internal class ClientOperation : IOperation
|
internal class ClientOperation : IOperation
|
||||||
{
|
{
|
||||||
private const int TEN_SECONDS = 10000;
|
private readonly int timeout_ms;
|
||||||
|
|
||||||
protected IConfigurationRepository configuration;
|
protected IConfigurationRepository configuration;
|
||||||
protected ILogger logger;
|
protected ILogger logger;
|
||||||
|
@ -38,13 +38,15 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IProcessFactory processFactory,
|
IProcessFactory processFactory,
|
||||||
IProxyFactory proxyFactory,
|
IProxyFactory proxyFactory,
|
||||||
IRuntimeHost runtimeHost)
|
IRuntimeHost runtimeHost,
|
||||||
|
int timeout_ms)
|
||||||
{
|
{
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.processFactory = processFactory;
|
this.processFactory = processFactory;
|
||||||
this.proxyFactory = proxyFactory;
|
this.proxyFactory = proxyFactory;
|
||||||
this.runtimeHost = runtimeHost;
|
this.runtimeHost = runtimeHost;
|
||||||
|
this.timeout_ms = timeout_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual OperationResult Perform()
|
public virtual OperationResult Perform()
|
||||||
|
@ -84,6 +86,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
var clientReady = false;
|
var clientReady = false;
|
||||||
var clientReadyEvent = new AutoResetEvent(false);
|
var clientReadyEvent = new AutoResetEvent(false);
|
||||||
var clientReadyEventHandler = new CommunicationEventHandler(() => clientReadyEvent.Set());
|
var clientReadyEventHandler = new CommunicationEventHandler(() => clientReadyEvent.Set());
|
||||||
|
|
||||||
var clientExecutable = configuration.RuntimeInfo.ClientExecutablePath;
|
var clientExecutable = configuration.RuntimeInfo.ClientExecutablePath;
|
||||||
var clientLogFile = $"{'"' + configuration.RuntimeInfo.ClientLogFile + '"'}";
|
var clientLogFile = $"{'"' + configuration.RuntimeInfo.ClientLogFile + '"'}";
|
||||||
var hostUri = configuration.RuntimeInfo.RuntimeAddress;
|
var hostUri = configuration.RuntimeInfo.RuntimeAddress;
|
||||||
|
@ -94,12 +97,12 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
ClientProcess = processFactory.StartNew(clientExecutable, clientLogFile, hostUri, token);
|
ClientProcess = processFactory.StartNew(clientExecutable, clientLogFile, hostUri, token);
|
||||||
|
|
||||||
logger.Info("Waiting for client to complete initialization...");
|
logger.Info("Waiting for client to complete initialization...");
|
||||||
clientReady = clientReadyEvent.WaitOne(TEN_SECONDS);
|
clientReady = clientReadyEvent.WaitOne(timeout_ms);
|
||||||
runtimeHost.ClientReady -= clientReadyEventHandler;
|
runtimeHost.ClientReady -= clientReadyEventHandler;
|
||||||
|
|
||||||
if (!clientReady)
|
if (!clientReady)
|
||||||
{
|
{
|
||||||
logger.Error($"Failed to start client within {TEN_SECONDS / 1000} seconds!");
|
logger.Error($"Failed to start client within {timeout_ms / 1000} seconds!");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -155,19 +158,19 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
ClientProxy.Disconnect();
|
ClientProxy.Disconnect();
|
||||||
|
|
||||||
logger.Info("Waiting for client to disconnect from runtime communication host...");
|
logger.Info("Waiting for client to disconnect from runtime communication host...");
|
||||||
disconnected = disconnectedEvent.WaitOne(TEN_SECONDS);
|
disconnected = disconnectedEvent.WaitOne(timeout_ms);
|
||||||
|
|
||||||
if (!disconnected)
|
if (!disconnected)
|
||||||
{
|
{
|
||||||
logger.Error($"Client failed to disconnect within {TEN_SECONDS / 1000} seconds!");
|
logger.Error($"Client failed to disconnect within {timeout_ms / 1000} seconds!");
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("Waiting for client process to terminate...");
|
logger.Info("Waiting for client process to terminate...");
|
||||||
terminated = terminatedEvent.WaitOne(TEN_SECONDS);
|
terminated = terminatedEvent.WaitOne(timeout_ms);
|
||||||
|
|
||||||
if (!terminated)
|
if (!terminated)
|
||||||
{
|
{
|
||||||
logger.Error($"Client failed to terminate within {TEN_SECONDS / 1000} seconds!");
|
logger.Error($"Client failed to terminate within {timeout_ms / 1000} seconds!");
|
||||||
}
|
}
|
||||||
|
|
||||||
runtimeHost.ClientDisconnected -= disconnectedEventHandler;
|
runtimeHost.ClientDisconnected -= disconnectedEventHandler;
|
||||||
|
@ -217,7 +220,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
{
|
{
|
||||||
logger.Warn("Failed to kill client process. Trying again...");
|
logger.Warn("Failed to kill client process. Trying again...");
|
||||||
|
|
||||||
return TryKillClient(attempt++);
|
return TryKillClient(++attempt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,8 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IProcessFactory processFactory,
|
IProcessFactory processFactory,
|
||||||
IProxyFactory proxyFactory,
|
IProxyFactory proxyFactory,
|
||||||
IRuntimeHost runtimeHost) : base(configuration, logger, processFactory, proxyFactory, runtimeHost)
|
IRuntimeHost runtimeHost,
|
||||||
|
int timeout_ms) : base(configuration, logger, processFactory, proxyFactory, runtimeHost, timeout_ms)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
internal void BuildObjectGraph(Action shutdown)
|
internal void BuildObjectGraph(Action shutdown)
|
||||||
{
|
{
|
||||||
|
const int TEN_SECONDS = 10000;
|
||||||
|
|
||||||
var args = Environment.GetCommandLineArgs();
|
var args = Environment.GetCommandLineArgs();
|
||||||
var configuration = new ConfigurationRepository();
|
var configuration = new ConfigurationRepository();
|
||||||
var nativeMethods = new NativeMethods();
|
var nativeMethods = new NativeMethods();
|
||||||
|
@ -64,9 +66,9 @@ namespace SafeExamBrowser.Runtime
|
||||||
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, messageBox, runtimeInfo, text, args));
|
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, messageBox, runtimeInfo, text, args));
|
||||||
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
|
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
|
||||||
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
|
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
|
||||||
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost));
|
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, TEN_SECONDS));
|
||||||
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
|
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
|
||||||
sessionOperations.Enqueue(new ClientOperation(configuration, logger, processFactory, proxyFactory, runtimeHost));
|
sessionOperations.Enqueue(new ClientOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, TEN_SECONDS));
|
||||||
|
|
||||||
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||||
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
||||||
|
|
Loading…
Reference in a new issue