SEBWIN-219: Decoupled proxy object creation from BaseProxy and implemented unit tests for the latter.

This commit is contained in:
dbuechel 2018-03-15 09:55:04 +01:00
parent b206b0d5be
commit 17c068de6f
16 changed files with 366 additions and 48 deletions

View file

@ -72,7 +72,7 @@ namespace SafeExamBrowser.Client
text = new Text(logger);
messageBox = new MessageBox(text);
uiFactory = new UserInterfaceFactory(text);
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ModuleLogger(logger, typeof(RuntimeProxy)));
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), new ModuleLogger(logger, typeof(RuntimeProxy)));
var displayMonitor = new DisplayMonitor(new ModuleLogger(logger, typeof(DisplayMonitor)), nativeMethods);
var processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods);

View file

@ -17,20 +17,21 @@ namespace SafeExamBrowser.Contracts.Communication
public interface ICommunicationProxy
{
/// <summary>
/// Fired when the connection to the proxy was lost, e.g. if a ping request failed or a communication fault occurred.
/// Fired when the connection to the host was lost, e.g. if a ping request failed or a communication fault occurred.
/// </summary>
event CommunicationEventHandler ConnectionLost;
/// <summary>
/// Tries to establish a connection. Returns <c>true</c> if the connection has been accepted, otherwise <c>false</c>. If a
/// connection was successfully established, a ping mechanism will be activated to periodically check the connection status.
/// connection was successfully established and the auto-ping flag is set, the connection status will be periodically checked.
/// </summary>
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
bool Connect(Guid? token = null);
bool Connect(Guid? token = null, bool autoPing = true);
/// <summary>
/// Terminates an open connection. Returns <c>true</c> if the disconnection has been acknowledged, otherwise <c>false</c>.
/// </summary>
/// <exception cref="InvalidOperationException">If no connection has been established.</exception>
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
bool Disconnect();
}

View file

@ -0,0 +1,21 @@
/*
* 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/.
*/
namespace SafeExamBrowser.Contracts.Communication
{
/// <summary>
/// A factory to create communication objects for proxies.
/// </summary>
public interface IProxyObjectFactory
{
/// <summary>
/// Creates a communication object (see <see cref="ICommunication"/>) for the specified endpoint address.
/// </summary>
ICommunication CreateObject(string address);
}
}

View file

@ -62,6 +62,7 @@
<Compile Include="Communication\IClientProxy.cs" />
<Compile Include="Communication\ICommunicationHost.cs" />
<Compile Include="Communication\ICommunicationProxy.cs" />
<Compile Include="Communication\IProxyObjectFactory.cs" />
<Compile Include="Communication\IProxyFactory.cs" />
<Compile Include="Communication\IRuntimeHost.cs" />
<Compile Include="Communication\IRuntimeProxy.cs" />

View file

