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…
	
	Add table
		
		Reference in a new issue