SEBWIN-220: Introduced timeout for startup and shutdown of BaseHost.
This commit is contained in:
parent
86d6949a6f
commit
c8001e85f6
10 changed files with 31 additions and 19 deletions
|
@ -40,7 +40,7 @@ namespace SafeExamBrowser.Client.UnitTests.Communication
|
||||||
|
|
||||||
hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object);
|
hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object);
|
||||||
|
|
||||||
sut = new ClientHost("net:pipe://some/address", hostObjectFactory.Object, logger.Object, PROCESS_ID);
|
sut = new ClientHost("net:pipe://some/address", hostObjectFactory.Object, logger.Object, PROCESS_ID, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
clientHost.VerifyNoOtherCalls();
|
clientHost.VerifyNoOtherCalls();
|
||||||
|
|
||||||
Assert.IsFalse(stopWatch.IsRunning);
|
Assert.IsFalse(stopWatch.IsRunning);
|
||||||
Assert.IsTrue(stopWatch.ElapsedMilliseconds > timeout_ms);
|
Assert.IsTrue(stopWatch.ElapsedMilliseconds >= timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
|
@ -28,7 +28,12 @@ namespace SafeExamBrowser.Client.Communication
|
||||||
public event CommunicationEventHandler RuntimeDisconnected;
|
public event CommunicationEventHandler RuntimeDisconnected;
|
||||||
public event CommunicationEventHandler Shutdown;
|
public event CommunicationEventHandler Shutdown;
|
||||||
|
|
||||||
public ClientHost(string address, IHostObjectFactory factory, ILogger logger, int processId) : base(address, factory, logger)
|
public ClientHost(
|
||||||
|
string address,
|
||||||
|
IHostObjectFactory factory,
|
||||||
|
ILogger logger,
|
||||||
|
int processId,
|
||||||
|
int timeout_ms) : base(address, factory, logger, timeout_ms)
|
||||||
{
|
{
|
||||||
this.processId = processId;
|
this.processId = processId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,9 +180,10 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
private IOperation BuildClientHostOperation()
|
private IOperation BuildClientHostOperation()
|
||||||
{
|
{
|
||||||
|
const int FIVE_SECONDS = 5000;
|
||||||
var processId = Process.GetCurrentProcess().Id;
|
var processId = Process.GetCurrentProcess().Id;
|
||||||
var factory = new HostObjectFactory();
|
var factory = new HostObjectFactory();
|
||||||
var host = new ClientHost(configuration.AppConfig.ClientAddress, factory, new ModuleLogger(logger, nameof(ClientHost)), processId);
|
var host = new ClientHost(configuration.AppConfig.ClientAddress, factory, new ModuleLogger(logger, nameof(ClientHost)), processId, FIVE_SECONDS);
|
||||||
var operation = new CommunicationHostOperation(host, logger);
|
var operation = new CommunicationHostOperation(host, logger);
|
||||||
|
|
||||||
clientHost = host;
|
clientHost = host;
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace SafeExamBrowser.Communication.UnitTests.Hosts
|
||||||
public Func<Message, Response> OnReceiveStub { get; set; }
|
public Func<Message, Response> OnReceiveStub { get; set; }
|
||||||
public Func<SimpleMessagePurport, Response> OnReceiveSimpleMessageStub { get; set; }
|
public Func<SimpleMessagePurport, Response> OnReceiveSimpleMessageStub { get; set; }
|
||||||
|
|
||||||
public BaseHostStub(string address, IHostObjectFactory factory, ILogger logger) : base(address, factory, logger)
|
public BaseHostStub(string address, IHostObjectFactory factory, ILogger logger, int timeout_ms) : base(address, factory, logger, timeout_ms)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace SafeExamBrowser.Communication.UnitTests.Hosts
|
||||||
|
|
||||||
hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object);
|
hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object);
|
||||||
|
|
||||||
sut = new BaseHostStub("net.pipe://some/address/here", hostObjectFactory.Object, logger.Object);
|
sut = new BaseHostStub("net.pipe://some/address/here", hostObjectFactory.Object, logger.Object, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -56,7 +56,6 @@ namespace SafeExamBrowser.Communication.UnitTests.Hosts
|
||||||
[ExpectedException(typeof(CommunicationException))]
|
[ExpectedException(typeof(CommunicationException))]
|
||||||
public void MustCorrectlyHandleStartupException()
|
public void MustCorrectlyHandleStartupException()
|
||||||
{
|
{
|
||||||
// TODO: Takes waaay too long, extract timeout (move to constructor like in ClientOperation)!
|
|
||||||
hostObject.Setup(h => h.Open()).Throws<Exception>();
|
hostObject.Setup(h => h.Open()).Throws<Exception>();
|
||||||
|
|
||||||
sut.Start();
|
sut.Start();
|
||||||
|
|
|
@ -22,13 +22,13 @@ namespace SafeExamBrowser.Communication.Hosts
|
||||||
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
|
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
|
||||||
public abstract class BaseHost : ICommunication, ICommunicationHost
|
public abstract class BaseHost : ICommunication, ICommunicationHost
|
||||||
{
|
{
|
||||||
private const int FIVE_SECONDS = 5000;
|
|
||||||
private readonly object @lock = new object();
|
private readonly object @lock = new object();
|
||||||
|
|
||||||
private string address;
|
private string address;
|
||||||
private IHostObject host;
|
private IHostObject host;
|
||||||
private IHostObjectFactory factory;
|
private IHostObjectFactory factory;
|
||||||
private Thread hostThread;
|
private Thread hostThread;
|
||||||
|
private int timeout_ms;
|
||||||
|
|
||||||
protected Guid? CommunicationToken { get; private set; }
|
protected Guid? CommunicationToken { get; private set; }
|
||||||
protected ILogger Logger { get; private set; }
|
protected ILogger Logger { get; private set; }
|
||||||
|
@ -44,11 +44,12 @@ namespace SafeExamBrowser.Communication.Hosts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseHost(string address, IHostObjectFactory factory, ILogger logger)
|
public BaseHost(string address, IHostObjectFactory factory, ILogger logger, int timeout_ms)
|
||||||
{
|
{
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
this.Logger = logger;
|
this.Logger = logger;
|
||||||
|
this.timeout_ms = timeout_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract bool OnConnect(Guid? token);
|
protected abstract bool OnConnect(Guid? token);
|
||||||
|
@ -137,11 +138,11 @@ namespace SafeExamBrowser.Communication.Hosts
|
||||||
hostThread.IsBackground = true;
|
hostThread.IsBackground = true;
|
||||||
hostThread.Start();
|
hostThread.Start();
|
||||||
|
|
||||||
var success = startedEvent.WaitOne(FIVE_SECONDS);
|
var success = startedEvent.WaitOne(timeout_ms);
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
throw new CommunicationException($"Failed to start communication host for endpoint '{address}' within {FIVE_SECONDS / 1000} seconds!", exception);
|
throw new CommunicationException($"Failed to start communication host for endpoint '{address}' within {timeout_ms / 1000} seconds!", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,7 +203,7 @@ namespace SafeExamBrowser.Communication.Hosts
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
host?.Close();
|
host?.Close();
|
||||||
success = hostThread?.Join(FIVE_SECONDS) == true;
|
success = hostThread?.Join(timeout_ms) == true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Communication
|
||||||
|
|
||||||
hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object);
|
hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object);
|
||||||
|
|
||||||
sut = new RuntimeHost("net:pipe://some/address", configuration.Object, hostObjectFactory.Object, logger.Object);
|
sut = new RuntimeHost("net:pipe://some/address", configuration.Object, hostObjectFactory.Object, logger.Object, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
|
@ -7,12 +7,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using SafeExamBrowser.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Communication.Data;
|
using SafeExamBrowser.Contracts.Communication.Data;
|
||||||
using SafeExamBrowser.Contracts.Communication.Events;
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Communication.Hosts;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Communication
|
namespace SafeExamBrowser.Runtime.Communication
|
||||||
{
|
{
|
||||||
|
@ -29,7 +29,12 @@ namespace SafeExamBrowser.Runtime.Communication
|
||||||
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
public event CommunicationEventHandler<ReconfigurationEventArgs> ReconfigurationRequested;
|
||||||
public event CommunicationEventHandler ShutdownRequested;
|
public event CommunicationEventHandler ShutdownRequested;
|
||||||
|
|
||||||
public RuntimeHost(string address, IConfigurationRepository configuration, IHostObjectFactory factory, ILogger logger) : base(address, factory, logger)
|
public RuntimeHost(
|
||||||
|
string address,
|
||||||
|
IConfigurationRepository configuration,
|
||||||
|
IHostObjectFactory factory,
|
||||||
|
ILogger logger,
|
||||||
|
int timeout_ms) : base(address, factory, logger, timeout_ms)
|
||||||
{
|
{
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,8 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
internal void BuildObjectGraph(Action shutdown)
|
internal void BuildObjectGraph(Action shutdown)
|
||||||
{
|
{
|
||||||
const int STARTUP_TIMEOUT_MS = 15000;
|
const int FIVE_SECONDS = 5000;
|
||||||
|
const int FIFTEEN_SECONDS = 15000;
|
||||||
|
|
||||||
var args = Environment.GetCommandLineArgs();
|
var args = Environment.GetCommandLineArgs();
|
||||||
var configuration = BuildConfigurationRepository();
|
var configuration = BuildConfigurationRepository();
|
||||||
|
@ -60,7 +61,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
var processFactory = new ProcessFactory(new ModuleLogger(logger, nameof(ProcessFactory)));
|
var processFactory = new ProcessFactory(new ModuleLogger(logger, nameof(ProcessFactory)));
|
||||||
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger);
|
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger);
|
||||||
var resourceLoader = new ResourceLoader();
|
var resourceLoader = new ResourceLoader();
|
||||||
var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, configuration, new HostObjectFactory(), new ModuleLogger(logger, nameof(RuntimeHost)));
|
var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, configuration, new HostObjectFactory(), new ModuleLogger(logger, nameof(RuntimeHost)), FIVE_SECONDS);
|
||||||
var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(ServiceProxy)));
|
var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(ServiceProxy)));
|
||||||
var uiFactory = new UserInterfaceFactory(text);
|
var uiFactory = new UserInterfaceFactory(text);
|
||||||
|
|
||||||
|
@ -73,9 +74,9 @@ namespace SafeExamBrowser.Runtime
|
||||||
sessionOperations.Enqueue(new ConfigurationOperation(appConfig, configuration, logger, messageBox, resourceLoader, runtimeHost, text, uiFactory, args));
|
sessionOperations.Enqueue(new ConfigurationOperation(appConfig, configuration, logger, messageBox, resourceLoader, runtimeHost, text, uiFactory, args));
|
||||||
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
|
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
|
||||||
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
|
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
|
||||||
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, STARTUP_TIMEOUT_MS));
|
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, FIFTEEN_SECONDS));
|
||||||
sessionOperations.Enqueue(new KioskModeOperation(configuration, desktopFactory, explorerShell, logger, processFactory));
|
sessionOperations.Enqueue(new KioskModeOperation(configuration, desktopFactory, explorerShell, logger, processFactory));
|
||||||
sessionOperations.Enqueue(new ClientOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, STARTUP_TIMEOUT_MS));
|
sessionOperations.Enqueue(new ClientOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, FIFTEEN_SECONDS));
|
||||||
|
|
||||||
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||||
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
||||||
|
|
Loading…
Reference in a new issue