SEBWIN-220: Moved exception handling to proxy implementations by introducing the CommunicationResult.
This commit is contained in:
parent
70f68abc8f
commit
c32028d3dd
24 changed files with 474 additions and 269 deletions
|
@ -101,21 +101,20 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
{
|
||||
RegisterEvents();
|
||||
|
||||
try
|
||||
var communication = runtime.InformClientReady();
|
||||
|
||||
if (communication.Success)
|
||||
{
|
||||
runtime.InformClientReady();
|
||||
splashScreen.Hide();
|
||||
|
||||
logger.Info("--- Application successfully initialized ---");
|
||||
logger.Log(string.Empty);
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
logger.Error("Failed to inform runtime that client is ready!", e);
|
||||
|
||||
return false;
|
||||
success = false;
|
||||
logger.Error("Failed to inform runtime that client is ready!");
|
||||
}
|
||||
|
||||
splashScreen.Hide();
|
||||
|
||||
logger.Info("--- Application successfully initialized ---");
|
||||
logger.Log(string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -227,14 +226,15 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
{
|
||||
if (success)
|
||||
{
|
||||
try
|
||||
var communication = runtime.RequestReconfiguration(filePath);
|
||||
|
||||
if (communication.Success)
|
||||
{
|
||||
runtime.RequestReconfiguration(filePath);
|
||||
logger.Info($"Sent reconfiguration request for '{filePath}' to the runtime.");
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
logger.Error($"Failed to communicate reconfiguration request for '{filePath}'!", e);
|
||||
logger.Error($"Failed to communicate reconfiguration request for '{filePath}'!");
|
||||
messageBox.Show(TextKey.MessageBox_ReconfigurationError, TextKey.MessageBox_ReconfigurationErrorTitle, icon: MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
@ -287,13 +287,11 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
var communication = runtime.RequestShutdown();
|
||||
|
||||
if (!communication.Success)
|
||||
{
|
||||
runtime.RequestShutdown();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to communicate shutdown request to the runtime!", e);
|
||||
logger.Error("Failed to communicate shutdown request to the runtime!");
|
||||
messageBox.Show(TextKey.MessageBox_QuitError, TextKey.MessageBox_QuitErrorTitle, icon: MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
|
|||
|
||||
try
|
||||
{
|
||||
var config = runtime.GetConfiguration();
|
||||
var communication = runtime.GetConfiguration();
|
||||
var config = communication.Value.Configuration;
|
||||
|
||||
configuration.AppConfig = config.AppConfig;
|
||||
configuration.SessionId = config.SessionId;
|
||||
|
|
|
@ -36,25 +36,18 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
|
|||
logger.Info("Initializing runtime connection...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeRuntimeConnection);
|
||||
|
||||
try
|
||||
{
|
||||
connected = runtime.Connect(token);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("An unexpected error occurred while trying to connect to the runtime!", e);
|
||||
}
|
||||
connected = runtime.Connect(token);
|
||||
|
||||
if (!connected)
|
||||
if (connected)
|
||||
{
|
||||
logger.Info("Successfully connected to the runtime.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error("Failed to connect to the runtime. Aborting startup...");
|
||||
|
||||
return OperationResult.Failed;
|
||||
}
|
||||
|
||||
logger.Info("Successfully connected to the runtime.");
|
||||
|
||||
return OperationResult.Success;
|
||||
return connected ? OperationResult.Success : OperationResult.Failed;
|
||||
}
|
||||
|
||||
public OperationResult Repeat()
|
||||
|
@ -69,13 +62,15 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
|
|||
|
||||
if (connected)
|
||||
{
|
||||
try
|
||||
var success = runtime.Disconnect();
|
||||
|
||||
if (success)
|
||||
{
|
||||
runtime.Disconnect();
|
||||
logger.Info("Successfully disconnected from the runtime.");
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
logger.Error("Failed to disconnect from runtime host!", e);
|
||||
logger.Error("Failed to disconnect from the runtime!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace SafeExamBrowser.Client
|
|||
operations.Enqueue(new I18nOperation(logger, text));
|
||||
operations.Enqueue(new RuntimeConnectionOperation(logger, runtimeProxy, startupToken));
|
||||
operations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeProxy));
|
||||
operations.Enqueue(new DelegateOperation(UpdateAppConfig));
|
||||
operations.Enqueue(new DelayedInitializationOperation(BuildCommunicationHostOperation));
|
||||
// TODO
|
||||
//operations.Enqueue(new DelayedInitializationOperation(BuildKeyboardInterceptorOperation));
|
||||
|
@ -202,9 +203,13 @@ namespace SafeExamBrowser.Client
|
|||
return operation;
|
||||
}
|
||||
|
||||
private void UpdateClientControllerDependencies()
|
||||
private void UpdateAppConfig()
|
||||
{
|
||||
ClientController.AppConfig = configuration.AppConfig;
|
||||
}
|
||||
|
||||
private void UpdateClientControllerDependencies()
|
||||
{
|
||||
ClientController.Browser = browserController;
|
||||
ClientController.ClientHost = clientHost;
|
||||
ClientController.SessionId = configuration.SessionId;
|
||||
|
|
|
@ -23,17 +23,14 @@ namespace SafeExamBrowser.Contracts.Communication
|
|||
event CommunicationEventHandler ConnectionLost;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to establish a connection. Returns <c>true</c> if the connection has been accepted, otherwise <c>false</c>. If a
|
||||
/// Tries to establish a connection. Returns <c>true</c> if the connection has been successful, otherwise <c>false</c>. If a
|
||||
/// connection was successfully established and the auto-ping flag is set, the connection status will be periodically checked.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
bool Connect(Guid? token = null, bool autoPing = true);
|
||||
|
||||
/// <summary>
|
||||
/// Terminates an open connection. Returns <c>true</c> if the disconnection has been acknowledged, otherwise <c>false</c>.
|
||||
/// Terminates an open connection. Returns <c>true</c> if the disconnection has been successful, otherwise <c>false</c>.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">If no connection has been established.</exception>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
bool Disconnect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.Proxies
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the result of a communication between an <see cref="ICommunicationProxy"/> and its <see cref="ICommunicationHost"/>.
|
||||
/// </summary>
|
||||
public class CommunicationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines whether the communication was successful or not.
|
||||
/// </summary>
|
||||
public bool Success { get; protected set; }
|
||||
|
||||
public CommunicationResult(bool success)
|
||||
{
|
||||
Success = success;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the result of a communication between an <see cref="ICommunicationProxy"/> and its <see cref="ICommunicationHost"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the expected response value.</typeparam>
|
||||
public class CommunicationResult<T> : CommunicationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The response value. Can be <c>null</c> or <c>default(T)</c> in case the communication has failed!
|
||||
/// </summary>
|
||||
public T Value { get; protected set; }
|
||||
|
||||
public CommunicationResult(bool success, T value) : base(success)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,24 +19,21 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
|||
/// <summary>
|
||||
/// Informs the client that the reconfiguration request for the specified file was denied.
|
||||
/// </summary>
|
||||
void InformReconfigurationDenied(string filePath);
|
||||
CommunicationResult InformReconfigurationDenied(string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// Instructs the client to initiate its shutdown procedure.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void InitiateShutdown();
|
||||
CommunicationResult InitiateShutdown();
|
||||
|
||||
/// <summary>
|
||||
/// Instructs the client to submit its authentication data.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
AuthenticationResponse RequestAuthentication();
|
||||
CommunicationResult<AuthenticationResponse> RequestAuthentication();
|
||||
|
||||
/// <summary>
|
||||
/// Requests the client to render a password dialog and subsequently return the interaction result as separate message.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void RequestPassword(PasswordRequestPurpose purpose, Guid requestId);
|
||||
CommunicationResult RequestPassword(PasswordRequestPurpose purpose, Guid requestId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Proxies
|
||||
{
|
||||
|
@ -19,32 +19,27 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
|||
/// <summary>
|
||||
/// Retrieves the application configuration from the runtime.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
ClientConfiguration GetConfiguration();
|
||||
CommunicationResult<ConfigurationResponse> GetConfiguration();
|
||||
|
||||
/// <summary>
|
||||
/// Informs the runtime that the client is ready.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void InformClientReady();
|
||||
CommunicationResult InformClientReady();
|
||||
|
||||
/// <summary>
|
||||
/// Requests the runtime to shut down the application.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void RequestShutdown();
|
||||
CommunicationResult RequestShutdown();
|
||||
|
||||
/// <summary>
|
||||
/// Requests the runtime to reconfigure the application with the specified configuration.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void RequestReconfiguration(string filePath);
|
||||
CommunicationResult RequestReconfiguration(string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// Submits the result of a password input previously requested by the runtime. If the procedure was aborted by the user,
|
||||
/// the password parameter will be <c>null</c>!
|
||||
/// </summary>
|
||||
/// /// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void SubmitPassword(Guid requestId, bool success, string password = null);
|
||||
CommunicationResult SubmitPassword(Guid requestId, bool success, string password = null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,11 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies
|
|||
/// <summary>
|
||||
/// Instructs the service to start a new session according to the given parameters.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void StartSession(Guid sessionId, Settings settings);
|
||||
CommunicationResult StartSession(Guid sessionId, Settings settings);
|
||||
|
||||
/// <summary>
|
||||
/// Instructs the service to stop the specified session.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
void StopSession(Guid sessionId);
|
||||
CommunicationResult StopSession(Guid sessionId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
<Compile Include="Communication\Hosts\IHostObject.cs" />
|
||||
<Compile Include="Communication\Hosts\IHostObjectFactory.cs" />
|
||||
<Compile Include="Communication\ICommunication.cs" />
|
||||
<Compile Include="Communication\Proxies\CommunicationResult.cs" />
|
||||
<Compile Include="Communication\Proxies\IClientProxy.cs" />
|
||||
<Compile Include="Communication\ICommunicationHost.cs" />
|
||||
<Compile Include="Communication\ICommunicationProxy.cs" />
|
||||
|
|
|
@ -106,14 +106,14 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void MustFailToDisconnectIfNotConnected()
|
||||
{
|
||||
sut.Disconnect();
|
||||
var success = sut.Disconnect();
|
||||
|
||||
Assert.IsFalse(success);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(CommunicationException))]
|
||||
public void MustFailToDisconnectIfChannelNotOpen()
|
||||
{
|
||||
var proxy = new Mock<IProxyObject>();
|
||||
|
@ -130,7 +130,10 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
var token = Guid.NewGuid();
|
||||
|
||||
sut.Connect(token);
|
||||
sut.Disconnect();
|
||||
|
||||
var success = sut.Disconnect();
|
||||
|
||||
Assert.IsFalse(success);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -141,7 +144,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(CommunicationException))]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void MustFailToSendIfChannelNotOpen()
|
||||
{
|
||||
var proxy = new Mock<IProxyObject>();
|
||||
|
|
|
@ -10,7 +10,6 @@ using System;
|
|||
using System.ServiceModel;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
@ -52,18 +51,20 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
{
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Shutdown))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged));
|
||||
|
||||
sut.InitiateShutdown();
|
||||
var communication = sut.InitiateShutdown();
|
||||
|
||||
proxy.Verify(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Shutdown)), Times.Once);
|
||||
Assert.IsTrue(communication.Success);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(CommunicationException))]
|
||||
public void MustFailIfShutdownCommandNotAcknowledged()
|
||||
public void MustIndicateIfShutdownCommandNotAcknowledged()
|
||||
{
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Shutdown))).Returns<Response>(null);
|
||||
|
||||
sut.InitiateShutdown();
|
||||
var communication = sut.InitiateShutdown();
|
||||
|
||||
Assert.IsFalse(communication.Success);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -71,20 +72,24 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
{
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Authenticate))).Returns(new AuthenticationResponse());
|
||||
|
||||
var response = sut.RequestAuthentication();
|
||||
var communication = sut.RequestAuthentication();
|
||||
var response = communication.Value;
|
||||
|
||||
proxy.Verify(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Authenticate)), Times.Once);
|
||||
|
||||
Assert.IsTrue(communication.Success);
|
||||
Assert.IsInstanceOfType(response, typeof(AuthenticationResponse));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(CommunicationException))]
|
||||
public void MustFailIfAuthenticationCommandNotFollowed()
|
||||
public void MustIndicateIfAuthenticationCommandNotAcknowledged()
|
||||
{
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.Authenticate))).Returns<Response>(null);
|
||||
|
||||
sut.RequestAuthentication();
|
||||
var communication = sut.RequestAuthentication();
|
||||
|
||||
Assert.AreEqual(default(AuthenticationResponse), communication.Value);
|
||||
Assert.IsFalse(communication.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,20 +57,23 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.ConfigurationNeeded))).Returns(response);
|
||||
|
||||
var configuration = sut.GetConfiguration();
|
||||
var communication = sut.GetConfiguration();
|
||||
var configuration = communication.Value.Configuration;
|
||||
|
||||
proxy.Verify(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.ConfigurationNeeded)), Times.Once);
|
||||
|
||||
Assert.IsTrue(communication.Success);
|
||||
Assert.IsInstanceOfType(configuration, typeof(ClientConfiguration));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(CommunicationException))]
|
||||
public void MustFailIfConfigurationNotRetrieved()
|
||||
{
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.ConfigurationNeeded))).Returns<Response>(null);
|
||||
|
||||
sut.GetConfiguration();
|
||||
var communication = sut.GetConfiguration();
|
||||
|
||||
Assert.IsFalse(communication.Success);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -78,18 +81,20 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
{
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.ClientIsReady))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged));
|
||||
|
||||
sut.InformClientReady();
|
||||
var communication = sut.InformClientReady();
|
||||
|
||||
Assert.IsTrue(communication.Success);
|
||||
proxy.Verify(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.ClientIsReady)), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(CommunicationException))]
|
||||
public void MustFailIfClientReadyNotAcknowledged()
|
||||
{
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.ClientIsReady))).Returns<Response>(null);
|
||||
|
||||
sut.InformClientReady();
|
||||
var communication = sut.InformClientReady();
|
||||
|
||||
Assert.IsFalse(communication.Success);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -99,20 +104,22 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
|
||||
proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationPath == url))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged));
|
||||
|
||||
sut.RequestReconfiguration(url);
|
||||
var communication = sut.RequestReconfiguration(url);
|
||||
|
||||
Assert.IsTrue(communication.Success);
|
||||
proxy.Verify(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationPath == url)), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(CommunicationException))]
|
||||
public void MustFailIfReconfigurationRequestNotAcknowledged()
|
||||
{
|
||||
var url = "file:///C:/Some/file/url.seb";
|
||||
|
||||
proxy.Setup(p => p.Send(It.Is<ReconfigurationMessage>(m => m.ConfigurationPath == url))).Returns<Response>(null);
|
||||
|
||||
sut.RequestReconfiguration(url);
|
||||
var communication = sut.RequestReconfiguration(url);
|
||||
|
||||
Assert.IsFalse(communication.Success);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -120,18 +127,20 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
{
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.RequestShutdown))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged));
|
||||
|
||||
sut.RequestShutdown();
|
||||
var communication = sut.RequestShutdown();
|
||||
|
||||
Assert.IsTrue(communication.Success);
|
||||
proxy.Verify(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.RequestShutdown)), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(CommunicationException))]
|
||||
public void MustFailIfShutdownRequestNotAcknowledged()
|
||||
{
|
||||
proxy.Setup(p => p.Send(It.Is<SimpleMessage>(m => m.Purport == SimpleMessagePurport.RequestShutdown))).Returns<Response>(null);
|
||||
|
||||
sut.RequestShutdown();
|
||||
var communication = sut.RequestShutdown();
|
||||
|
||||
Assert.IsFalse(communication.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ using System;
|
|||
using System.ServiceModel;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
@ -68,8 +67,10 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
public void MustIgnoreStartSessionIfUnavaiable()
|
||||
{
|
||||
sut.Ignore = true;
|
||||
sut.StartSession(Guid.Empty, null);
|
||||
|
||||
var communication = sut.StartSession(Guid.Empty, null);
|
||||
|
||||
Assert.IsTrue(communication.Success);
|
||||
proxy.Verify(p => p.Send(It.IsAny<Message>()), Times.Never);
|
||||
}
|
||||
|
||||
|
@ -77,8 +78,10 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies
|
|||
public void MustIgnoreStopSessionIfUnavaiable()
|
||||
{
|
||||
sut.Ignore = true;
|
||||
sut.StopSession(Guid.Empty);
|
||||
|
||||
var communication = sut.StopSession(Guid.Empty);
|
||||
|
||||
Assert.IsTrue(communication.Success);
|
||||
proxy.Verify(p => p.Send(It.IsAny<Message>()), Times.Never);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
|||
private Guid? communicationToken;
|
||||
private Timer timer;
|
||||
|
||||
protected bool IsConnected { get { return communicationToken.HasValue; } }
|
||||
protected ILogger Logger { get; private set; }
|
||||
|
||||
public event CommunicationEventHandler ConnectionLost;
|
||||
|
@ -44,50 +45,76 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
|||
|
||||
public virtual bool Connect(Guid? token = null, bool autoPing = true)
|
||||
{
|
||||
Logger.Debug($"Trying to connect to endpoint '{address}'{(token.HasValue ? $" with authentication token '{token}'" : string.Empty)}...");
|
||||
|
||||
InitializeProxyObject();
|
||||
|
||||
var response = proxy.Connect(token);
|
||||
|
||||
communicationToken = response.CommunicationToken;
|
||||
Logger.Debug($"Connection was {(response.ConnectionEstablished ? "established" : "refused")}.");
|
||||
|
||||
if (response.ConnectionEstablished && autoPing)
|
||||
try
|
||||
{
|
||||
StartAutoPing();
|
||||
}
|
||||
Logger.Debug($"Trying to connect to endpoint '{address}'{(token.HasValue ? $" with authentication token '{token}'" : string.Empty)}...");
|
||||
|
||||
return response.ConnectionEstablished;
|
||||
InitializeProxyObject();
|
||||
|
||||
var response = proxy.Connect(token);
|
||||
var success = response.ConnectionEstablished;
|
||||
|
||||
communicationToken = response.CommunicationToken;
|
||||
Logger.Debug($"Connection was {(success ? "established" : "refused")}.");
|
||||
|
||||
if (success && autoPing)
|
||||
{
|
||||
StartAutoPing();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to connect to endpoint '{address}'!", e);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Disconnect()
|
||||
{
|
||||
FailIfNotConnected(nameof(Disconnect));
|
||||
StopAutoPing();
|
||||
try
|
||||
{
|
||||
if (!IsConnected)
|
||||
{
|
||||
Logger.Warn($"Cannot disconnect from endpoint '{address}' before being connected!");
|
||||
|
||||
var message = new DisconnectionMessage { CommunicationToken = communicationToken.Value };
|
||||
var response = proxy.Disconnect(message);
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger.Debug($"{(response.ConnectionTerminated ? "Disconnected" : "Failed to disconnect")} from {address}.");
|
||||
StopAutoPing();
|
||||
|
||||
return response.ConnectionTerminated;
|
||||
var message = new DisconnectionMessage { CommunicationToken = communicationToken.Value };
|
||||
var response = proxy.Disconnect(message);
|
||||
var success = response.ConnectionTerminated;
|
||||
|
||||
Logger.Debug($"{(success ? "Disconnected" : "Failed to disconnect")} from {address}.");
|
||||
|
||||
if (success)
|
||||
{
|
||||
communicationToken = null;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to disconnect from endpoint '{address}'!", e);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the given message, optionally returning a response. If no response is expected, <c>null</c> will be returned.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException">If the given message is <c>null</c>.</exception>
|
||||
/// <exception cref="InvalidOperationException">If no connection has been established yet.</exception>
|
||||
/// <exception cref="System.ServiceModel.*">If the communication failed.</exception>
|
||||
/// <exception cref="InvalidOperationException">If no connection has been established yet or the connection is corrupted.</exception>
|
||||
protected virtual Response Send(Message message)
|
||||
{
|
||||
if (message is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
FailIfNotConnected(nameof(Send));
|
||||
FailIfNull(message);
|
||||
FailIfNotConnected();
|
||||
|
||||
message.CommunicationToken = communicationToken.Value;
|
||||
|
||||
|
@ -195,16 +222,24 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
|||
Logger.Debug("Communication channel is opening...");
|
||||
}
|
||||
|
||||
private void FailIfNotConnected(string operationName)
|
||||
private void FailIfNull(Message message)
|
||||
{
|
||||
if (!communicationToken.HasValue)
|
||||
if (message is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot perform '{operationName}' before being connected to endpoint!");
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
}
|
||||
|
||||
private void FailIfNotConnected()
|
||||
{
|
||||
if (!IsConnected)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot send message before being connected to endpoint '{address}'!");
|
||||
}
|
||||
|
||||
if (proxy == null || proxy.State != CommunicationState.Opened)
|
||||
{
|
||||
throw new CommunicationException($"Tried to perform {operationName}, but channel was {GetChannelState()}!");
|
||||
throw new InvalidOperationException($"Tried to send message, but channel was {GetChannelState()}!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
@ -23,45 +22,107 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
|||
{
|
||||
}
|
||||
|
||||
public void InformReconfigurationDenied(string filePath)
|
||||
public CommunicationResult InformReconfigurationDenied(string filePath)
|
||||
{
|
||||
var response = Send(new ReconfigurationDeniedMessage(filePath));
|
||||
|
||||
if (!IsAcknowledged(response))
|
||||
try
|
||||
{
|
||||
throw new CommunicationException($"Client did not acknowledge shutdown request! Received: {ToString(response)}.");
|
||||
var response = Send(new ReconfigurationDeniedMessage(filePath));
|
||||
var success = IsAcknowledged(response);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Logger.Debug("Client acknowledged reconfiguration denial.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Client did not acknowledge reconfiguration denial! Received: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return new CommunicationResult(success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to perform '{nameof(InformReconfigurationDenied)}'", e);
|
||||
|
||||
return new CommunicationResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void InitiateShutdown()
|
||||
public CommunicationResult InitiateShutdown()
|
||||
{
|
||||
var response = Send(SimpleMessagePurport.Shutdown);
|
||||
|
||||
if (!IsAcknowledged(response))
|
||||
try
|
||||
{
|
||||
throw new CommunicationException($"Client did not acknowledge shutdown request! Received: {ToString(response)}.");
|
||||
var response = Send(SimpleMessagePurport.Shutdown);
|
||||
var success = IsAcknowledged(response);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Logger.Debug("Client acknowledged shutdown request.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Client did not acknowledge shutdown request! Received: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return new CommunicationResult(success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to perform '{nameof(InitiateShutdown)}'", e);
|
||||
|
||||
return new CommunicationResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public AuthenticationResponse RequestAuthentication()
|
||||
public CommunicationResult<AuthenticationResponse> RequestAuthentication()
|
||||
{
|
||||
var response = Send(SimpleMessagePurport.Authenticate);
|
||||
|
||||
if (response is AuthenticationResponse authenticationResponse)
|
||||
try
|
||||
{
|
||||
return authenticationResponse;
|
||||
}
|
||||
var response = Send(SimpleMessagePurport.Authenticate);
|
||||
var success = response is AuthenticationResponse;
|
||||
|
||||
throw new CommunicationException($"Did not receive authentication response! Received: {ToString(response)}.");
|
||||
if (success)
|
||||
{
|
||||
Logger.Debug("Received authentication response.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Did not receive authentication response! Received: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return new CommunicationResult<AuthenticationResponse>(success, response as AuthenticationResponse);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to perform '{nameof(RequestAuthentication)}'", e);
|
||||
|
||||
return new CommunicationResult<AuthenticationResponse>(false, default(AuthenticationResponse));
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestPassword(PasswordRequestPurpose purpose, Guid requestId)
|
||||
public CommunicationResult RequestPassword(PasswordRequestPurpose purpose, Guid requestId)
|
||||
{
|
||||
var response = Send(new PasswordRequestMessage(purpose, requestId));
|
||||
|
||||
if (!IsAcknowledged(response))
|
||||
try
|
||||
{
|
||||
throw new CommunicationException($"Client did not acknowledge shutdown request! Received: {ToString(response)}.");
|
||||
var response = Send(new PasswordRequestMessage(purpose, requestId));
|
||||
var success = IsAcknowledged(response);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Logger.Debug("Client acknowledged password request.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Client did not acknowledge password request! Received: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return new CommunicationResult(success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to perform '{nameof(RequestPassword)}'", e);
|
||||
|
||||
return new CommunicationResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Data;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication.Proxies
|
||||
|
@ -24,55 +22,133 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
|||
{
|
||||
}
|
||||
|
||||
public ClientConfiguration GetConfiguration()
|
||||
public CommunicationResult<ConfigurationResponse> GetConfiguration()
|
||||
{
|
||||
var response = Send(SimpleMessagePurport.ConfigurationNeeded);
|
||||
|
||||
if (response is ConfigurationResponse configurationResponse)
|
||||
try
|
||||
{
|
||||
return configurationResponse.Configuration;
|
||||
var response = Send(SimpleMessagePurport.ConfigurationNeeded);
|
||||
var success = response is ConfigurationResponse;
|
||||
|
||||
if (success)
|
||||
{
|
||||
Logger.Debug("Received configuration response.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Did not retrieve configuration response! Received: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return new CommunicationResult<ConfigurationResponse>(success, response as ConfigurationResponse);
|
||||
}
|
||||
|
||||
throw new CommunicationException($"Could not retrieve client configuration! Received: {ToString(response)}.");
|
||||
}
|
||||
|
||||
public void InformClientReady()
|
||||
{
|
||||
var response = Send(SimpleMessagePurport.ClientIsReady);
|
||||
|
||||
if (!IsAcknowledged(response))
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new CommunicationException($"Runtime did not acknowledge that client is ready! Response: {ToString(response)}.");
|
||||
Logger.Error($"Failed to perform '{nameof(GetConfiguration)}'", e);
|
||||
|
||||
return new CommunicationResult<ConfigurationResponse>(false, default(ConfigurationResponse));
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestReconfiguration(string filePath)
|
||||
public CommunicationResult InformClientReady()
|
||||
{
|
||||
var response = Send(new ReconfigurationMessage(filePath));
|
||||
|
||||
if (!IsAcknowledged(response))
|
||||
try
|
||||
{
|
||||
throw new CommunicationException($"Runtime did not acknowledge reconfiguration request! Response: {ToString(response)}.");
|
||||
var response = Send(SimpleMessagePurport.ClientIsReady);
|
||||
var success = IsAcknowledged(response);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Logger.Debug("Runtime acknowledged that the client is ready.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Runtime did not acknowledge that the client is ready! Response: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return new CommunicationResult(success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to perform '{nameof(InformClientReady)}'", e);
|
||||
|
||||
return new CommunicationResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestShutdown()
|
||||
public CommunicationResult RequestReconfiguration(string filePath)
|
||||
{
|
||||
var response = Send(SimpleMessagePurport.RequestShutdown);
|
||||
|
||||
if (!IsAcknowledged(response))
|
||||
try
|
||||
{
|
||||
throw new CommunicationException($"Runtime did not acknowledge shutdown request! Response: {ToString(response)}.");
|
||||
var response = Send(new ReconfigurationMessage(filePath));
|
||||
var success = IsAcknowledged(response);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Logger.Debug("Runtime acknowledged reconfiguration request.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Runtime did not acknowledge reconfiguration request! Response: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return new CommunicationResult(success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to perform '{nameof(RequestReconfiguration)}'", e);
|
||||
|
||||
return new CommunicationResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void SubmitPassword(Guid requestId, bool success, string password = null)
|
||||
public CommunicationResult RequestShutdown()
|
||||
{
|
||||
var response = Send(new PasswordReplyMessage(requestId, success, password));
|
||||
|
||||
if (!IsAcknowledged(response))
|
||||
try
|
||||
{
|
||||
throw new CommunicationException($"Runtime did not acknowledge password submission! Response: {ToString(response)}.");
|
||||
var response = Send(SimpleMessagePurport.RequestShutdown);
|
||||
var success = IsAcknowledged(response);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Logger.Debug("Runtime acknowledged shutdown request.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Runtime did not acknowledge shutdown request! Response: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return new CommunicationResult(success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to perform '{nameof(RequestShutdown)}'", e);
|
||||
|
||||
return new CommunicationResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public CommunicationResult SubmitPassword(Guid requestId, bool success, string password = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = Send(new PasswordReplyMessage(requestId, success, password));
|
||||
var acknowledged = IsAcknowledged(response);
|
||||
|
||||
if (acknowledged)
|
||||
{
|
||||
Logger.Debug("Runtime acknowledged password transmission.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Runtime did not acknowledge password transmission! Response: {ToString(response)}.");
|
||||
}
|
||||
|
||||
return new CommunicationResult(acknowledged);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to perform '{nameof(SubmitPassword)}'", e);
|
||||
|
||||
return new CommunicationResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,32 +38,36 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
|||
{
|
||||
if (IgnoreOperation(nameof(Disconnect)))
|
||||
{
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.Disconnect();
|
||||
}
|
||||
|
||||
public void StartSession(Guid sessionId, Settings settings)
|
||||
public CommunicationResult StartSession(Guid sessionId, Settings settings)
|
||||
{
|
||||
if (IgnoreOperation(nameof(StartSession)))
|
||||
{
|
||||
return;
|
||||
return new CommunicationResult(true);
|
||||
}
|
||||
|
||||
// TODO: Implement service communication
|
||||
// Send(new StartSessionMessage { Id = sessionId, Settings = settings });
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void StopSession(Guid sessionId)
|
||||
public CommunicationResult StopSession(Guid sessionId)
|
||||
{
|
||||
if (IgnoreOperation(nameof(StopSession)))
|
||||
{
|
||||
return;
|
||||
return new CommunicationResult(true);
|
||||
}
|
||||
|
||||
// TODO: Implement service communication
|
||||
// Send(new StopSessionMessage { SessionId = sessionId });
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private bool IgnoreOperation(string operationName)
|
||||
|
|
|
@ -67,10 +67,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
var result = default(OperationResult);
|
||||
var response = new AuthenticationResponse { ProcessId = 1234 };
|
||||
var communication = new CommunicationResult<AuthenticationResponse>(true, response);
|
||||
|
||||
process.SetupGet(p => p.Id).Returns(response.ProcessId);
|
||||
processFactory.Setup(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>())).Returns(process.Object).Callback(clientReady);
|
||||
proxy.Setup(p => p.RequestAuthentication()).Returns(response);
|
||||
proxy.Setup(p => p.RequestAuthentication()).Returns(communication);
|
||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), true)).Returns(true);
|
||||
|
||||
result = sut.Perform();
|
||||
|
@ -86,10 +87,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
var result = default(OperationResult);
|
||||
var response = new AuthenticationResponse { ProcessId = 1234 };
|
||||
var communication = new CommunicationResult<AuthenticationResponse>(true, response);
|
||||
|
||||
process.SetupGet(p => p.Id).Returns(response.ProcessId);
|
||||
processFactory.Setup(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>())).Returns(process.Object).Callback(clientReady);
|
||||
proxy.Setup(p => p.RequestAuthentication()).Returns(response);
|
||||
proxy.Setup(p => p.RequestAuthentication()).Returns(communication);
|
||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), true)).Returns(true);
|
||||
|
||||
result = sut.Repeat();
|
||||
|
@ -134,10 +136,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
{
|
||||
var result = default(OperationResult);
|
||||
var response = new AuthenticationResponse { ProcessId = -1 };
|
||||
var communication = new CommunicationResult<AuthenticationResponse>(true, response);
|
||||
|
||||
process.SetupGet(p => p.Id).Returns(1234);
|
||||
processFactory.Setup(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>())).Returns(process.Object).Callback(clientReady);
|
||||
proxy.Setup(p => p.RequestAuthentication()).Returns(response);
|
||||
proxy.Setup(p => p.RequestAuthentication()).Returns(communication);
|
||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), true)).Returns(true);
|
||||
|
||||
result = sut.Perform();
|
||||
|
@ -204,10 +207,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
private void PerformNormally()
|
||||
{
|
||||
var response = new AuthenticationResponse { ProcessId = 1234 };
|
||||
var communication = new CommunicationResult<AuthenticationResponse>(true, response);
|
||||
|
||||
process.SetupGet(p => p.Id).Returns(response.ProcessId);
|
||||
processFactory.Setup(f => f.StartNew(It.IsAny<string>(), It.IsAny<string[]>())).Returns(process.Object).Callback(clientReady);
|
||||
proxy.Setup(p => p.RequestAuthentication()).Returns(response);
|
||||
proxy.Setup(p => p.RequestAuthentication()).Returns(communication);
|
||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), true)).Returns(true);
|
||||
|
||||
sut.Perform();
|
||||
|
|
|
@ -335,6 +335,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public void MustRequestPasswordViaClientDuringReconfigurationOnNewDesktop()
|
||||
{
|
||||
var clientProxy = new Mock<IClientProxy>();
|
||||
var communication = new CommunicationResult(true);
|
||||
var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
||||
{
|
||||
runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordReplyEventArgs { RequestId = id, Success = true });
|
||||
|
@ -342,7 +343,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
var session = new Mock<ISessionData>();
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
clientProxy.Setup(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>())).Callback(passwordReceived);
|
||||
clientProxy.Setup(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>())).Returns(communication).Callback(passwordReceived);
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(new PasswordDialogResultStub { Success = true });
|
||||
repository.SetupGet(r => r.CurrentSession).Returns(session.Object);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
|
@ -361,6 +362,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public void MustAbortAskingForPasswordViaClientIfDecidedByUser()
|
||||
{
|
||||
var clientProxy = new Mock<IClientProxy>();
|
||||
var communication = new CommunicationResult(true);
|
||||
var passwordReceived = new Action<PasswordRequestPurpose, Guid>((p, id) =>
|
||||
{
|
||||
runtimeHost.Raise(r => r.PasswordReceived += null, new PasswordReplyEventArgs { RequestId = id, Success = false });
|
||||
|
@ -368,8 +370,28 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
var session = new Mock<ISessionData>();
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
clientProxy.Setup(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>())).Callback(passwordReceived);
|
||||
passwordDialog.Setup(d => d.Show(null)).Returns(new PasswordDialogResultStub { Success = true });
|
||||
clientProxy.Setup(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>())).Returns(communication).Callback(passwordReceived);
|
||||
repository.SetupGet(r => r.CurrentSession).Returns(session.Object);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object);
|
||||
settings.KioskMode = KioskMode.CreateNewDesktop;
|
||||
|
||||
sut = new ConfigurationOperation(appConfig, repository.Object, logger.Object, messageBox.Object, resourceLoader.Object, runtimeHost.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", url });
|
||||
|
||||
var result = sut.Perform();
|
||||
|
||||
Assert.AreEqual(OperationResult.Aborted, result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotWaitForPasswordViaClientIfCommunicationHasFailed()
|
||||
{
|
||||
var clientProxy = new Mock<IClientProxy>();
|
||||
var communication = new CommunicationResult(false);
|
||||
var session = new Mock<ISessionData>();
|
||||
var url = @"http://www.safeexambrowser.org/whatever.seb";
|
||||
|
||||
clientProxy.Setup(c => c.RequestPassword(It.IsAny<PasswordRequestPurpose>(), It.IsAny<Guid>())).Returns(communication);
|
||||
repository.SetupGet(r => r.CurrentSession).Returns(session.Object);
|
||||
repository.Setup(r => r.LoadSettings(It.IsAny<Uri>(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded);
|
||||
session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object);
|
||||
|
|
|
@ -97,16 +97,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect(null, true)).Throws<Exception>();
|
||||
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect(null, true)).Throws<Exception>();
|
||||
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
|
||||
|
||||
sut.Perform();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -177,7 +167,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
public void MustNotFailWhenDisconnecting()
|
||||
{
|
||||
service.Setup(s => s.Connect(null, true)).Returns(true);
|
||||
service.Setup(s => s.Disconnect()).Throws<Exception>();
|
||||
service.Setup(s => s.Disconnect()).Returns(false);
|
||||
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
|
||||
|
||||
sut.Perform();
|
||||
|
@ -201,18 +191,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect(null, true)).Throws<Exception>();
|
||||
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory });
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect(null, true)).Throws<Exception>();
|
||||
configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional });
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Verify(s => s.Disconnect(), Times.Never);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,9 +120,10 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
|
||||
logger.Info("Connection with client has been established. Requesting authentication...");
|
||||
|
||||
var response = ClientProxy.RequestAuthentication();
|
||||
var communication = ClientProxy.RequestAuthentication();
|
||||
var response = communication.Value;
|
||||
|
||||
if (ClientProcess.Id != response?.ProcessId)
|
||||
if (!communication.Success || ClientProcess.Id != response?.ProcessId)
|
||||
{
|
||||
logger.Error("Failed to verify client integrity!");
|
||||
|
||||
|
|
|
@ -172,17 +172,11 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
var title = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequiredTitle : TextKey.PasswordDialog_SettingsPasswordRequiredTitle;
|
||||
var dialog = uiFactory.CreatePasswordDialog(text.Get(message), text.Get(title));
|
||||
var result = dialog.Show();
|
||||
var success = result.Success;
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
password = result.Password;
|
||||
}
|
||||
else
|
||||
{
|
||||
password = default(string);
|
||||
}
|
||||
password = success ? result.Password : default(string);
|
||||
|
||||
return result.Success;
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TryGetPasswordViaClient(PasswordRequestPurpose purpose, out string password)
|
||||
|
@ -200,20 +194,20 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
});
|
||||
|
||||
runtimeHost.PasswordReceived += responseEventHandler;
|
||||
configuration.CurrentSession.ClientProxy.RequestPassword(purpose, requestId);
|
||||
responseEvent.WaitOne();
|
||||
|
||||
var communication = configuration.CurrentSession.ClientProxy.RequestPassword(purpose, requestId);
|
||||
|
||||
if (communication.Success)
|
||||
{
|
||||
responseEvent.WaitOne();
|
||||
}
|
||||
|
||||
var success = response?.Success == true;
|
||||
|
||||
runtimeHost.PasswordReceived -= responseEventHandler;
|
||||
password = success ? response.Password : default(string);
|
||||
|
||||
if (response.Success)
|
||||
{
|
||||
password = response.Password;
|
||||
}
|
||||
else
|
||||
{
|
||||
password = default(string);
|
||||
}
|
||||
|
||||
return response.Success;
|
||||
return success;
|
||||
}
|
||||
|
||||
private void HandleInvalidData(ref LoadStatus status, Uri uri)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Behaviour.OperationModel;
|
||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
@ -40,15 +39,8 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
logger.Info($"Initializing service session...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeServiceSession);
|
||||
|
||||
try
|
||||
{
|
||||
mandatory = configuration.CurrentSettings.ServicePolicy == ServicePolicy.Mandatory;
|
||||
connected = service.Connect();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogException(e);
|
||||
}
|
||||
mandatory = configuration.CurrentSettings.ServicePolicy == ServicePolicy.Mandatory;
|
||||
connected = service.Connect();
|
||||
|
||||
if (mandatory && !connected)
|
||||
{
|
||||
|
@ -89,13 +81,15 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
{
|
||||
StopServiceSession();
|
||||
|
||||
try
|
||||
var success = service.Disconnect();
|
||||
|
||||
if (success)
|
||||
{
|
||||
service.Disconnect();
|
||||
logger.Info("Successfully disconnected from the service.");
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
logger.Error("Failed to disconnect from the service!", e);
|
||||
logger.Error("Failed to disconnect from the service!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,19 +103,5 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
{
|
||||
service.StopSession(configuration.CurrentSession.Id);
|
||||
}
|
||||
|
||||
private void LogException(Exception e)
|
||||
{
|
||||
var message = "Failed to connect to the service component!";
|
||||
|
||||
if (mandatory)
|
||||
{
|
||||
logger.Error(message, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info($"{message} Reason: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue