From 2cde60b1e7a68dbe8ce3b61732588bdb3c6b5713 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Mon, 10 Feb 2020 16:47:50 +0100 Subject: [PATCH] Fixed issue with splash screen not being closed on client side if reconfiguration was aborted. --- .../ClientControllerTests.cs | 13 ++++++++++ .../Communication/ClientHostTests.cs | 26 +++++++++++++++++++ SafeExamBrowser.Client/ClientController.cs | 11 +++++--- .../Communication/ClientHost.cs | 4 +++ .../Data/SimpleMessagePurport.cs | 5 ++++ .../Hosts/IClientHost.cs | 5 ++++ .../Proxies/IClientProxy.cs | 5 ++++ .../Proxies/ClientProxyTests.cs | 21 +++++++++++++++ .../Proxies/ClientProxy.cs | 26 +++++++++++++++++++ SafeExamBrowser.I18n/Text.xml | 2 +- .../RuntimeControllerTests.cs | 12 +++++++++ SafeExamBrowser.Runtime/RuntimeController.cs | 2 ++ 12 files changed, 127 insertions(+), 5 deletions(-) diff --git a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs index b556b206..3bd8cd73 100644 --- a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs +++ b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs @@ -297,6 +297,19 @@ namespace SafeExamBrowser.Client.UnitTests It.Is(s => s == result.Password)), Times.Once); } + [TestMethod] + public void Communication_MustCorrectlyHandleAbortedReconfiguration() + { + var splashScreen = new Mock(); + + uiFactory.Setup(f => f.CreateSplashScreen(It.IsAny())).Returns(splashScreen.Object); + + sut.TryStart(); + clientHost.Raise(c => c.ReconfigurationAborted += null); + + splashScreen.Verify(s => s.Close(), Times.AtLeastOnce); + } + [TestMethod] public void Communication_MustInformUserAboutDeniedReconfiguration() { diff --git a/SafeExamBrowser.Client.UnitTests/Communication/ClientHostTests.cs b/SafeExamBrowser.Client.UnitTests/Communication/ClientHostTests.cs index 5a2ed1bb..2eaf4b7c 100644 --- a/SafeExamBrowser.Client.UnitTests/Communication/ClientHostTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Communication/ClientHostTests.cs @@ -208,6 +208,31 @@ namespace SafeExamBrowser.Client.UnitTests.Communication Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport); } + [TestMethod] + public void MustHandleReconfigurationAbortionCorrectly() + { + var reconfigurationAborted = false; + var resetEvent = new AutoResetEvent(false); + + sut.ReconfigurationAborted += () => + { + reconfigurationAborted = true; + resetEvent.Set(); + }; + sut.AuthenticationToken = Guid.Empty; + + var token = sut.Connect(Guid.Empty).CommunicationToken.Value; + var message = new SimpleMessage(SimpleMessagePurport.ReconfigurationAborted) { CommunicationToken = token }; + var response = sut.Send(message); + + resetEvent.WaitOne(); + + Assert.IsTrue(reconfigurationAborted); + Assert.IsNotNull(response); + Assert.IsInstanceOfType(response, typeof(SimpleResponse)); + Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport); + } + [TestMethod] public void MustHandleReconfigurationDenialCorrectly() { @@ -282,6 +307,7 @@ namespace SafeExamBrowser.Client.UnitTests.Communication sut.Send(new MessageBoxRequestMessage(default(int), default(int), "", Guid.Empty, "") { CommunicationToken = token }); sut.Send(new PasswordRequestMessage(default(PasswordRequestPurpose), Guid.Empty) { CommunicationToken = token }); + sut.Send(new SimpleMessage(SimpleMessagePurport.ReconfigurationAborted)); sut.Send(new ReconfigurationDeniedMessage("") { CommunicationToken = token }); sut.Send(new SimpleMessage(SimpleMessagePurport.Shutdown) { CommunicationToken = token }); sut.Disconnect(new DisconnectionMessage { CommunicationToken = token, Interlocutor = Interlocutor.Runtime }); diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs index a1a532c7..3f960a56 100644 --- a/SafeExamBrowser.Client/ClientController.cs +++ b/SafeExamBrowser.Client/ClientController.cs @@ -178,6 +178,7 @@ namespace SafeExamBrowser.Client Browser.TerminationRequested += Browser_TerminationRequested; ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested; ClientHost.PasswordRequested += ClientHost_PasswordRequested; + ClientHost.ReconfigurationAborted += ClientHost_ReconfigurationAborted; ClientHost.ReconfigurationDenied += ClientHost_ReconfigurationDenied; ClientHost.Shutdown += ClientHost_Shutdown; displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged; @@ -208,6 +209,7 @@ namespace SafeExamBrowser.Client { ClientHost.MessageBoxRequested -= ClientHost_MessageBoxRequested; ClientHost.PasswordRequested -= ClientHost_PasswordRequested; + ClientHost.ReconfigurationAborted -= ClientHost_ReconfigurationAborted; ClientHost.ReconfigurationDenied -= ClientHost_ReconfigurationDenied; ClientHost.Shutdown -= ClientHost_Shutdown; } @@ -421,11 +423,12 @@ namespace SafeExamBrowser.Client runtime.SubmitPassword(args.RequestId, result.Success, result.Password); logger.Info($"Password request with id '{args.RequestId}' was {(result.Success ? "successful" : "aborted by the user")}."); + } - if (!result.Success) - { - splashScreen?.Close(); - } + private void ClientHost_ReconfigurationAborted() + { + logger.Info("The reconfiguration was aborted by the runtime."); + splashScreen?.Close(); } private void ClientHost_ReconfigurationDenied(ReconfigurationEventArgs args) diff --git a/SafeExamBrowser.Client/Communication/ClientHost.cs b/SafeExamBrowser.Client/Communication/ClientHost.cs index c1036db3..7df4aa6a 100644 --- a/SafeExamBrowser.Client/Communication/ClientHost.cs +++ b/SafeExamBrowser.Client/Communication/ClientHost.cs @@ -26,6 +26,7 @@ namespace SafeExamBrowser.Client.Communication public event CommunicationEventHandler MessageBoxRequested; public event CommunicationEventHandler PasswordRequested; + public event CommunicationEventHandler ReconfigurationAborted; public event CommunicationEventHandler ReconfigurationDenied; public event CommunicationEventHandler RuntimeDisconnected; public event CommunicationEventHandler Shutdown; @@ -88,6 +89,9 @@ namespace SafeExamBrowser.Client.Communication { case SimpleMessagePurport.Authenticate: return new AuthenticationResponse { ProcessId = processId }; + case SimpleMessagePurport.ReconfigurationAborted: + ReconfigurationAborted?.InvokeAsync(); + return new SimpleResponse(SimpleResponsePurport.Acknowledged); case SimpleMessagePurport.Shutdown: Shutdown?.Invoke(); return new SimpleResponse(SimpleResponsePurport.Acknowledged); diff --git a/SafeExamBrowser.Communication.Contracts/Data/SimpleMessagePurport.cs b/SafeExamBrowser.Communication.Contracts/Data/SimpleMessagePurport.cs index 38640347..6fff7d8e 100644 --- a/SafeExamBrowser.Communication.Contracts/Data/SimpleMessagePurport.cs +++ b/SafeExamBrowser.Communication.Contracts/Data/SimpleMessagePurport.cs @@ -36,6 +36,11 @@ namespace SafeExamBrowser.Communication.Contracts.Data /// Ping, + /// + /// Sent from the runtime to the client to inform the latter that a reconfiguration was aborted. + /// + ReconfigurationAborted, + /// /// Sent from the client to the runtime to request shutting down the application. /// diff --git a/SafeExamBrowser.Communication.Contracts/Hosts/IClientHost.cs b/SafeExamBrowser.Communication.Contracts/Hosts/IClientHost.cs index 6df10cf6..dda8e2ef 100644 --- a/SafeExamBrowser.Communication.Contracts/Hosts/IClientHost.cs +++ b/SafeExamBrowser.Communication.Contracts/Hosts/IClientHost.cs @@ -36,6 +36,11 @@ namespace SafeExamBrowser.Communication.Contracts.Hosts /// event CommunicationEventHandler PasswordRequested; + /// + /// Event fired when the runtime aborted a reconfiguration. + /// + event CommunicationEventHandler ReconfigurationAborted; + /// /// Event fired when the runtime denied a reconfiguration request. /// diff --git a/SafeExamBrowser.Communication.Contracts/Proxies/IClientProxy.cs b/SafeExamBrowser.Communication.Contracts/Proxies/IClientProxy.cs index 5c8aa843..57193cd4 100644 --- a/SafeExamBrowser.Communication.Contracts/Proxies/IClientProxy.cs +++ b/SafeExamBrowser.Communication.Contracts/Proxies/IClientProxy.cs @@ -16,6 +16,11 @@ namespace SafeExamBrowser.Communication.Contracts.Proxies /// public interface IClientProxy : ICommunicationProxy { + /// + /// Informs the client that a reconfiguration was aborted. + /// + CommunicationResult InformReconfigurationAborted(); + /// /// Informs the client that the reconfiguration request for the specified file was denied. /// diff --git a/SafeExamBrowser.Communication.UnitTests/Proxies/ClientProxyTests.cs b/SafeExamBrowser.Communication.UnitTests/Proxies/ClientProxyTests.cs index b4b2c8a2..7577b4bd 100644 --- a/SafeExamBrowser.Communication.UnitTests/Proxies/ClientProxyTests.cs +++ b/SafeExamBrowser.Communication.UnitTests/Proxies/ClientProxyTests.cs @@ -93,6 +93,27 @@ namespace SafeExamBrowser.Communication.UnitTests.Proxies Assert.IsFalse(communication.Success); } + [TestMethod] + public void MustCorrectlyInformAboutReconfigurationAbortion() + { + proxy.Setup(p => p.Send(It.Is(m => m.Purport == SimpleMessagePurport.ReconfigurationAborted))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged)); + + var communication = sut.InformReconfigurationAborted(); + + proxy.Verify(p => p.Send(It.Is(m => m.Purport == SimpleMessagePurport.ReconfigurationAborted)), Times.Once); + Assert.IsTrue(communication.Success); + } + + [TestMethod] + public void MustFailIfReconfigurationAbortionNotAcknowledged() + { + proxy.Setup(p => p.Send(It.IsAny())).Returns(null); + + var communication = sut.InformReconfigurationAborted(); + + Assert.IsFalse(communication.Success); + } + [TestMethod] public void MustCorrectlyInformAboutReconfigurationDenial() { diff --git a/SafeExamBrowser.Communication/Proxies/ClientProxy.cs b/SafeExamBrowser.Communication/Proxies/ClientProxy.cs index 01a76384..9406cc08 100644 --- a/SafeExamBrowser.Communication/Proxies/ClientProxy.cs +++ b/SafeExamBrowser.Communication/Proxies/ClientProxy.cs @@ -23,6 +23,32 @@ namespace SafeExamBrowser.Communication.Proxies { } + public CommunicationResult InformReconfigurationAborted() + { + try + { + var response = Send(new SimpleMessage(SimpleMessagePurport.ReconfigurationAborted)); + var success = IsAcknowledged(response); + + if (success) + { + Logger.Debug("Client acknowledged reconfiguration abortion."); + } + else + { + Logger.Error($"Client did not acknowledge reconfiguration abortion! Received: {ToString(response)}."); + } + + return new CommunicationResult(success); + } + catch (Exception e) + { + Logger.Error($"Failed to perform '{nameof(InformReconfigurationAborted)}'", e); + + return new CommunicationResult(false); + } + } + public CommunicationResult InformReconfigurationDenied(string filePath) { try diff --git a/SafeExamBrowser.I18n/Text.xml b/SafeExamBrowser.I18n/Text.xml index 6c4056c8..70e05ee3 100644 --- a/SafeExamBrowser.I18n/Text.xml +++ b/SafeExamBrowser.I18n/Text.xml @@ -271,7 +271,7 @@ Configuration Error - This computer appears to be a virtual machine. The currently active configuration does not allow SEB to be run in a virtual machine. + This computer appears to be a virtual machine. The selected configuration does not allow SEB to be run in a virtual machine. Virtual Machine Detected diff --git a/SafeExamBrowser.Runtime.UnitTests/RuntimeControllerTests.cs b/SafeExamBrowser.Runtime.UnitTests/RuntimeControllerTests.cs index 922f78aa..7c90d774 100644 --- a/SafeExamBrowser.Runtime.UnitTests/RuntimeControllerTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/RuntimeControllerTests.cs @@ -171,6 +171,18 @@ namespace SafeExamBrowser.Runtime.UnitTests Assert.AreEqual(sessionContext.ReconfigurationFilePath, args.ConfigurationPath); } + [TestMethod] + public void Communication_MustInformClientAboutAbortedReconfiguration() + { + StartSession(); + sessionSequence.Reset(); + sessionSequence.Setup(s => s.TryRepeat()).Returns(OperationResult.Aborted); + + runtimeHost.Raise(r => r.ReconfigurationRequested += null, new ReconfigurationEventArgs()); + + clientProxy.Verify(c => c.InformReconfigurationAborted(), Times.Once); + } + [TestMethod] public void Communication_MustInformClientAboutDeniedReconfiguration() { diff --git a/SafeExamBrowser.Runtime/RuntimeController.cs b/SafeExamBrowser.Runtime/RuntimeController.cs index 2a0aafe5..a7644ed7 100644 --- a/SafeExamBrowser.Runtime/RuntimeController.cs +++ b/SafeExamBrowser.Runtime/RuntimeController.cs @@ -233,6 +233,8 @@ namespace SafeExamBrowser.Runtime { runtimeWindow.Hide(); } + + sessionContext.ClientProxy.InformReconfigurationAborted(); } }