@ -0,0 +1,39 @@
/*
* 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 SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Communication.Messages;
using SafeExamBrowser.Contracts.Communication.Responses;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Core.Communication;
namespace SafeExamBrowser.Core.UnitTests.Communication
{
internal class BaseProxyImpl : BaseProxy
{
public BaseProxyImpl(string address, IProxyObjectFactory factory, ILogger logger) : base(address, factory, logger)
{
}
public override bool Connect(Guid? token = null, bool autoPing = false)
{
return base.Connect(token, autoPing);
}
public override bool Disconnect()
{
return base.Disconnect();
}
public new Response Send(Message message)
{
return base.Send(message);
}
}
}

View file

@ -0,0 +1,197 @@
/*
* 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 System.ServiceModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Communication.Messages;
using SafeExamBrowser.Contracts.Communication.Responses;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Core.UnitTests.Communication
{
[TestClass]
public class BaseProxyTests
{
private Mock<IProxyObjectFactory> proxyObjectFactory;
private Mock<ILogger> logger;
private BaseProxyImpl sut;
[TestInitialize]
public void Initialize()
{
proxyObjectFactory = new Mock<IProxyObjectFactory>();
logger = new Mock<ILogger>();
sut = new BaseProxyImpl("net.pipe://some/address/here", proxyObjectFactory.Object, logger.Object);
}
[TestMethod]
public void MustConnectCorrectly()
{
var proxy = new Mock<ICommunication>();
var response = new ConnectionResponse
{
CommunicationToken = Guid.NewGuid(),
ConnectionEstablished = true
};
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
var token = Guid.NewGuid();
var connected = sut.Connect(token);
proxy.Verify(p => p.Connect(token), Times.Once);
proxyObjectFactory.Verify(f => f.CreateObject(It.IsAny<string>()), Times.Once);
Assert.IsTrue(connected);
}
[TestMethod]
public void MustDisconnectCorrectly()
{
var proxy = new Mock<ICommunication>();
var connectionResponse = new ConnectionResponse
{
CommunicationToken = Guid.NewGuid(),
ConnectionEstablished = true
};
var disconnectionResponse = new DisconnectionResponse
{
ConnectionTerminated = true
};
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
proxy.Setup(p => p.Disconnect(It.IsAny<DisconnectionMessage>())).Returns(disconnectionResponse);
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
var token = Guid.NewGuid();
var connected = sut.Connect(token);
var disconnected = sut.Disconnect();
proxy.Verify(p => p.Disconnect(It.Is<DisconnectionMessage>(m => m.CommunicationToken == connectionResponse.CommunicationToken)), Times.Once);
Assert.IsTrue(connected);
Assert.IsTrue(disconnected);
}
[TestMethod]
public void MustHandleConnectionRefusalCorrectly()
{
var proxy = new Mock<ICommunication>();
var response = new ConnectionResponse
{
CommunicationToken = Guid.NewGuid(),
ConnectionEstablished = false
};
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
var token = Guid.NewGuid();
var connected = sut.Connect(token);
proxy.Verify(p => p.Connect(token), Times.Once);
proxyObjectFactory.Verify(f => f.CreateObject(It.IsAny<string>()), Times.Once);
Assert.IsFalse(connected);
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void MustFailToDisconnectIfNotConnected()
{
sut.Disconnect();
}
[TestMethod]
[ExpectedException(typeof(CommunicationException))]
public void MustFailToDisconnectIfChannelNotOpen()
{
var proxy = new Mock<ICommunication>();
var response = new ConnectionResponse
{
CommunicationToken = Guid.NewGuid(),
ConnectionEstablished = true
};
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Faulted);
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
var token = Guid.NewGuid();
sut.Connect(token);
sut.Disconnect();
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void MustFailToSendIfNotConnected()
{
sut.Send(new Mock<Message>().Object);
}
[TestMethod]
[ExpectedException(typeof(CommunicationException))]
public void MustFailToSendIfChannelNotOpen()
{
var proxy = new Mock<ICommunication>();
var response = new ConnectionResponse
{
CommunicationToken = Guid.NewGuid(),
ConnectionEstablished = true
};
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Faulted);
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
var token = Guid.NewGuid();
sut.Connect(token);
sut.Send(new Mock<Message>().Object);
}
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void MustNotAllowSendingNull()
{
sut.Send(null);
}
[TestMethod]
public void MustSendCorrectly()
{
var proxy = new Mock<ICommunication>();
var connectionResponse = new ConnectionResponse
{
CommunicationToken = Guid.NewGuid(),
ConnectionEstablished = true
};
var message = new SimpleMessage(SimpleMessagePurport.Authenticate);
var response = new Mock<Response>();
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
proxy.Setup(p => p.Send(message)).Returns(response.Object);
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
var token = Guid.NewGuid();
var connected = sut.Connect(token);
var received = sut.Send(message);
Assert.AreEqual(response.Object, received);
Assert.AreEqual(connectionResponse.CommunicationToken, message.CommunicationToken);
}
}
}

View file

@ -69,6 +69,7 @@
<HintPath>..\packages\Moq.4.8.1\lib\net45\Moq.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Threading.Tasks.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.4.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
@ -83,6 +84,8 @@
<Compile Include="Behaviour\OperationModel\I18nOperationTests.cs" />
<Compile Include="Behaviour\OperationModel\DelegateOperationTests.cs" />
<Compile Include="Behaviour\OperationModel\OperationSequenceTests.cs" />
<Compile Include="Communication\BaseProxyImpl.cs" />
<Compile Include="Communication\BaseProxyTests.cs" />
<Compile Include="I18n\TextTests.cs" />
<Compile Include="I18n\XmlTextResourceTests.cs" />
<Compile Include="Logging\DefaultLogFormatterTests.cs" />

View file

@ -17,8 +17,7 @@ using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Core.Communication
{
/// <summary>
/// Base implementation of an <see cref="ICommunicationProxy"/>. Automatically starts a ping mechanism with a timeout of
/// <see cref="ONE_MINUTE"/> once a connection was established.
/// Base implementation of an <see cref="ICommunicationProxy"/>.
/// </summary>
public abstract class BaseProxy : ICommunicationProxy
{
@ -26,7 +25,8 @@ namespace SafeExamBrowser.Core.Communication
private static readonly object @lock = new object();
private string address;
private ICommunication channel;
private ICommunication proxy;
private IProxyObjectFactory factory;
private Guid? communicationToken;
private Timer timer;
@ -34,31 +34,34 @@ namespace SafeExamBrowser.Core.Communication
public event CommunicationEventHandler ConnectionLost;
public BaseProxy(string address, ILogger logger)
public BaseProxy(string address, IProxyObjectFactory factory, ILogger logger)
{
this.address = address;
this.factory = factory;
this.Logger = logger;
}
public virtual bool Connect(Guid? token = null)
public virtual bool Connect(Guid? token = null, bool autoPing = true)
{
var endpoint = new EndpointAddress(address);
proxy = factory.CreateObject(address);
channel = ChannelFactory<ICommunication>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), endpoint);
(channel as ICommunicationObject).Closed += BaseProxy_Closed;
(channel as ICommunicationObject).Closing += BaseProxy_Closing;
(channel as ICommunicationObject).Faulted += BaseProxy_Faulted;
(channel as ICommunicationObject).Opened += BaseProxy_Opened;
(channel as ICommunicationObject).Opening += BaseProxy_Opening;
if (proxy is ICommunicationObject communicationObject)
{
communicationObject.Closed += BaseProxy_Closed;
communicationObject.Closing += BaseProxy_Closing;
communicationObject.Faulted += BaseProxy_Faulted;
communicationObject.Opened += BaseProxy_Opened;
communicationObject.Opening += BaseProxy_Opening;
}
Logger.Debug($"Trying to connect to endpoint '{address}'{(token.HasValue ? $" with authentication token '{token}'" : string.Empty)}...");
var response = channel.Connect(token);
var response = proxy.Connect(token);
communicationToken = response.CommunicationToken;
Logger.Debug($"Connection was {(response.ConnectionEstablished ? "established" : "refused")}.");
if (response.ConnectionEstablished)
if (response.ConnectionEstablished && autoPing)
{
StartAutoPing();
}
@ -72,41 +75,64 @@ namespace SafeExamBrowser.Core.Communication
StopAutoPing();
var message = new DisconnectionMessage { CommunicationToken = communicationToken.Value };
var response = channel.Disconnect(message);
var response = proxy.Disconnect(message);
Logger.Debug($"{(response.ConnectionTerminated ? "Disconnected" : "Failed to disconnect")} from {address}.");
return response.ConnectionTerminated;
}
protected Response Send(Message message)
/// <summary>
/// Sends the given message, optionally returning a response. If no response is expected, <c>null</c> will be returned.
/// </summary>
/// <exception cref="ArgumentNullException">If the given message is <c>null</c>.</exception>
/// <exception cref="InvalidOperationException">If no connection has been established yet.</exception>
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
protected virtual Response Send(Message message)
{
if (message is null)
{
throw new ArgumentNullException(nameof(message));
}
FailIfNotConnected(nameof(Send));
message.CommunicationToken = communicationToken.Value;
var response = channel.Send(message);
var response = proxy.Send(message);
Logger.Debug($"Sent message '{ToString(message)}', got response '{ToString(response)}'.");
return response;
}
/// <summary>
/// Sends the given purport as <see cref="SimpleMessage"/>.
/// </summary>
protected Response Send(SimpleMessagePurport purport)
{
return Send(new SimpleMessage(purport));
}
/// <summary>
/// Determines whether the given response is a <see cref="SimpleResponse"/> with purport <see cref="SimpleResponsePurport.Acknowledged"/>.
/// </summary>
protected bool IsAcknowledged(Response response)
{
return response is SimpleResponse simpleResponse && simpleResponse.Purport == SimpleResponsePurport.Acknowledged;
}
/// <summary>
/// Retrieves the string representation of the given <see cref="Message"/>, or indicates that a message is <c>null</c>.
/// </summary>
protected string ToString(Message message)
{
return message != null ? message.ToString() : "<null>";
}
/// <summary>
/// etrieves the string representation of the given <see cref="Response"/>, or indicates that a response is <c>null</c>.
/// </summary>
protected string ToString(Response response)
{
return response != null ? response.ToString() : "<null>";
@ -144,7 +170,7 @@ namespace SafeExamBrowser.Core.Communication
throw new InvalidOperationException($"Cannot perform '{operationName}' before being connected to endpoint!");
}
if (channel == null || (channel as ICommunicationObject).State != CommunicationState.Opened)
if (proxy == null || (proxy as ICommunicationObject)?.State != CommunicationState.Opened)
{
throw new CommunicationException($"Tried to perform {operationName}, but channel was {GetChannelState()}!");
}
@ -152,7 +178,7 @@ namespace SafeExamBrowser.Core.Communication
private string GetChannelState()
{
return channel == null ? "null" : $"in state '{(channel as ICommunicationObject).State}'";
return proxy == null ? "null" : $"in state '{(proxy as ICommunicationObject)?.State}'";
}
private void StartAutoPing()

View file

@ -19,7 +19,7 @@ namespace SafeExamBrowser.Core.Communication
/// </summary>
public class ClientProxy : BaseProxy, IClientProxy
{
public ClientProxy(string address, ILogger logger) : base(address, logger)
public ClientProxy(string address, IProxyObjectFactory factory, ILogger logger) : base(address, factory, logger)
{
}

View file

@ -0,0 +1,27 @@
/*
* 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.ServiceModel;
using SafeExamBrowser.Contracts.Communication;
namespace SafeExamBrowser.Core.Communication
{
/// <summary>
/// Default implementation of the <see cref="IProxyObjectFactory"/> utilizing WCF (<see cref="ChannelFactory"/>).
/// </summary>
public class ProxyObjectFactory : IProxyObjectFactory
{
public ICommunication CreateObject(string address)
{
var endpoint = new EndpointAddress(address);
var channel = ChannelFactory<ICommunication>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), endpoint);
return channel;
}
}
}

View file

@ -20,7 +20,7 @@ namespace SafeExamBrowser.Core.Communication
/// </summary>
public class RuntimeProxy : BaseProxy, IRuntimeProxy
{
public RuntimeProxy(string address, ILogger logger) : base(address, logger)
public RuntimeProxy(string address, IProxyObjectFactory factory, ILogger logger) : base(address, factory, logger)
{
}

View file

@ -20,18 +20,18 @@ namespace SafeExamBrowser.Core.Communication
{
public bool Ignore { private get; set; }
public ServiceProxy(string address, ILogger logger) : base(address, logger)
public ServiceProxy(string address, IProxyObjectFactory factory, ILogger logger) : base(address, factory, logger)
{
}
public override bool Connect(Guid? token = null)
public override bool Connect(Guid? token = null, bool autoPing = true)
{
if (IgnoreOperation(nameof(Connect)))
{
return false;
}
return base.Connect();
return base.Connect(autoPing: autoPing);
}
public override bool Disconnect()

View file

@ -63,6 +63,7 @@
<Compile Include="Communication\BaseProxy.cs" />
<Compile Include="Communication\BaseHost.cs" />
<Compile Include="Communication\ClientProxy.cs" />
<Compile Include="Communication\ProxyObjectFactory.cs" />
<Compile Include="Communication\RuntimeProxy.cs" />
<Compile Include="Communication\ServiceProxy.cs" />
<Compile Include="Logging\DefaultLogFormatter.cs" />

View file

@ -45,38 +45,38 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
[TestMethod]
public void MustConnectToService()
{
service.Setup(s => s.Connect(null)).Returns(true);
service.Setup(s => s.Connect(null, true)).Returns(true);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
sut.Perform();
service.Setup(s => s.Connect(null)).Returns(true);
service.Setup(s => s.Connect(null, true)).Returns(true);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
sut.Perform();
service.Verify(s => s.Connect(null), Times.Exactly(2));
service.Verify(s => s.Connect(null, true), Times.Exactly(2));
}
[TestMethod]
public void MustNotFailIfServiceNotAvailable()
{
service.Setup(s => s.Connect(null)).Returns(false);
service.Setup(s => s.Connect(null, true)).Returns(false);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
sut.Perform();
service.Setup(s => s.Connect(null)).Returns(false);
service.Setup(s => s.Connect(null, true)).Returns(false);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
sut.Perform();
service.Setup(s => s.Connect(null)).Throws<Exception>();
service.Setup(s => s.Connect(null, true)).Throws<Exception>();
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
sut.Perform();
service.Setup(s => s.Connect(null)).Throws<Exception>();
service.Setup(s => s.Connect(null, true)).Throws<Exception>();
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
sut.Perform();
@ -85,7 +85,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
[TestMethod]
public void MustFailIfServiceMandatoryAndNotAvailable()
{
service.Setup(s => s.Connect(null)).Returns(false);
service.Setup(s => s.Connect(null, true)).Returns(false);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
var result = sut.Perform();
@ -96,7 +96,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
[TestMethod]
public void MustNotFailIfServiceOptionalAndNotAvailable()
{
service.Setup(s => s.Connect(null)).Returns(false);
service.Setup(s => s.Connect(null, true)).Returns(false);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
var result = sut.Perform();
@ -109,13 +109,13 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
[TestMethod]
public void MustDisconnectWhenReverting()
{
service.Setup(s => s.Connect(null)).Returns(true);
service.Setup(s => s.Connect(null, true)).Returns(true);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
sut.Perform();
sut.Revert();
service.Setup(s => s.Connect(null)).Returns(true);
service.Setup(s => s.Connect(null, true)).Returns(true);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
sut.Perform();
@ -127,7 +127,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
[TestMethod]
public void MustNotFailWhenDisconnecting()
{
service.Setup(s => s.Connect(null)).Returns(true);
service.Setup(s => s.Connect(null, true)).Returns(true);
service.Setup(s => s.Disconnect()).Throws<Exception>();
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
@ -140,25 +140,25 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
[TestMethod]
public void MustNotDisconnnectIfNotAvailable()
{
service.Setup(s => s.Connect(null)).Returns(false);
service.Setup(s => s.Connect(null, true)).Returns(false);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
sut.Perform();
sut.Revert();
service.Setup(s => s.Connect(null)).Returns(false);
service.Setup(s => s.Connect(null, true)).Returns(false);
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
sut.Perform();
sut.Revert();
service.Setup(s => s.Connect(null)).Throws<Exception>();
service.Setup(s => s.Connect(null, true)).Throws<Exception>();
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
sut.Perform();
sut.Revert();
service.Setup(s => s.Connect(null)).Throws<Exception>();
service.Setup(s => s.Connect(null, true)).Throws<Exception>();
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
sut.Perform();

View file

@ -15,16 +15,18 @@ namespace SafeExamBrowser.Runtime.Communication
{
internal class ProxyFactory : IProxyFactory
{
private IProxyObjectFactory factory;
private ILogger logger;
public ProxyFactory(ILogger logger)
public ProxyFactory(IProxyObjectFactory factory, ILogger logger)
{
this.factory = factory;
this.logger = logger;
}
public IClientProxy CreateClientProxy(string address)
{
return new ClientProxy(address, new ModuleLogger(logger, typeof(ClientProxy)));
return new ClientProxy(address, factory, new ModuleLogger(logger, typeof(ClientProxy)));
}
}
}

View file

@ -50,9 +50,9 @@ namespace SafeExamBrowser.Runtime
var uiFactory = new UserInterfaceFactory(text);
var desktop = new Desktop(new ModuleLogger(logger, typeof(Desktop)));
var processFactory = new ProcessFactory(desktop, new ModuleLogger(logger, typeof(ProcessFactory)));
var proxyFactory = new ProxyFactory(logger);
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger);
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, configuration, new ModuleLogger(logger, typeof(RuntimeHost)));
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy)));
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, typeof(ServiceProxy)));
var sessionController = new SessionController(configuration, logger, processFactory, proxyFactory, runtimeHost, serviceProxy);
var bootstrapOperations = new Queue<IOperation>();