SEBWIN-219: Extracted creation of proxy and host objects from base implementations and started implementing unit tests for hosts.
This commit is contained in:
parent
e4940383fb
commit
3a4f189916
21 changed files with 448 additions and 66 deletions
|
@ -24,7 +24,7 @@ namespace SafeExamBrowser.Client.Communication
|
||||||
|
|
||||||
public event CommunicationEventHandler Shutdown;
|
public event CommunicationEventHandler Shutdown;
|
||||||
|
|
||||||
public ClientHost(string address, ILogger logger, int processId) : base(address, logger)
|
public ClientHost(string address, IHostObjectFactory factory, ILogger logger, int processId) : base(address, factory, logger)
|
||||||
{
|
{
|
||||||
this.processId = processId;
|
this.processId = processId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ using SafeExamBrowser.Contracts.UserInterface;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
|
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
|
||||||
using SafeExamBrowser.Contracts.WindowsApi;
|
using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
using SafeExamBrowser.Core.Behaviour.OperationModel;
|
using SafeExamBrowser.Core.Behaviour.OperationModel;
|
||||||
|
using SafeExamBrowser.Core.Communication.Hosts;
|
||||||
using SafeExamBrowser.Core.Communication.Proxies;
|
using SafeExamBrowser.Core.Communication.Proxies;
|
||||||
using SafeExamBrowser.Core.I18n;
|
using SafeExamBrowser.Core.I18n;
|
||||||
using SafeExamBrowser.Core.Logging;
|
using SafeExamBrowser.Core.Logging;
|
||||||
|
@ -159,7 +160,8 @@ namespace SafeExamBrowser.Client
|
||||||
private IOperation BuildCommunicationHostOperation()
|
private IOperation BuildCommunicationHostOperation()
|
||||||
{
|
{
|
||||||
var processId = Process.GetCurrentProcess().Id;
|
var processId = Process.GetCurrentProcess().Id;
|
||||||
var host = new ClientHost(configuration.RuntimeInfo.ClientAddress, new ModuleLogger(logger, typeof(ClientHost)), processId);
|
var factory = new HostObjectFactory();
|
||||||
|
var host = new ClientHost(configuration.RuntimeInfo.ClientAddress, factory, new ModuleLogger(logger, typeof(ClientHost)), processId);
|
||||||
var operation = new CommunicationOperation(host, logger);
|
var operation = new CommunicationOperation(host, logger);
|
||||||
|
|
||||||
clientHost = host;
|
clientHost = host;
|
||||||
|
|
19
SafeExamBrowser.Contracts/Communication/Hosts/IHostObject.cs
Normal file
19
SafeExamBrowser.Contracts/Communication/Hosts/IHostObject.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Hosts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The host object to be used in communication hosts.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHostObject : ICommunicationObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.Hosts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A factory to create host objects for communication hosts.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHostObjectFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Utilizes the given communication object to create a host object (see <see cref="IHostObject"/>) for the specified endpoint address.
|
||||||
|
/// </summary>
|
||||||
|
IHostObject CreateObject(string address, ICommunication communicationObject);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Communication.Proxies
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The communication object to be used in an <see cref="ICommunicationProxy"/>.
|
||||||
|
/// </summary>
|
||||||
|
public interface IProxyObject : ICommunication, ICommunicationObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,13 +9,13 @@
|
||||||
namespace SafeExamBrowser.Contracts.Communication.Proxies
|
namespace SafeExamBrowser.Contracts.Communication.Proxies
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A factory to create communication objects for proxies.
|
/// A factory to create proxy objects for communication proxies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IProxyObjectFactory
|
public interface IProxyObjectFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a communication object (see <see cref="ICommunication"/>) for the specified endpoint address.
|
/// Creates a proxy object (see <see cref="IProxyObject"/>) for the specified endpoint address.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ICommunication CreateObject(string address);
|
IProxyObject CreateObject(string address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,10 +58,13 @@
|
||||||
<Compile Include="Behaviour\OperationModel\IOperationSequence.cs" />
|
<Compile Include="Behaviour\OperationModel\IOperationSequence.cs" />
|
||||||
<Compile Include="Behaviour\OperationModel\OperationResult.cs" />
|
<Compile Include="Behaviour\OperationModel\OperationResult.cs" />
|
||||||
<Compile Include="Communication\Hosts\IClientHost.cs" />
|
<Compile Include="Communication\Hosts\IClientHost.cs" />
|
||||||
|
<Compile Include="Communication\Hosts\IHostObject.cs" />
|
||||||
|
<Compile Include="Communication\Hosts\IHostObjectFactory.cs" />
|
||||||
<Compile Include="Communication\ICommunication.cs" />
|
<Compile Include="Communication\ICommunication.cs" />
|
||||||
<Compile Include="Communication\Proxies\IClientProxy.cs" />
|
<Compile Include="Communication\Proxies\IClientProxy.cs" />
|
||||||
<Compile Include="Communication\ICommunicationHost.cs" />
|
<Compile Include="Communication\ICommunicationHost.cs" />
|
||||||
<Compile Include="Communication\ICommunicationProxy.cs" />
|
<Compile Include="Communication\ICommunicationProxy.cs" />
|
||||||
|
<Compile Include="Communication\Proxies\IProxyObject.cs" />
|
||||||
<Compile Include="Communication\Proxies\IProxyObjectFactory.cs" />
|
<Compile Include="Communication\Proxies\IProxyObjectFactory.cs" />
|
||||||
<Compile Include="Communication\Proxies\IProxyFactory.cs" />
|
<Compile Include="Communication\Proxies\IProxyFactory.cs" />
|
||||||
<Compile Include="Communication\Hosts\IRuntimeHost.cs" />
|
<Compile Include="Communication\Hosts\IRuntimeHost.cs" />
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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.Data;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Core.Communication.Hosts;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.UnitTests.Communication.Hosts
|
||||||
|
{
|
||||||
|
internal class BaseHostImpl : BaseHost
|
||||||
|
{
|
||||||
|
public Func<Guid?, bool> OnConnectStub { get; set; }
|
||||||
|
public Action OnDisconnectStub { get; set; }
|
||||||
|
public Func<Message, Response> OnReceiveStub { get; set; }
|
||||||
|
public Func<SimpleMessagePurport, Response> OnReceiveSimpleMessageStub { get; set; }
|
||||||
|
|
||||||
|
public BaseHostImpl(string address, IHostObjectFactory factory, ILogger logger) : base(address, factory, logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid? GetCommunicationToken()
|
||||||
|
{
|
||||||
|
return CommunicationToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnConnect(Guid? token)
|
||||||
|
{
|
||||||
|
return OnConnectStub?.Invoke(token) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDisconnect()
|
||||||
|
{
|
||||||
|
OnDisconnectStub?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Response OnReceive(Message message)
|
||||||
|
{
|
||||||
|
return OnReceiveStub?.Invoke(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Response OnReceive(SimpleMessagePurport message)
|
||||||
|
{
|
||||||
|
return OnReceiveSimpleMessageStub?.Invoke(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
* 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 System.Threading;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.UnitTests.Communication.Hosts
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class BaseHostTests
|
||||||
|
{
|
||||||
|
private Mock<IHostObject> hostObject;
|
||||||
|
private Mock<IHostObjectFactory> hostObjectFactory;
|
||||||
|
private Mock<ILogger> logger;
|
||||||
|
private BaseHostImpl sut;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
hostObject = new Mock<IHostObject>();
|
||||||
|
hostObjectFactory = new Mock<IHostObjectFactory>();
|
||||||
|
logger = new Mock<ILogger>();
|
||||||
|
|
||||||
|
hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object);
|
||||||
|
|
||||||
|
sut = new BaseHostImpl("net.pipe://some/address/here", hostObjectFactory.Object, logger.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyStartHost()
|
||||||
|
{
|
||||||
|
var threadId = Thread.CurrentThread.ManagedThreadId;
|
||||||
|
|
||||||
|
hostObject.Setup(h => h.Open()).Callback(() => threadId = Thread.CurrentThread.ManagedThreadId);
|
||||||
|
|
||||||
|
sut.Start();
|
||||||
|
|
||||||
|
hostObjectFactory.Verify(f => f.CreateObject(It.IsAny<string>(), sut), Times.Once);
|
||||||
|
|
||||||
|
Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[ExpectedException(typeof(CommunicationException))]
|
||||||
|
public void MustCorrectlyHandleStartupException()
|
||||||
|
{
|
||||||
|
hostObject.Setup(h => h.Open()).Throws<Exception>();
|
||||||
|
|
||||||
|
sut.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyStopHost()
|
||||||
|
{
|
||||||
|
sut.Start();
|
||||||
|
sut.Stop();
|
||||||
|
|
||||||
|
hostObject.Verify(h => h.Close(), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[ExpectedException(typeof(CommunicationException))]
|
||||||
|
public void MustCorrectlyHandleShutdownException()
|
||||||
|
{
|
||||||
|
hostObject.Setup(h => h.Close()).Throws<Exception>();
|
||||||
|
|
||||||
|
sut.Start();
|
||||||
|
sut.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustNotFailToStopIfNotRunning()
|
||||||
|
{
|
||||||
|
sut.Stop();
|
||||||
|
sut.Stop();
|
||||||
|
sut.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustNotFailToEvaluateIsRunningIfNotRunning()
|
||||||
|
{
|
||||||
|
var running = sut.IsRunning;
|
||||||
|
|
||||||
|
Assert.IsFalse(running);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyIndicateWhetherHostIsRunning()
|
||||||
|
{
|
||||||
|
hostObject.SetupGet(h => h.State).Returns(CommunicationState.Faulted);
|
||||||
|
|
||||||
|
sut.Start();
|
||||||
|
|
||||||
|
Assert.IsFalse(sut.IsRunning);
|
||||||
|
|
||||||
|
hostObject.SetupGet(h => h.State).Returns(CommunicationState.Opened);
|
||||||
|
|
||||||
|
Assert.IsTrue(sut.IsRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyHandleConnectionRequest()
|
||||||
|
{
|
||||||
|
var token = Guid.NewGuid();
|
||||||
|
var receivedToken = default(Guid?);
|
||||||
|
|
||||||
|
sut.OnConnectStub = (t) =>
|
||||||
|
{
|
||||||
|
receivedToken = t;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = sut.Connect(token);
|
||||||
|
|
||||||
|
Assert.IsTrue(response.ConnectionEstablished);
|
||||||
|
Assert.AreEqual(token, receivedToken);
|
||||||
|
Assert.AreEqual(sut.GetCommunicationToken(), response.CommunicationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyHandleDeniedConnectionRequest()
|
||||||
|
{
|
||||||
|
var token = Guid.NewGuid();
|
||||||
|
var receivedToken = default(Guid?);
|
||||||
|
|
||||||
|
sut.OnConnectStub = (t) =>
|
||||||
|
{
|
||||||
|
receivedToken = t;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = sut.Connect(token);
|
||||||
|
|
||||||
|
Assert.IsFalse(response.ConnectionEstablished);
|
||||||
|
Assert.AreEqual(token, receivedToken);
|
||||||
|
Assert.IsNull(sut.GetCommunicationToken());
|
||||||
|
Assert.IsNull(response.CommunicationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyHandleDisconnectionRequest()
|
||||||
|
{
|
||||||
|
var message = new DisconnectionMessage();
|
||||||
|
var disconnected = false;
|
||||||
|
|
||||||
|
sut.OnConnectStub = (t) => { return true; };
|
||||||
|
sut.OnDisconnectStub = () => disconnected = true;
|
||||||
|
sut.Connect();
|
||||||
|
|
||||||
|
message.CommunicationToken = sut.GetCommunicationToken().Value;
|
||||||
|
|
||||||
|
var response = sut.Disconnect(message);
|
||||||
|
|
||||||
|
Assert.IsTrue(disconnected);
|
||||||
|
Assert.IsTrue(response.ConnectionTerminated);
|
||||||
|
Assert.IsNull(sut.GetCommunicationToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyHandleUnauthorizedDisconnectionRequest()
|
||||||
|
{
|
||||||
|
var disconnected = false;
|
||||||
|
|
||||||
|
sut.OnConnectStub = (t) => { return true; };
|
||||||
|
sut.OnDisconnectStub = () => disconnected = true;
|
||||||
|
sut.Connect();
|
||||||
|
|
||||||
|
var response = sut.Disconnect(new DisconnectionMessage());
|
||||||
|
|
||||||
|
Assert.IsFalse(disconnected);
|
||||||
|
Assert.IsFalse(response.ConnectionTerminated);
|
||||||
|
Assert.IsNotNull(sut.GetCommunicationToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyHandleUnauthorizedTransmission()
|
||||||
|
{
|
||||||
|
var received = false;
|
||||||
|
var simpleReceived = false;
|
||||||
|
|
||||||
|
sut.OnReceiveStub = (m) => { received = true; return null; };
|
||||||
|
sut.OnReceiveSimpleMessageStub = (m) => { simpleReceived = true; return null; };
|
||||||
|
|
||||||
|
var response = sut.Send(new DisconnectionMessage());
|
||||||
|
|
||||||
|
Assert.IsFalse(received);
|
||||||
|
Assert.IsFalse(simpleReceived);
|
||||||
|
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||||
|
Assert.AreEqual(SimpleResponsePurport.Unauthorized, (response as SimpleResponse)?.Purport);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyHandlePingMessage()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
Assert.Fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyReceiveSimpleMessage()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
Assert.Fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustCorrectlyReceiveMessage()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
Assert.Fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,6 @@ using System;
|
||||||
using System.ServiceModel;
|
using System.ServiceModel;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
|
||||||
using SafeExamBrowser.Contracts.Communication.Data;
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
@ -36,7 +35,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustConnectCorrectly()
|
public void MustConnectCorrectly()
|
||||||
{
|
{
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var response = new ConnectionResponse
|
var response = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -58,7 +57,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustDisconnectCorrectly()
|
public void MustDisconnectCorrectly()
|
||||||
{
|
{
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var connectionResponse = new ConnectionResponse
|
var connectionResponse = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -71,7 +70,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
||||||
proxy.Setup(p => p.Disconnect(It.IsAny<DisconnectionMessage>())).Returns(disconnectionResponse);
|
proxy.Setup(p => p.Disconnect(It.IsAny<DisconnectionMessage>())).Returns(disconnectionResponse);
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Opened);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
var token = Guid.NewGuid();
|
var token = Guid.NewGuid();
|
||||||
|
@ -87,7 +86,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustHandleConnectionRefusalCorrectly()
|
public void MustHandleConnectionRefusalCorrectly()
|
||||||
{
|
{
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var response = new ConnectionResponse
|
var response = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -117,7 +116,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[ExpectedException(typeof(CommunicationException))]
|
[ExpectedException(typeof(CommunicationException))]
|
||||||
public void MustFailToDisconnectIfChannelNotOpen()
|
public void MustFailToDisconnectIfChannelNotOpen()
|
||||||
{
|
{
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var response = new ConnectionResponse
|
var response = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -125,7 +124,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
};
|
};
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Faulted);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Faulted);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
var token = Guid.NewGuid();
|
var token = Guid.NewGuid();
|
||||||
|
@ -145,7 +144,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[ExpectedException(typeof(CommunicationException))]
|
[ExpectedException(typeof(CommunicationException))]
|
||||||
public void MustFailToSendIfChannelNotOpen()
|
public void MustFailToSendIfChannelNotOpen()
|
||||||
{
|
{
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var response = new ConnectionResponse
|
var response = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -153,7 +152,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
};
|
};
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Faulted);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Faulted);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
var token = Guid.NewGuid();
|
var token = Guid.NewGuid();
|
||||||
|
@ -172,7 +171,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustSendCorrectly()
|
public void MustSendCorrectly()
|
||||||
{
|
{
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var connectionResponse = new ConnectionResponse
|
var connectionResponse = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -183,7 +182,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
||||||
proxy.Setup(p => p.Send(message)).Returns(response.Object);
|
proxy.Setup(p => p.Send(message)).Returns(response.Object);
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Opened);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
var token = Guid.NewGuid();
|
var token = Guid.NewGuid();
|
||||||
|
@ -197,7 +196,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustSendSimpleMessageCorrectly()
|
public void MustSendSimpleMessageCorrectly()
|
||||||
{
|
{
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var connectionResponse = new ConnectionResponse
|
var connectionResponse = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -208,7 +207,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
||||||
proxy.Setup(p => p.Send(It.IsAny<Message>())).Returns(response.Object);
|
proxy.Setup(p => p.Send(It.IsAny<Message>())).Returns(response.Object);
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Opened);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
var token = Guid.NewGuid();
|
var token = Guid.NewGuid();
|
||||||
|
@ -255,7 +254,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestConnectionMustPingHost()
|
public void TestConnectionMustPingHost()
|
||||||
{
|
{
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var connectionResponse = new ConnectionResponse
|
var connectionResponse = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -264,7 +263,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
||||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Ping))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged));
|
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Ping))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged));
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Opened);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
var token = Guid.NewGuid();
|
var token = Guid.NewGuid();
|
||||||
|
@ -279,7 +278,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
public void TestConnectionMustInvokeConnectionLostEvent()
|
public void TestConnectionMustInvokeConnectionLostEvent()
|
||||||
{
|
{
|
||||||
var lost = false;
|
var lost = false;
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var connectionResponse = new ConnectionResponse
|
var connectionResponse = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -290,7 +289,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
||||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Ping))).Returns(new SimpleResponse(SimpleResponsePurport.UnknownMessage));
|
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Ping))).Returns(new SimpleResponse(SimpleResponsePurport.UnknownMessage));
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Opened);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
var token = Guid.NewGuid();
|
var token = Guid.NewGuid();
|
||||||
|
@ -305,7 +304,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
public void TestConnectionMustNotFail()
|
public void TestConnectionMustNotFail()
|
||||||
{
|
{
|
||||||
var lost = false;
|
var lost = false;
|
||||||
var proxy = new Mock<ICommunication>();
|
var proxy = new Mock<IProxyObject>();
|
||||||
var connectionResponse = new ConnectionResponse
|
var connectionResponse = new ConnectionResponse
|
||||||
{
|
{
|
||||||
CommunicationToken = Guid.NewGuid(),
|
CommunicationToken = Guid.NewGuid(),
|
||||||
|
@ -316,7 +315,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(connectionResponse);
|
||||||
proxy.Setup(p => p.Send(It.IsAny<Message>())).Throws<Exception>();
|
proxy.Setup(p => p.Send(It.IsAny<Message>())).Throws<Exception>();
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Opened);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
var token = Guid.NewGuid();
|
var token = Guid.NewGuid();
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
{
|
{
|
||||||
private Mock<ILogger> logger;
|
private Mock<ILogger> logger;
|
||||||
private Mock<IProxyObjectFactory> proxyObjectFactory;
|
private Mock<IProxyObjectFactory> proxyObjectFactory;
|
||||||
private Mock<ICommunication> proxy;
|
private Mock<IProxyObject> proxy;
|
||||||
private ClientProxy sut;
|
private ClientProxy sut;
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
|
@ -37,10 +37,10 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
|
|
||||||
logger = new Mock<ILogger>();
|
logger = new Mock<ILogger>();
|
||||||
proxyObjectFactory = new Mock<IProxyObjectFactory>();
|
proxyObjectFactory = new Mock<IProxyObjectFactory>();
|
||||||
proxy = new Mock<ICommunication>();
|
proxy = new Mock<IProxyObject>();
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Opened);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
sut = new ClientProxy("net.pipe://random/address/here", proxyObjectFactory.Object, logger.Object);
|
sut = new ClientProxy("net.pipe://random/address/here", proxyObjectFactory.Object, logger.Object);
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
{
|
{
|
||||||
private Mock<ILogger> logger;
|
private Mock<ILogger> logger;
|
||||||
private Mock<IProxyObjectFactory> proxyObjectFactory;
|
private Mock<IProxyObjectFactory> proxyObjectFactory;
|
||||||
private Mock<ICommunication> proxy;
|
private Mock<IProxyObject> proxy;
|
||||||
private RuntimeProxy sut;
|
private RuntimeProxy sut;
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
|
@ -38,10 +38,10 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
|
|
||||||
logger = new Mock<ILogger>();
|
logger = new Mock<ILogger>();
|
||||||
proxyObjectFactory = new Mock<IProxyObjectFactory>();
|
proxyObjectFactory = new Mock<IProxyObjectFactory>();
|
||||||
proxy = new Mock<ICommunication>();
|
proxy = new Mock<IProxyObject>();
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Opened);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
sut = new RuntimeProxy("net.pipe://random/address/here", proxyObjectFactory.Object, logger.Object);
|
sut = new RuntimeProxy("net.pipe://random/address/here", proxyObjectFactory.Object, logger.Object);
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
{
|
{
|
||||||
private Mock<ILogger> logger;
|
private Mock<ILogger> logger;
|
||||||
private Mock<IProxyObjectFactory> proxyObjectFactory;
|
private Mock<IProxyObjectFactory> proxyObjectFactory;
|
||||||
private Mock<ICommunication> proxy;
|
private Mock<IProxyObject> proxy;
|
||||||
private ServiceProxy sut;
|
private ServiceProxy sut;
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
|
@ -37,10 +37,10 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
||||||
|
|
||||||
logger = new Mock<ILogger>();
|
logger = new Mock<ILogger>();
|
||||||
proxyObjectFactory = new Mock<IProxyObjectFactory>();
|
proxyObjectFactory = new Mock<IProxyObjectFactory>();
|
||||||
proxy = new Mock<ICommunication>();
|
proxy = new Mock<IProxyObject>();
|
||||||
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>())).Returns(response);
|
||||||
proxy.As<ICommunicationObject>().Setup(o => o.State).Returns(CommunicationState.Opened);
|
proxy.Setup(o => o.State).Returns(CommunicationState.Opened);
|
||||||
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>())).Returns(proxy.Object);
|
||||||
|
|
||||||
sut = new ServiceProxy("net.pipe://random/address/here", proxyObjectFactory.Object, logger.Object);
|
sut = new ServiceProxy("net.pipe://random/address/here", proxyObjectFactory.Object, logger.Object);
|
||||||
|
|
|
@ -84,6 +84,8 @@
|
||||||
<Compile Include="Behaviour\OperationModel\I18nOperationTests.cs" />
|
<Compile Include="Behaviour\OperationModel\I18nOperationTests.cs" />
|
||||||
<Compile Include="Behaviour\OperationModel\DelegateOperationTests.cs" />
|
<Compile Include="Behaviour\OperationModel\DelegateOperationTests.cs" />
|
||||||
<Compile Include="Behaviour\OperationModel\OperationSequenceTests.cs" />
|
<Compile Include="Behaviour\OperationModel\OperationSequenceTests.cs" />
|
||||||
|
<Compile Include="Communication\Hosts\BaseHostImpl.cs" />
|
||||||
|
<Compile Include="Communication\Hosts\BaseHostTests.cs" />
|
||||||
<Compile Include="Communication\Proxies\BaseProxyImpl.cs" />
|
<Compile Include="Communication\Proxies\BaseProxyImpl.cs" />
|
||||||
<Compile Include="Communication\Proxies\BaseProxyTests.cs" />
|
<Compile Include="Communication\Proxies\BaseProxyTests.cs" />
|
||||||
<Compile Include="Communication\Proxies\ClientProxyTests.cs" />
|
<Compile Include="Communication\Proxies\ClientProxyTests.cs" />
|
||||||
|
|
|
@ -11,6 +11,7 @@ using System.ServiceModel;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
using SafeExamBrowser.Contracts.Communication.Data;
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Core.Communication.Hosts
|
namespace SafeExamBrowser.Core.Communication.Hosts
|
||||||
|
@ -25,7 +26,8 @@ namespace SafeExamBrowser.Core.Communication.Hosts
|
||||||
private readonly object @lock = new object();
|
private readonly object @lock = new object();
|
||||||
|
|
||||||
private string address;
|
private string address;
|
||||||
private ServiceHost host;
|
private IHostObject host;
|
||||||
|
private IHostObjectFactory factory;
|
||||||
private Thread hostThread;
|
private Thread hostThread;
|
||||||
|
|
||||||
protected Guid? CommunicationToken { get; private set; }
|
protected Guid? CommunicationToken { get; private set; }
|
||||||
|
@ -42,9 +44,10 @@ namespace SafeExamBrowser.Core.Communication.Hosts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseHost(string address, ILogger logger)
|
public BaseHost(string address, IHostObjectFactory factory, ILogger logger)
|
||||||
{
|
{
|
||||||
this.address = address;
|
this.address = address;
|
||||||
|
this.factory = factory;
|
||||||
this.Logger = logger;
|
this.Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +156,7 @@ namespace SafeExamBrowser.Core.Communication.Hosts
|
||||||
{
|
{
|
||||||
Logger.Debug($"Terminated communication host for endpoint '{address}'.");
|
Logger.Debug($"Terminated communication host for endpoint '{address}'.");
|
||||||
}
|
}
|
||||||
else
|
else if (exception != null)
|
||||||
{
|
{
|
||||||
throw new CommunicationException($"Failed to terminate communication host for endpoint '{address}'!", exception);
|
throw new CommunicationException($"Failed to terminate communication host for endpoint '{address}'!", exception);
|
||||||
}
|
}
|
||||||
|
@ -171,16 +174,15 @@ namespace SafeExamBrowser.Core.Communication.Hosts
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
host = new ServiceHost(this);
|
host = factory.CreateObject(address, this);
|
||||||
host.AddServiceEndpoint(typeof(ICommunication), new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), address);
|
|
||||||
host.Closed += Host_Closed;
|
host.Closed += Host_Closed;
|
||||||
host.Closing += Host_Closing;
|
host.Closing += Host_Closing;
|
||||||
host.Faulted += Host_Faulted;
|
host.Faulted += Host_Faulted;
|
||||||
host.Opened += Host_Opened;
|
host.Opened += Host_Opened;
|
||||||
host.Opening += Host_Opening;
|
host.Opening += Host_Opening;
|
||||||
host.UnknownMessageReceived += Host_UnknownMessageReceived;
|
|
||||||
host.Open();
|
|
||||||
|
|
||||||
|
host.Open();
|
||||||
Logger.Debug($"Successfully started communication host for endpoint '{address}'.");
|
Logger.Debug($"Successfully started communication host for endpoint '{address}'.");
|
||||||
|
|
||||||
startedEvent.Set();
|
startedEvent.Set();
|
||||||
|
@ -200,7 +202,7 @@ namespace SafeExamBrowser.Core.Communication.Hosts
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
host?.Close();
|
host?.Close();
|
||||||
success = hostThread.Join(TWO_SECONDS);
|
success = hostThread?.Join(TWO_SECONDS) == true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -236,11 +238,6 @@ namespace SafeExamBrowser.Core.Communication.Hosts
|
||||||
Logger.Debug("Communication host is opening...");
|
Logger.Debug("Communication host is opening...");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Host_UnknownMessageReceived(object sender, UnknownMessageReceivedEventArgs e)
|
|
||||||
{
|
|
||||||
Logger.Warn($"Communication host has received an unknown message: {e?.Message}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private string ToString(Message message)
|
private string ToString(Message message)
|
||||||
{
|
{
|
||||||
return message != null ? message.ToString() : "<null>";
|
return message != null ? message.ToString() : "<null>";
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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 SafeExamBrowser.Contracts.Communication;
|
||||||
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.Communication.Hosts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default implementation of the <see cref="IHostObjectFactory"/> utilizing WCF (<see cref="ServiceHost"/>).
|
||||||
|
/// </summary>
|
||||||
|
public class HostObjectFactory : IHostObjectFactory
|
||||||
|
{
|
||||||
|
public IHostObject CreateObject(string address, ICommunication communicationObject)
|
||||||
|
{
|
||||||
|
var host = new Host(communicationObject);
|
||||||
|
|
||||||
|
host.AddServiceEndpoint(typeof(ICommunication), new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), address);
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Host : ServiceHost, IHostObject
|
||||||
|
{
|
||||||
|
internal Host(object singletonInstance, params Uri[] baseAddresses) : base(singletonInstance, baseAddresses)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
private static readonly object @lock = new object();
|
private static readonly object @lock = new object();
|
||||||
|
|
||||||
private string address;
|
private string address;
|
||||||
private ICommunication proxy;
|
private IProxyObject proxy;
|
||||||
private IProxyObjectFactory factory;
|
private IProxyObjectFactory factory;
|
||||||
private Guid? communicationToken;
|
private Guid? communicationToken;
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
|
@ -43,19 +43,10 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
|
|
||||||
public virtual bool Connect(Guid? token = null, bool autoPing = true)
|
public virtual bool Connect(Guid? token = null, bool autoPing = true)
|
||||||
{
|
{
|
||||||
proxy = factory.CreateObject(address);
|
|
||||||
|
|
||||||
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)}...");
|
Logger.Debug($"Trying to connect to endpoint '{address}'{(token.HasValue ? $" with authentication token '{token}'" : string.Empty)}...");
|
||||||
|
|
||||||
|
InitializeProxyObject();
|
||||||
|
|
||||||
var response = proxy.Connect(token);
|
var response = proxy.Connect(token);
|
||||||
|
|
||||||
communicationToken = response.CommunicationToken;
|
communicationToken = response.CommunicationToken;
|
||||||
|
@ -160,13 +151,24 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// etrieves the string representation of the given <see cref="Response"/>, or indicates that a response is <c>null</c>.
|
/// Retrieves the string representation of the given <see cref="Response"/>, or indicates that a response is <c>null</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected string ToString(Response response)
|
protected string ToString(Response response)
|
||||||
{
|
{
|
||||||
return response != null ? response.ToString() : "<null>";
|
return response != null ? response.ToString() : "<null>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitializeProxyObject()
|
||||||
|
{
|
||||||
|
proxy = factory.CreateObject(address);
|
||||||
|
|
||||||
|
proxy.Closed += BaseProxy_Closed;
|
||||||
|
proxy.Closing += BaseProxy_Closing;
|
||||||
|
proxy.Faulted += BaseProxy_Faulted;
|
||||||
|
proxy.Opened += BaseProxy_Opened;
|
||||||
|
proxy.Opening += BaseProxy_Opening;
|
||||||
|
}
|
||||||
|
|
||||||
private void BaseProxy_Closed(object sender, EventArgs e)
|
private void BaseProxy_Closed(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Logger.Debug("Communication channel has been closed.");
|
Logger.Debug("Communication channel has been closed.");
|
||||||
|
@ -199,7 +201,7 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
throw new InvalidOperationException($"Cannot perform '{operationName}' before being connected to endpoint!");
|
throw new InvalidOperationException($"Cannot perform '{operationName}' before being connected to endpoint!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proxy == null || (proxy as ICommunicationObject)?.State != CommunicationState.Opened)
|
if (proxy == null || proxy.State != CommunicationState.Opened)
|
||||||
{
|
{
|
||||||
throw new CommunicationException($"Tried to perform {operationName}, but channel was {GetChannelState()}!");
|
throw new CommunicationException($"Tried to perform {operationName}, but channel was {GetChannelState()}!");
|
||||||
}
|
}
|
||||||
|
@ -207,7 +209,7 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
|
|
||||||
private string GetChannelState()
|
private string GetChannelState()
|
||||||
{
|
{
|
||||||
return proxy == null ? "null" : $"in state '{(proxy as ICommunicationObject)?.State}'";
|
return proxy == null ? "null" : $"in state '{proxy.State}'";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartAutoPing()
|
private void StartAutoPing()
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System.ServiceModel;
|
using System.ServiceModel;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Core.Communication.Proxies
|
namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
|
@ -17,10 +16,10 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProxyObjectFactory : IProxyObjectFactory
|
public class ProxyObjectFactory : IProxyObjectFactory
|
||||||
{
|
{
|
||||||
public ICommunication CreateObject(string address)
|
public IProxyObject CreateObject(string address)
|
||||||
{
|
{
|
||||||
var endpoint = new EndpointAddress(address);
|
var endpoint = new EndpointAddress(address);
|
||||||
var channel = ChannelFactory<ICommunication>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), endpoint);
|
var channel = ChannelFactory<IProxyObject>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport), endpoint);
|
||||||
|
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
<Compile Include="Behaviour\OperationModel\I18nOperation.cs" />
|
<Compile Include="Behaviour\OperationModel\I18nOperation.cs" />
|
||||||
<Compile Include="Behaviour\OperationModel\DelegateOperation.cs" />
|
<Compile Include="Behaviour\OperationModel\DelegateOperation.cs" />
|
||||||
<Compile Include="Behaviour\OperationModel\OperationSequence.cs" />
|
<Compile Include="Behaviour\OperationModel\OperationSequence.cs" />
|
||||||
|
<Compile Include="Communication\Hosts\HostObjectFactory.cs" />
|
||||||
<Compile Include="Communication\Proxies\BaseProxy.cs" />
|
<Compile Include="Communication\Proxies\BaseProxy.cs" />
|
||||||
<Compile Include="Communication\Hosts\BaseHost.cs" />
|
<Compile Include="Communication\Hosts\BaseHost.cs" />
|
||||||
<Compile Include="Communication\Proxies\ClientProxy.cs" />
|
<Compile Include="Communication\Proxies\ClientProxy.cs" />
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace SafeExamBrowser.Runtime.Communication
|
||||||
public event CommunicationEventHandler ReconfigurationRequested;
|
public event CommunicationEventHandler ReconfigurationRequested;
|
||||||
public event CommunicationEventHandler ShutdownRequested;
|
public event CommunicationEventHandler ShutdownRequested;
|
||||||
|
|
||||||
public RuntimeHost(string address, IConfigurationRepository configuration, ILogger logger) : base(address, logger)
|
public RuntimeHost(string address, IConfigurationRepository configuration, IHostObjectFactory factory, ILogger logger) : base(address, factory, logger)
|
||||||
{
|
{
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Core.Behaviour.OperationModel;
|
using SafeExamBrowser.Core.Behaviour.OperationModel;
|
||||||
|
using SafeExamBrowser.Core.Communication.Hosts;
|
||||||
using SafeExamBrowser.Core.Communication.Proxies;
|
using SafeExamBrowser.Core.Communication.Proxies;
|
||||||
using SafeExamBrowser.Core.I18n;
|
using SafeExamBrowser.Core.I18n;
|
||||||
using SafeExamBrowser.Core.Logging;
|
using SafeExamBrowser.Core.Logging;
|
||||||
|
@ -51,7 +52,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
var desktop = new Desktop(new ModuleLogger(logger, typeof(Desktop)));
|
var desktop = new Desktop(new ModuleLogger(logger, typeof(Desktop)));
|
||||||
var processFactory = new ProcessFactory(desktop, new ModuleLogger(logger, typeof(ProcessFactory)));
|
var processFactory = new ProcessFactory(desktop, new ModuleLogger(logger, typeof(ProcessFactory)));
|
||||||
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger);
|
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger);
|
||||||
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, configuration, new ModuleLogger(logger, typeof(RuntimeHost)));
|
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, configuration, new HostObjectFactory(), new ModuleLogger(logger, typeof(RuntimeHost)));
|
||||||
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ProxyObjectFactory(), 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 sessionController = new SessionController(configuration, logger, processFactory, proxyFactory, runtimeHost, serviceProxy);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue