diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs
index c40522de..7b8a9741 100644
--- a/SafeExamBrowser.Client/CompositionRoot.cs
+++ b/SafeExamBrowser.Client/CompositionRoot.cs
@@ -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);
diff --git a/SafeExamBrowser.Contracts/Communication/ICommunicationProxy.cs b/SafeExamBrowser.Contracts/Communication/ICommunicationProxy.cs
index 2fd4d08c..152ae784 100644
--- a/SafeExamBrowser.Contracts/Communication/ICommunicationProxy.cs
+++ b/SafeExamBrowser.Contracts/Communication/ICommunicationProxy.cs
@@ -17,20 +17,21 @@ namespace SafeExamBrowser.Contracts.Communication
public interface ICommunicationProxy
{
///
- /// 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.
///
event CommunicationEventHandler ConnectionLost;
///
/// Tries to establish a connection. Returns true if the connection has been accepted, otherwise false. 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.
///
/// If the communication failed.
- bool Connect(Guid? token = null);
+ bool Connect(Guid? token = null, bool autoPing = true);
///
/// Terminates an open connection. Returns true if the disconnection has been acknowledged, otherwise false.
///
+ /// If no connection has been established.
/// If the communication failed.
bool Disconnect();
}
diff --git a/SafeExamBrowser.Contracts/Communication/IProxyObjectFactory.cs b/SafeExamBrowser.Contracts/Communication/IProxyObjectFactory.cs
new file mode 100644
index 00000000..a2565a2b
--- /dev/null
+++ b/SafeExamBrowser.Contracts/Communication/IProxyObjectFactory.cs
@@ -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
+{
+ ///
+ /// A factory to create communication objects for proxies.
+ ///
+ public interface IProxyObjectFactory
+ {
+ ///
+ /// Creates a communication object (see ) for the specified endpoint address.
+ ///
+ ICommunication CreateObject(string address);
+ }
+}
diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj
index 29ab4299..4383dd9c 100644
--- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj
+++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj
@@ -62,6 +62,7 @@
+
diff --git a/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyImpl.cs b/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyImpl.cs
new file mode 100644
index 00000000..cf0d2b7d
--- /dev/null
+++ b/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyImpl.cs
@@ -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);
+ }
+ }
+}
diff --git a/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyTests.cs b/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyTests.cs
new file mode 100644
index 00000000..72e120df
--- /dev/null
+++ b/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyTests.cs
@@ -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 proxyObjectFactory;
+ private Mock logger;
+ private BaseProxyImpl sut;
+
+ [TestInitialize]
+ public void Initialize()
+ {
+ proxyObjectFactory = new Mock();
+ logger = new Mock();
+
+ sut = new BaseProxyImpl("net.pipe://some/address/here", proxyObjectFactory.Object, logger.Object);
+ }
+
+ [TestMethod]
+ public void MustConnectCorrectly()
+ {
+ var proxy = new Mock();
+ var response = new ConnectionResponse
+ {
+ CommunicationToken = Guid.NewGuid(),
+ ConnectionEstablished = true
+ };
+
+ proxy.Setup(p => p.Connect(It.IsAny())).Returns(response);
+ proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).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()), Times.Once);
+
+ Assert.IsTrue(connected);
+ }
+
+ [TestMethod]
+ public void MustDisconnectCorrectly()
+ {
+ var proxy = new Mock();
+ var connectionResponse = new ConnectionResponse
+ {
+ CommunicationToken = Guid.NewGuid(),
+ ConnectionEstablished = true
+ };
+ var disconnectionResponse = new DisconnectionResponse
+ {
+ ConnectionTerminated = true
+ };
+
+ proxy.Setup(p => p.Connect(It.IsAny())).Returns(connectionResponse);
+ proxy.Setup(p => p.Disconnect(It.IsAny())).Returns(disconnectionResponse);
+ proxy.As().Setup(o => o.State).Returns(CommunicationState.Opened);
+ proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).Returns(proxy.Object);
+
+ var token = Guid.NewGuid();
+ var connected = sut.Connect(token);
+ var disconnected = sut.Disconnect();
+
+ proxy.Verify(p => p.Disconnect(It.Is(m => m.CommunicationToken == connectionResponse.CommunicationToken)), Times.Once);
+
+ Assert.IsTrue(connected);
+ Assert.IsTrue(disconnected);
+ }
+
+ [TestMethod]
+ public void MustHandleConnectionRefusalCorrectly()
+ {
+ var proxy = new Mock();
+ var response = new ConnectionResponse
+ {
+ CommunicationToken = Guid.NewGuid(),
+ ConnectionEstablished = false
+ };
+
+ proxy.Setup(p => p.Connect(It.IsAny())).Returns(response);
+ proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).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()), 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();
+ var response = new ConnectionResponse
+ {
+ CommunicationToken = Guid.NewGuid(),
+ ConnectionEstablished = true
+ };
+
+ proxy.Setup(p => p.Connect(It.IsAny())).Returns(response);
+ proxy.As().Setup(o => o.State).Returns(CommunicationState.Faulted);
+ proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).Returns(proxy.Object);
+
+ var token = Guid.NewGuid();
+
+ sut.Connect(token);
+ sut.Disconnect();
+ }
+
+ [TestMethod]
+ [ExpectedException(typeof(InvalidOperationException))]
+ public void MustFailToSendIfNotConnected()
+ {
+ sut.Send(new Mock().Object);
+ }
+
+ [TestMethod]
+ [ExpectedException(typeof(CommunicationException))]
+ public void MustFailToSendIfChannelNotOpen()
+ {
+ var proxy = new Mock();
+ var response = new ConnectionResponse
+ {
+ CommunicationToken = Guid.NewGuid(),
+ ConnectionEstablished = true
+ };
+
+ proxy.Setup(p => p.Connect(It.IsAny())).Returns(response);
+ proxy.As().Setup(o => o.State).Returns(CommunicationState.Faulted);
+ proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).Returns(proxy.Object);
+
+ var token = Guid.NewGuid();
+
+ sut.Connect(token);
+ sut.Send(new Mock().Object);
+ }
+
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void MustNotAllowSendingNull()
+ {
+ sut.Send(null);
+ }
+
+ [TestMethod]
+ public void MustSendCorrectly()
+ {
+ var proxy = new Mock();
+ var connectionResponse = new ConnectionResponse
+ {
+ CommunicationToken = Guid.NewGuid(),
+ ConnectionEstablished = true
+ };
+ var message = new SimpleMessage(SimpleMessagePurport.Authenticate);
+ var response = new Mock();
+
+ proxy.Setup(p => p.Connect(It.IsAny())).Returns(connectionResponse);
+ proxy.Setup(p => p.Send(message)).Returns(response.Object);
+ proxy.As().Setup(o => o.State).Returns(CommunicationState.Opened);
+ proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).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);
+ }
+ }
+}
diff --git a/SafeExamBrowser.Core.UnitTests/SafeExamBrowser.Core.UnitTests.csproj b/SafeExamBrowser.Core.UnitTests/SafeExamBrowser.Core.UnitTests.csproj
index a6444549..85b3e7de 100644
--- a/SafeExamBrowser.Core.UnitTests/SafeExamBrowser.Core.UnitTests.csproj
+++ b/SafeExamBrowser.Core.UnitTests/SafeExamBrowser.Core.UnitTests.csproj
@@ -69,6 +69,7 @@
..\packages\Moq.4.8.1\lib\net45\Moq.dll
+
..\packages\System.Threading.Tasks.Extensions.4.4.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll
@@ -83,6 +84,8 @@
+
+
diff --git a/SafeExamBrowser.Core/Communication/BaseProxy.cs b/SafeExamBrowser.Core/Communication/BaseProxy.cs
index f29a03ca..1a6088d0 100644
--- a/SafeExamBrowser.Core/Communication/BaseProxy.cs
+++ b/SafeExamBrowser.Core/Communication/BaseProxy.cs
@@ -17,8 +17,7 @@ using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Core.Communication
{
///
- /// Base implementation of an . Automatically starts a ping mechanism with a timeout of
- /// once a connection was established.
+ /// Base implementation of an .
///
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.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)
+ ///
+ /// Sends the given message, optionally returning a response. If no response is expected, null will be returned.
+ ///
+ /// If the given message is null.
+ /// If no connection has been established yet.
+ /// If the communication failed.
+ 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;
}
+ ///
+ /// Sends the given purport as .
+ ///
protected Response Send(SimpleMessagePurport purport)
{
return Send(new SimpleMessage(purport));
}
+ ///
+ /// Determines whether the given response is a with purport .
+ ///
protected bool IsAcknowledged(Response response)
{
return response is SimpleResponse simpleResponse && simpleResponse.Purport == SimpleResponsePurport.Acknowledged;
}
+ ///
+ /// Retrieves the string representation of the given , or indicates that a message is null.
+ ///
protected string ToString(Message message)
{
return message != null ? message.ToString() : "";
}
+ ///
+ /// etrieves the string representation of the given , or indicates that a response is null.
+ ///
protected string ToString(Response response)
{
return response != null ? response.ToString() : "";
@@ -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()
diff --git a/SafeExamBrowser.Core/Communication/ClientProxy.cs b/SafeExamBrowser.Core/Communication/ClientProxy.cs
index 996e4e8c..5c9bf375 100644
--- a/SafeExamBrowser.Core/Communication/ClientProxy.cs
+++ b/SafeExamBrowser.Core/Communication/ClientProxy.cs
@@ -19,7 +19,7 @@ namespace SafeExamBrowser.Core.Communication
///
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)
{
}
diff --git a/SafeExamBrowser.Core/Communication/ProxyObjectFactory.cs b/SafeExamBrowser.Core/Communication/ProxyObjectFactory.cs
new file mode 100644
index 00000000..d601709c
--- /dev/null
+++ b/SafeExamBrowser.Core/Communication/ProxyObjectFactory.cs
@@ -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
+{
+ ///
+ /// Default implementation of the utilizing WCF ().
+ ///
+ public class ProxyObjectFactory : IProxyObjectFactory
+ {
+ public ICommunication CreateObject(string address)
+ {
+ var endpoint = new EndpointAddress(address);
+ var channel = ChannelFactory.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), endpoint);
+
+ return channel;
+ }
+ }
+}
diff --git a/SafeExamBrowser.Core/Communication/RuntimeProxy.cs b/SafeExamBrowser.Core/Communication/RuntimeProxy.cs
index 0aff2402..343ede46 100644
--- a/SafeExamBrowser.Core/Communication/RuntimeProxy.cs
+++ b/SafeExamBrowser.Core/Communication/RuntimeProxy.cs
@@ -20,7 +20,7 @@ namespace SafeExamBrowser.Core.Communication
///
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)
{
}
diff --git a/SafeExamBrowser.Core/Communication/ServiceProxy.cs b/SafeExamBrowser.Core/Communication/ServiceProxy.cs
index f44d7a1f..f84d327e 100644
--- a/SafeExamBrowser.Core/Communication/ServiceProxy.cs
+++ b/SafeExamBrowser.Core/Communication/ServiceProxy.cs
@@ -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()
diff --git a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj
index ec65ac98..77384578 100644
--- a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj
+++ b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj
@@ -63,6 +63,7 @@
+
diff --git a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceConnectionOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceConnectionOperationTests.cs
index e9995376..80a3d282 100644
--- a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceConnectionOperationTests.cs
+++ b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceConnectionOperationTests.cs
@@ -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();
+ service.Setup(s => s.Connect(null, true)).Throws();
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
sut.Perform();
- service.Setup(s => s.Connect(null)).Throws();
+ service.Setup(s => s.Connect(null, true)).Throws();
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();
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();
+ service.Setup(s => s.Connect(null, true)).Throws();
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
sut.Perform();
sut.Revert();
- service.Setup(s => s.Connect(null)).Throws();
+ service.Setup(s => s.Connect(null, true)).Throws();
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
sut.Perform();
diff --git a/SafeExamBrowser.Runtime/Communication/ProxyFactory.cs b/SafeExamBrowser.Runtime/Communication/ProxyFactory.cs
index 12ae7cc8..6b38b4ce 100644
--- a/SafeExamBrowser.Runtime/Communication/ProxyFactory.cs
+++ b/SafeExamBrowser.Runtime/Communication/ProxyFactory.cs
@@ -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)));
}
}
}
diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs
index a9b9cff8..e62741a9 100644
--- a/SafeExamBrowser.Runtime/CompositionRoot.cs
+++ b/SafeExamBrowser.Runtime/CompositionRoot.cs
@@ -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();