From c32028d3dd6030001324f338be2a39ebb91c91c3 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Fri, 10 Aug 2018 13:23:24 +0200 Subject: [PATCH] SEBWIN-220: Moved exception handling to proxy implementations by introducing the CommunicationResult. --- .../Behaviour/ClientController.cs | 40 +++-- .../Operations/ConfigurationOperation.cs | 3 +- .../Operations/RuntimeConnectionOperation.cs | 31 ++-- SafeExamBrowser.Client/CompositionRoot.cs | 7 +- .../Communication/ICommunicationProxy.cs | 7 +- .../Proxies/CommunicationResult.cs | 43 ++++++ .../Communication/Proxies/IClientProxy.cs | 11 +- .../Communication/Proxies/IRuntimeProxy.cs | 17 +-- .../Communication/Proxies/IServiceProxy.cs | 6 +- .../SafeExamBrowser.Contracts.csproj | 1 + .../Communication/Proxies/BaseProxyTests.cs | 13 +- .../Communication/Proxies/ClientProxyTests.cs | 23 +-- .../Proxies/RuntimeProxyTests.cs | 33 +++-- .../Proxies/ServiceProxyTests.cs | 9 +- .../Communication/Proxies/BaseProxy.cs | 97 ++++++++---- .../Communication/Proxies/ClientProxy.cs | 107 ++++++++++--- .../Communication/Proxies/RuntimeProxy.cs | 140 ++++++++++++++---- .../Communication/Proxies/ServiceProxy.cs | 14 +- .../Operations/ClientOperationTests.cs | 12 +- .../Operations/ConfigurationOperationTests.cs | 28 +++- .../Operations/ServiceOperationTests.cs | 24 +-- .../Behaviour/Operations/ClientOperation.cs | 5 +- .../Operations/ConfigurationOperation.cs | 36 ++--- .../Behaviour/Operations/ServiceOperation.cs | 36 +---- 24 files changed, 474 insertions(+), 269 deletions(-) create mode 100644 SafeExamBrowser.Contracts/Communication/Proxies/CommunicationResult.cs diff --git a/SafeExamBrowser.Client/Behaviour/ClientController.cs b/SafeExamBrowser.Client/Behaviour/ClientController.cs index f5935e94..c17bcbe6 100644 --- a/SafeExamBrowser.Client/Behaviour/ClientController.cs +++ b/SafeExamBrowser.Client/Behaviour/ClientController.cs @@ -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); } } diff --git a/SafeExamBrowser.Client/Behaviour/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/ConfigurationOperation.cs index 520cca18..f308deb7 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/ConfigurationOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/ConfigurationOperation.cs @@ -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; diff --git a/SafeExamBrowser.Client/Behaviour/Operations/RuntimeConnectionOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/RuntimeConnectionOperation.cs index d0a7a3c9..d4f4daee 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/RuntimeConnectionOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/RuntimeConnectionOperation.cs @@ -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!"); } } } diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 7a6c495f..f6905150 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -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; diff --git a/SafeExamBrowser.Contracts/Communication/ICommunicationProxy.cs b/SafeExamBrowser.Contracts/Communication/ICommunicationProxy.cs index 510d2ded..665adb50 100644 --- a/SafeExamBrowser.Contracts/Communication/ICommunicationProxy.cs +++ b/SafeExamBrowser.Contracts/Communication/ICommunicationProxy.cs @@ -23,17 +23,14 @@ namespace SafeExamBrowser.Contracts.Communication event CommunicationEventHandler ConnectionLost; /// - /// Tries to establish a connection. Returns true if the connection has been accepted, otherwise false. If a + /// Tries to establish a connection. Returns true if the connection has been successful, otherwise false. If a /// connection was successfully established and the auto-ping flag is set, the connection status will be periodically checked. /// - /// If the communication failed. bool Connect(Guid? token = null, bool autoPing = true); /// - /// Terminates an open connection. Returns true if the disconnection has been acknowledged, otherwise false. + /// Terminates an open connection. Returns true if the disconnection has been successful, otherwise false. /// - /// If no connection has been established. - /// If the communication failed. bool Disconnect(); } } diff --git a/SafeExamBrowser.Contracts/Communication/Proxies/CommunicationResult.cs b/SafeExamBrowser.Contracts/Communication/Proxies/CommunicationResult.cs new file mode 100644 index 00000000..e2369b48 --- /dev/null +++ b/SafeExamBrowser.Contracts/Communication/Proxies/CommunicationResult.cs @@ -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 +{ + /// + /// Defines the result of a communication between an and its . + /// + public class CommunicationResult + { + /// + /// Defines whether the communication was successful or not. + /// + public bool Success { get; protected set; } + + public CommunicationResult(bool success) + { + Success = success; + } + } + + /// + /// Defines the result of a communication between an and its . + /// + /// The type of the expected response value. + public class CommunicationResult : CommunicationResult + { + /// + /// The response value. Can be null or default(T) in case the communication has failed! + /// + public T Value { get; protected set; } + + public CommunicationResult(bool success, T value) : base(success) + { + Value = value; + } + } +} diff --git a/SafeExamBrowser.Contracts/Communication/Proxies/IClientProxy.cs b/SafeExamBrowser.Contracts/Communication/Proxies/IClientProxy.cs index 13e0ed36..9f3c049e 100644 --- a/SafeExamBrowser.Contracts/Communication/Proxies/IClientProxy.cs +++ b/SafeExamBrowser.Contracts/Communication/Proxies/IClientProxy.cs @@ -19,24 +19,21 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies /// /// Informs the client that the reconfiguration request for the specified file was denied. /// - void InformReconfigurationDenied(string filePath); + CommunicationResult InformReconfigurationDenied(string filePath); /// /// Instructs the client to initiate its shutdown procedure. /// - /// If the communication failed. - void InitiateShutdown(); + CommunicationResult InitiateShutdown(); /// /// Instructs the client to submit its authentication data. /// - /// If the communication failed. - AuthenticationResponse RequestAuthentication(); + CommunicationResult RequestAuthentication(); /// /// Requests the client to render a password dialog and subsequently return the interaction result as separate message. /// - /// If the communication failed. - void RequestPassword(PasswordRequestPurpose purpose, Guid requestId); + CommunicationResult RequestPassword(PasswordRequestPurpose purpose, Guid requestId); } } diff --git a/SafeExamBrowser.Contracts/Communication/Proxies/IRuntimeProxy.cs b/SafeExamBrowser.Contracts/Communication/Proxies/IRuntimeProxy.cs index 5a261088..5140e5c4 100644 --- a/SafeExamBrowser.Contracts/Communication/Proxies/IRuntimeProxy.cs +++ b/SafeExamBrowser.Contracts/Communication/Proxies/IRuntimeProxy.cs @@ -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 /// /// Retrieves the application configuration from the runtime. /// - /// If the communication failed. - ClientConfiguration GetConfiguration(); + CommunicationResult GetConfiguration(); /// /// Informs the runtime that the client is ready. /// - /// If the communication failed. - void InformClientReady(); + CommunicationResult InformClientReady(); /// /// Requests the runtime to shut down the application. /// - /// If the communication failed. - void RequestShutdown(); + CommunicationResult RequestShutdown(); /// /// Requests the runtime to reconfigure the application with the specified configuration. /// - /// If the communication failed. - void RequestReconfiguration(string filePath); + CommunicationResult RequestReconfiguration(string filePath); /// /// 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 null! /// - /// /// If the communication failed. - void SubmitPassword(Guid requestId, bool success, string password = null); + CommunicationResult SubmitPassword(Guid requestId, bool success, string password = null); } } diff --git a/SafeExamBrowser.Contracts/Communication/Proxies/IServiceProxy.cs b/SafeExamBrowser.Contracts/Communication/Proxies/IServiceProxy.cs index 82e96968..b8f15b1c 100644 --- a/SafeExamBrowser.Contracts/Communication/Proxies/IServiceProxy.cs +++ b/SafeExamBrowser.Contracts/Communication/Proxies/IServiceProxy.cs @@ -25,13 +25,11 @@ namespace SafeExamBrowser.Contracts.Communication.Proxies /// /// Instructs the service to start a new session according to the given parameters. /// - /// If the communication failed. - void StartSession(Guid sessionId, Settings settings); + CommunicationResult StartSession(Guid sessionId, Settings settings); /// /// Instructs the service to stop the specified session. /// - /// If the communication failed. - void StopSession(Guid sessionId); + CommunicationResult StopSession(Guid sessionId); } } diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index 2a9d5031..623bed9f 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -75,6 +75,7 @@ + diff --git a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/BaseProxyTests.cs b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/BaseProxyTests.cs index 24d9cca9..1efcab54 100644 --- a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/BaseProxyTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/BaseProxyTests.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(); @@ -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(); diff --git a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/ClientProxyTests.cs b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/ClientProxyTests.cs index 7424271b..c95ad41e 100644 --- a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/ClientProxyTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/ClientProxyTests.cs @@ -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(m => m.Purport == SimpleMessagePurport.Shutdown))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged)); - sut.InitiateShutdown(); + var communication = sut.InitiateShutdown(); proxy.Verify(p => p.Send(It.Is(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(m => m.Purport == SimpleMessagePurport.Shutdown))).Returns(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(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(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(m => m.Purport == SimpleMessagePurport.Authenticate))).Returns(null); - sut.RequestAuthentication(); + var communication = sut.RequestAuthentication(); + + Assert.AreEqual(default(AuthenticationResponse), communication.Value); + Assert.IsFalse(communication.Success); } } } diff --git a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/RuntimeProxyTests.cs b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/RuntimeProxyTests.cs index 58de0025..f593ce69 100644 --- a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/RuntimeProxyTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/RuntimeProxyTests.cs @@ -57,20 +57,23 @@ namespace SafeExamBrowser.Core.UnitTests.Communication.Proxies proxy.Setup(p => p.Send(It.Is(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(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(m => m.Purport == SimpleMessagePurport.ConfigurationNeeded))).Returns(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(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(m => m.Purport == SimpleMessagePurport.ClientIsReady)), Times.Once); } [TestMethod] - [ExpectedException(typeof(CommunicationException))] public void MustFailIfClientReadyNotAcknowledged() { proxy.Setup(p => p.Send(It.Is(m => m.Purport == SimpleMessagePurport.ClientIsReady))).Returns(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(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(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(m => m.ConfigurationPath == url))).Returns(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(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(m => m.Purport == SimpleMessagePurport.RequestShutdown)), Times.Once); } [TestMethod] - [ExpectedException(typeof(CommunicationException))] public void MustFailIfShutdownRequestNotAcknowledged() { proxy.Setup(p => p.Send(It.Is(m => m.Purport == SimpleMessagePurport.RequestShutdown))).Returns(null); - sut.RequestShutdown(); + var communication = sut.RequestShutdown(); + + Assert.IsFalse(communication.Success); } } } diff --git a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/ServiceProxyTests.cs b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/ServiceProxyTests.cs index 3385aa36..c496e3a6 100644 --- a/SafeExamBrowser.Core.UnitTests/Communication/Proxies/ServiceProxyTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Communication/Proxies/ServiceProxyTests.cs @@ -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()), 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()), Times.Never); } } diff --git a/SafeExamBrowser.Core/Communication/Proxies/BaseProxy.cs b/SafeExamBrowser.Core/Communication/Proxies/BaseProxy.cs index c2817488..982c4e61 100644 --- a/SafeExamBrowser.Core/Communication/Proxies/BaseProxy.cs +++ b/SafeExamBrowser.Core/Communication/Proxies/BaseProxy.cs @@ -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; + } } /// /// Sends the given message, optionally returning a response. If no response is expected, null will be returned. /// /// If the given message is null. - /// If no connection has been established yet. - /// If the communication failed. + /// If no connection has been established yet or the connection is corrupted. 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()}!"); } } diff --git a/SafeExamBrowser.Core/Communication/Proxies/ClientProxy.cs b/SafeExamBrowser.Core/Communication/Proxies/ClientProxy.cs index 81f6db3e..e940abbc 100644 --- a/SafeExamBrowser.Core/Communication/Proxies/ClientProxy.cs +++ b/SafeExamBrowser.Core/Communication/Proxies/ClientProxy.cs @@ -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 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(success, response as AuthenticationResponse); + } + catch (Exception e) + { + Logger.Error($"Failed to perform '{nameof(RequestAuthentication)}'", e); + + return new CommunicationResult(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); } } } diff --git a/SafeExamBrowser.Core/Communication/Proxies/RuntimeProxy.cs b/SafeExamBrowser.Core/Communication/Proxies/RuntimeProxy.cs index 6cb7e0bc..7406e2cd 100644 --- a/SafeExamBrowser.Core/Communication/Proxies/RuntimeProxy.cs +++ b/SafeExamBrowser.Core/Communication/Proxies/RuntimeProxy.cs @@ -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 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(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(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); } } } diff --git a/SafeExamBrowser.Core/Communication/Proxies/ServiceProxy.cs b/SafeExamBrowser.Core/Communication/Proxies/ServiceProxy.cs index 2a4740e8..da5dd5d6 100644 --- a/SafeExamBrowser.Core/Communication/Proxies/ServiceProxy.cs +++ b/SafeExamBrowser.Core/Communication/Proxies/ServiceProxy.cs @@ -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) diff --git a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ClientOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ClientOperationTests.cs index cd31681e..36e73bda 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ClientOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ClientOperationTests.cs @@ -67,10 +67,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations { var result = default(OperationResult); var response = new AuthenticationResponse { ProcessId = 1234 }; + var communication = new CommunicationResult(true, response); process.SetupGet(p => p.Id).Returns(response.ProcessId); processFactory.Setup(f => f.StartNew(It.IsAny(), It.IsAny())).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(), 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(true, response); process.SetupGet(p => p.Id).Returns(response.ProcessId); processFactory.Setup(f => f.StartNew(It.IsAny(), It.IsAny())).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(), 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(true, response); process.SetupGet(p => p.Id).Returns(1234); processFactory.Setup(f => f.StartNew(It.IsAny(), It.IsAny())).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(), 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(true, response); process.SetupGet(p => p.Id).Returns(response.ProcessId); processFactory.Setup(f => f.StartNew(It.IsAny(), It.IsAny())).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(), true)).Returns(true); sut.Perform(); diff --git a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs index 04af1235..1f621e01 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs @@ -335,6 +335,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations public void MustRequestPasswordViaClientDuringReconfigurationOnNewDesktop() { var clientProxy = new Mock(); + var communication = new CommunicationResult(true); var passwordReceived = new Action((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(); var url = @"http://www.safeexambrowser.org/whatever.seb"; - clientProxy.Setup(c => c.RequestPassword(It.IsAny(), It.IsAny())).Callback(passwordReceived); + clientProxy.Setup(c => c.RequestPassword(It.IsAny(), It.IsAny())).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(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded); @@ -361,6 +362,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations public void MustAbortAskingForPasswordViaClientIfDecidedByUser() { var clientProxy = new Mock(); + var communication = new CommunicationResult(true); var passwordReceived = new Action((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(); var url = @"http://www.safeexambrowser.org/whatever.seb"; - clientProxy.Setup(c => c.RequestPassword(It.IsAny(), It.IsAny())).Callback(passwordReceived); - passwordDialog.Setup(d => d.Show(null)).Returns(new PasswordDialogResultStub { Success = true }); + clientProxy.Setup(c => c.RequestPassword(It.IsAny(), It.IsAny())).Returns(communication).Callback(passwordReceived); + repository.SetupGet(r => r.CurrentSession).Returns(session.Object); + repository.Setup(r => r.LoadSettings(It.IsAny(), 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(); + var communication = new CommunicationResult(false); + var session = new Mock(); + var url = @"http://www.safeexambrowser.org/whatever.seb"; + + clientProxy.Setup(c => c.RequestPassword(It.IsAny(), It.IsAny())).Returns(communication); repository.SetupGet(r => r.CurrentSession).Returns(session.Object); repository.Setup(r => r.LoadSettings(It.IsAny(), null, null)).Returns(LoadStatus.SettingsPasswordNeeded); session.SetupGet(r => r.ClientProxy).Returns(clientProxy.Object); diff --git a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceOperationTests.cs index a1c04cdb..90a71111 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceOperationTests.cs @@ -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(); - configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory }); - - sut.Perform(); - - service.Setup(s => s.Connect(null, true)).Throws(); - 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(); + 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(); - configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Mandatory }); - - sut.Perform(); - sut.Revert(); - - service.Setup(s => s.Connect(null, true)).Throws(); - configuration.SetupGet(s => s.CurrentSettings).Returns(new Settings { ServicePolicy = ServicePolicy.Optional }); - - sut.Perform(); - sut.Revert(); - service.Verify(s => s.Disconnect(), Times.Never); } } diff --git a/SafeExamBrowser.Runtime/Behaviour/Operations/ClientOperation.cs b/SafeExamBrowser.Runtime/Behaviour/Operations/ClientOperation.cs index 74f7258e..25de60ef 100644 --- a/SafeExamBrowser.Runtime/Behaviour/Operations/ClientOperation.cs +++ b/SafeExamBrowser.Runtime/Behaviour/Operations/ClientOperation.cs @@ -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!"); diff --git a/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs index a24c8dba..03ac810b 100644 --- a/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs +++ b/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs @@ -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) diff --git a/SafeExamBrowser.Runtime/Behaviour/Operations/ServiceOperation.cs b/SafeExamBrowser.Runtime/Behaviour/Operations/ServiceOperation.cs index 2a6c99f3..90ae10ac 100644 --- a/SafeExamBrowser.Runtime/Behaviour/Operations/ServiceOperation.cs +++ b/SafeExamBrowser.Runtime/Behaviour/Operations/ServiceOperation.cs @@ -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}"); - } - } } }