SEBWIN-221: Fixed issues with the operation model by separating repeatable from non-repeatable operations and solved conundrum with session operation sequence.
This commit is contained in:
parent
4ca2fac50e
commit
f4631a1a3d
60 changed files with 719 additions and 786 deletions
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
|
@ -64,12 +63,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
|
|
||||||
controllerMock.Verify(c => c.Terminate(), Times.Once);
|
controllerMock.Verify(c => c.Terminate(), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,12 +96,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
|
@ -47,12 +46,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
|
|
||||||
nativeMethodsMock.Verify(n => n.EmptyClipboard(), Times.Once);
|
nativeMethodsMock.Verify(n => n.EmptyClipboard(), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
|
@ -39,12 +38,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
{
|
{
|
||||||
Assert.Fail();
|
Assert.Fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
|
@ -64,12 +63,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
displayMonitorMock.Verify(d => d.StopMonitoringDisplayChanges(), Times.Once);
|
displayMonitorMock.Verify(d => d.StopMonitoringDisplayChanges(), Times.Once);
|
||||||
displayMonitorMock.Verify(d => d.ResetPrimaryDisplay(), Times.Once);
|
displayMonitorMock.Verify(d => d.ResetPrimaryDisplay(), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
|
@ -50,12 +49,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
|
|
||||||
nativeMethodsMock.Verify(n => n.DeregisterKeyboardHook(It.IsAny<IKeyboardInterceptor>()), Times.Once);
|
nativeMethodsMock.Verify(n => n.DeregisterKeyboardHook(It.IsAny<IKeyboardInterceptor>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
|
@ -50,12 +49,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
|
|
||||||
nativeMethodsMock.Verify(n => n.DeregisterMouseHook(It.IsAny<IMouseInterceptor>()), Times.Once);
|
nativeMethodsMock.Verify(n => n.DeregisterMouseHook(It.IsAny<IMouseInterceptor>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
|
@ -71,12 +70,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
processMonitor.Verify(p => p.StartMonitoringExplorer(), Times.Never);
|
processMonitor.Verify(p => p.StartMonitoringExplorer(), Times.Never);
|
||||||
processMonitor.Verify(p => p.StopMonitoringExplorer(), Times.Never);
|
processMonitor.Verify(p => p.StopMonitoringExplorer(), Times.Never);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
|
||||||
|
@ -33,14 +31,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
{
|
{
|
||||||
Assert.Fail();
|
Assert.Fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
var sut = new RuntimeConnectionOperation(logger.Object, runtime.Object, Guid.Empty);
|
|
||||||
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
|
@ -94,12 +93,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
powerSupplyMock.Verify(p => p.Terminate(), Times.Once);
|
powerSupplyMock.Verify(p => p.Terminate(), Times.Once);
|
||||||
wirelessNetworkMock.Verify(w => w.Terminate(), Times.Once);
|
wirelessNetworkMock.Verify(w => w.Terminate(), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Operations;
|
using SafeExamBrowser.Client.Operations;
|
||||||
|
@ -106,14 +105,5 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
|
|
||||||
windowMonitorMock.VerifyNoOtherCalls();
|
windowMonitorMock.VerifyNoOtherCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
var sut = new WindowMonitorOperation(KioskMode.None, loggerMock.Object, windowMonitorMock.Object);
|
|
||||||
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
DeregisterEvents();
|
DeregisterEvents();
|
||||||
|
|
||||||
var success = operations.TryRevert();
|
var success = operations.TryRevert() == OperationResult.Success;
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Core;
|
using SafeExamBrowser.Contracts.Core;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
|
@ -58,17 +57,14 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{nameof(BrowserOperation)}' is not meant to be repeated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
{
|
||||||
logger.Info("Terminating browser...");
|
logger.Info("Terminating browser...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_TerminateBrowser);
|
StatusChanged?.Invoke(TextKey.OperationStatus_TerminateBrowser);
|
||||||
|
|
||||||
browserController.Terminate();
|
browserController.Terminate();
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using SafeExamBrowser.Contracts.Communication.Events;
|
using SafeExamBrowser.Contracts.Communication.Events;
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
|
@ -42,29 +41,32 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"The '{nameof(ClientHostDisconnectionOperation)}' is not meant to be repeated!");
|
StatusChanged?.Invoke(TextKey.OperationStatus_WaitRuntimeDisconnection);
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
if (clientHost.IsConnected)
|
||||||
{
|
{
|
||||||
var disconnected = false;
|
var disconnected = false;
|
||||||
var disconnectedEvent = new AutoResetEvent(false);
|
var disconnectedEvent = new AutoResetEvent(false);
|
||||||
var disconnectedEventHandler = new CommunicationEventHandler(() => disconnectedEvent.Set());
|
var disconnectedEventHandler = new CommunicationEventHandler(() => disconnectedEvent.Set());
|
||||||
|
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_WaitRuntimeDisconnection);
|
|
||||||
|
|
||||||
clientHost.RuntimeDisconnected += disconnectedEventHandler;
|
clientHost.RuntimeDisconnected += disconnectedEventHandler;
|
||||||
|
|
||||||
if (clientHost.IsConnected)
|
|
||||||
{
|
|
||||||
logger.Info("Waiting for runtime to disconnect from client communication host...");
|
logger.Info("Waiting for runtime to disconnect from client communication host...");
|
||||||
disconnected = disconnectedEvent.WaitOne(timeout_ms);
|
disconnected = disconnectedEvent.WaitOne(timeout_ms);
|
||||||
|
|
||||||
if (!disconnected)
|
clientHost.RuntimeDisconnected -= disconnectedEventHandler;
|
||||||
|
|
||||||
|
if (disconnected)
|
||||||
{
|
{
|
||||||
logger.Error($"Runtime failed to disconnect within {timeout_ms / 1000} seconds!");
|
logger.Info("The runtime has successfully disconnected from the client communication host.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Error($"The runtime failed to disconnect within {timeout_ms / 1000} seconds!");
|
||||||
|
|
||||||
|
return OperationResult.Failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -72,7 +74,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
logger.Info("The runtime has already disconnected from the client communication host.");
|
logger.Info("The runtime has already disconnected from the client communication host.");
|
||||||
}
|
}
|
||||||
|
|
||||||
clientHost.RuntimeDisconnected -= disconnectedEventHandler;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
|
@ -36,14 +35,11 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{nameof(ClipboardOperation)}' is not meant to be repeated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
{
|
||||||
EmptyClipboard();
|
EmptyClipboard();
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmptyClipboard()
|
private void EmptyClipboard()
|
||||||
|
|
|
@ -61,14 +61,9 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"The '{nameof(ConfigurationOperation)}' is not meant to be repeated!");
|
return OperationResult.Success;
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
|
||||||
// Nothing to do here...
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
|
@ -44,18 +43,15 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{nameof(DisplayMonitorOperation)}' is not meant to be repeated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
{
|
||||||
logger.Info("Restoring working area...");
|
logger.Info("Restoring working area...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_RestoreWorkingArea);
|
StatusChanged?.Invoke(TextKey.OperationStatus_RestoreWorkingArea);
|
||||||
|
|
||||||
displayMonitor.StopMonitoringDisplayChanges();
|
displayMonitor.StopMonitoringDisplayChanges();
|
||||||
displayMonitor.ResetPrimaryDisplay();
|
displayMonitor.ResetPrimaryDisplay();
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
|
@ -45,17 +44,14 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{nameof(KeyboardInterceptorOperation)}' is not meant to be repeated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
{
|
||||||
logger.Info("Stopping keyboard interception...");
|
logger.Info("Stopping keyboard interception...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_StopKeyboardInterception);
|
StatusChanged?.Invoke(TextKey.OperationStatus_StopKeyboardInterception);
|
||||||
|
|
||||||
nativeMethods.DeregisterKeyboardHook(keyboardInterceptor);
|
nativeMethods.DeregisterKeyboardHook(keyboardInterceptor);
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
|
@ -45,17 +44,14 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{nameof(MouseInterceptorOperation)}' is not meant to be repeated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
{
|
||||||
logger.Info("Stopping mouse interception...");
|
logger.Info("Stopping mouse interception...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_StopMouseInterception);
|
StatusChanged?.Invoke(TextKey.OperationStatus_StopMouseInterception);
|
||||||
|
|
||||||
nativeMethods.DeregisterMouseHook(mouseInterceptor);
|
nativeMethods.DeregisterMouseHook(mouseInterceptor);
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||||
|
@ -45,12 +44,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{nameof(ProcessMonitorOperation)}' is not meant to be repeated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
{
|
||||||
logger.Info("Stopping process monitoring...");
|
logger.Info("Stopping process monitoring...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_StopProcessMonitoring);
|
StatusChanged?.Invoke(TextKey.OperationStatus_StopProcessMonitoring);
|
||||||
|
@ -59,6 +53,8 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
{
|
{
|
||||||
processMonitor.StopMonitoringExplorer();
|
processMonitor.StopMonitoringExplorer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,12 +51,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return connected ? OperationResult.Success : OperationResult.Failed;
|
return connected ? OperationResult.Success : OperationResult.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{nameof(RuntimeConnectionOperation)}' is not meant to be repeated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
{
|
||||||
logger.Info("Closing runtime connection...");
|
logger.Info("Closing runtime connection...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_CloseRuntimeConnection);
|
StatusChanged?.Invoke(TextKey.OperationStatus_CloseRuntimeConnection);
|
||||||
|
@ -73,7 +68,11 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
{
|
{
|
||||||
logger.Error("Failed to disconnect from the runtime!");
|
logger.Error("Failed to disconnect from the runtime!");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return success ? OperationResult.Success : OperationResult.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.Core;
|
using SafeExamBrowser.Contracts.Core;
|
||||||
|
@ -91,12 +90,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{nameof(TaskbarOperation)}' is not meant to be repeated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
{
|
||||||
logger.Info("Terminating taskbar...");
|
logger.Info("Terminating taskbar...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_TerminateTaskbar);
|
StatusChanged?.Invoke(TextKey.OperationStatus_TerminateTaskbar);
|
||||||
|
@ -120,6 +114,8 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
{
|
{
|
||||||
wirelessNetwork.Terminate();
|
wirelessNetwork.Terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddKeyboardLayoutControl()
|
private void AddKeyboardLayoutControl()
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||||
|
@ -50,12 +49,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{nameof(WindowMonitorOperation)}' is not meant to be repeated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
{
|
||||||
logger.Info("Stopping window monitoring...");
|
logger.Info("Stopping window monitoring...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_StopWindowMonitoring);
|
StatusChanged?.Invoke(TextKey.OperationStatus_StopWindowMonitoring);
|
||||||
|
@ -69,6 +63,8 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
{
|
{
|
||||||
windowMonitor.RestoreHiddenWindows();
|
windowMonitor.RestoreHiddenWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,9 @@ namespace SafeExamBrowser.Configuration
|
||||||
{
|
{
|
||||||
CurrentSession = new SessionData
|
CurrentSession = new SessionData
|
||||||
{
|
{
|
||||||
ClientProcess = CurrentSession?.ClientProcess,
|
|
||||||
ClientProxy = CurrentSession?.ClientProxy,
|
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
|
NewDesktop = CurrentSession?.NewDesktop,
|
||||||
|
OriginalDesktop = CurrentSession?.OriginalDesktop,
|
||||||
StartupToken = Guid.NewGuid()
|
StartupToken = Guid.NewGuid()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace SafeExamBrowser.Configuration
|
||||||
public IClientProxy ClientProxy { get; set; }
|
public IClientProxy ClientProxy { get; set; }
|
||||||
public IProcess ClientProcess { get; set; }
|
public IProcess ClientProcess { get; set; }
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
public IDesktop NewDesktop { get; set; }
|
||||||
|
public IDesktop OriginalDesktop { get; set; }
|
||||||
public Guid StartupToken { get; set; }
|
public Guid StartupToken { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
namespace SafeExamBrowser.Contracts.Configuration
|
namespace SafeExamBrowser.Contracts.Configuration
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines all session-related (configuration) data.
|
/// Holds all session-related configuration and runtime data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISessionData
|
public interface ISessionData
|
||||||
{
|
{
|
||||||
|
@ -32,6 +32,16 @@ namespace SafeExamBrowser.Contracts.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Guid Id { get; }
|
Guid Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The new desktop, if <see cref="Settings.KioskMode.CreateNewDesktop"/> is active for this session.
|
||||||
|
/// </summary>
|
||||||
|
IDesktop NewDesktop { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The original desktop, if <see cref="Settings.KioskMode.CreateNewDesktop"/> is active for this session.
|
||||||
|
/// </summary>
|
||||||
|
IDesktop OriginalDesktop { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The startup token used by the client and runtime components for initial authentication.
|
/// The startup token used by the client and runtime components for initial authentication.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -31,13 +31,8 @@ namespace SafeExamBrowser.Contracts.Core.OperationModel
|
||||||
OperationResult Perform();
|
OperationResult Perform();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Repeats the operation.
|
/// Reverts all changes made when executing the operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
OperationResult Repeat();
|
OperationResult Revert();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reverts all changes which were made when executing the operation.
|
|
||||||
/// </summary>
|
|
||||||
void Revert();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,13 @@ using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||||
namespace SafeExamBrowser.Contracts.Core.OperationModel
|
namespace SafeExamBrowser.Contracts.Core.OperationModel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A sequence of <see cref="IOperation"/>s which can be used for sequential procedures, e.g. the initialization & finalization of
|
/// A sequence of <see cref="IOperation"/> which can be used for sequential procedures, e.g. the initialization & finalization of
|
||||||
/// an application component. Each operation will be executed failsafe, i.e. the return value will indicate whether a procedure
|
/// an application component. Each operation will be executed failsafe, i.e. the return value will indicate whether a procedure
|
||||||
/// completed successfully or not.
|
/// completed successfully or not.
|
||||||
///
|
///
|
||||||
/// Exemplary execution order for a sequence initialized with operations A, B, C, D:
|
/// Exemplary execution order for a sequence initialized with operations A, B, C, D:
|
||||||
///
|
///
|
||||||
/// <see cref="TryPerform"/>: A -> B -> C -> D.
|
/// <see cref="TryPerform"/>: A -> B -> C -> D.
|
||||||
/// <see cref="TryRepeat"/>: A -> B -> C -> D.
|
|
||||||
/// <see cref="TryRevert"/>: D -> C -> B -> A.
|
/// <see cref="TryRevert"/>: D -> C -> B -> A.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IOperationSequence
|
public interface IOperationSequence
|
||||||
|
@ -45,15 +44,9 @@ namespace SafeExamBrowser.Contracts.Core.OperationModel
|
||||||
OperationResult TryPerform();
|
OperationResult TryPerform();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to repeat the operations of this sequence according to their initialized order. If any operation fails, the already
|
/// Tries to revert the operations of this sequence in reversion of their initialized order. The reversion of all operations will
|
||||||
/// performed operations will not be reverted.
|
/// continue, even if one or multiple operations fail to revert successfully.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
OperationResult TryRepeat();
|
OperationResult TryRevert();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tries to revert the operations of this sequence. Returns <c>true</c> if all operations were reverted without errors,
|
|
||||||
/// otherwise <c>false</c>. The reversion of all operations will continue, even if one or multiple operations fail.
|
|
||||||
/// </summary>
|
|
||||||
bool TryRevert();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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.Core.OperationModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines an operation which can be executed multiple times as part of an <see cref="IRepeatableOperationSequence"/>.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRepeatableOperation : IOperation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Repeats the operation.
|
||||||
|
/// </summary>
|
||||||
|
OperationResult Repeat();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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.Core.OperationModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A sequence of <see cref="IRepeatableOperation"/> which can be used for repeatable sequential procedures.
|
||||||
|
///
|
||||||
|
/// Exemplary execution order for a sequence initialized with operations A, B, C, D:
|
||||||
|
///
|
||||||
|
/// <see cref="TryRepeat()"/>: A -> B -> C -> D.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRepeatableOperationSequence : IOperationSequence
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to repeat the operations of this sequence according to their initialized order. If any operation fails, the already
|
||||||
|
/// repeated operations will not be reverted.
|
||||||
|
/// </summary>
|
||||||
|
OperationResult TryRepeat();
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@
|
||||||
namespace SafeExamBrowser.Contracts.Core.OperationModel
|
namespace SafeExamBrowser.Contracts.Core.OperationModel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the result of the sequential execution of <see cref="IOperation"/>s (as part of an <see cref="IOperationSequence"/>).
|
/// Defines the operation result of the execution of an <see cref="IOperation"/> resp. <see cref="IOperationSequence"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum OperationResult
|
public enum OperationResult
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,6 +63,8 @@
|
||||||
<Compile Include="Core\OperationModel\Events\ProgressChangedEventHandler.cs" />
|
<Compile Include="Core\OperationModel\Events\ProgressChangedEventHandler.cs" />
|
||||||
<Compile Include="Core\OperationModel\Events\StatusChangedEventHandler.cs" />
|
<Compile Include="Core\OperationModel\Events\StatusChangedEventHandler.cs" />
|
||||||
<Compile Include="Core\OperationModel\IOperationSequence.cs" />
|
<Compile Include="Core\OperationModel\IOperationSequence.cs" />
|
||||||
|
<Compile Include="Core\OperationModel\IRepeatableOperation.cs" />
|
||||||
|
<Compile Include="Core\OperationModel\IRepeatableOperationSequence.cs" />
|
||||||
<Compile Include="Core\OperationModel\OperationResult.cs" />
|
<Compile Include="Core\OperationModel\OperationResult.cs" />
|
||||||
<Compile Include="Browser\DownloadEventArgs.cs" />
|
<Compile Include="Browser\DownloadEventArgs.cs" />
|
||||||
<Compile Include="Browser\DownloadFinishedCallback.cs" />
|
<Compile Include="Browser\DownloadFinishedCallback.cs" />
|
||||||
|
|
|
@ -303,159 +303,6 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Repeat Tests
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustCorrectlyAbortRepeat()
|
|
||||||
{
|
|
||||||
var operationA = new Mock<IOperation>();
|
|
||||||
var operationB = new Mock<IOperation>();
|
|
||||||
var operationC = new Mock<IOperation>();
|
|
||||||
var operations = new Queue<IOperation>();
|
|
||||||
|
|
||||||
operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
|
||||||
operationB.Setup(o => o.Repeat()).Returns(OperationResult.Aborted);
|
|
||||||
|
|
||||||
operations.Enqueue(operationA.Object);
|
|
||||||
operations.Enqueue(operationB.Object);
|
|
||||||
operations.Enqueue(operationC.Object);
|
|
||||||
|
|
||||||
var sut = new OperationSequence(loggerMock.Object, operations);
|
|
||||||
var result = sut.TryRepeat();
|
|
||||||
|
|
||||||
operationA.Verify(o => o.Repeat(), Times.Once);
|
|
||||||
operationA.Verify(o => o.Revert(), Times.Never);
|
|
||||||
operationB.Verify(o => o.Repeat(), Times.Once);
|
|
||||||
operationB.Verify(o => o.Revert(), Times.Never);
|
|
||||||
operationC.Verify(o => o.Repeat(), Times.Never);
|
|
||||||
operationC.Verify(o => o.Revert(), Times.Never);
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Aborted, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustRepeatOperations()
|
|
||||||
{
|
|
||||||
var operationA = new Mock<IOperation>();
|
|
||||||
var operationB = new Mock<IOperation>();
|
|
||||||
var operationC = new Mock<IOperation>();
|
|
||||||
var operations = new Queue<IOperation>();
|
|
||||||
|
|
||||||
operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
|
||||||
operationB.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
|
||||||
operationC.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
|
||||||
|
|
||||||
operations.Enqueue(operationA.Object);
|
|
||||||
operations.Enqueue(operationB.Object);
|
|
||||||
operations.Enqueue(operationC.Object);
|
|
||||||
|
|
||||||
var sut = new OperationSequence(loggerMock.Object, operations);
|
|
||||||
var result = sut.TryRepeat();
|
|
||||||
|
|
||||||
operationA.Verify(o => o.Perform(), Times.Never);
|
|
||||||
operationA.Verify(o => o.Repeat(), Times.Once);
|
|
||||||
operationA.Verify(o => o.Revert(), Times.Never);
|
|
||||||
operationB.Verify(o => o.Perform(), Times.Never);
|
|
||||||
operationB.Verify(o => o.Repeat(), Times.Once);
|
|
||||||
operationB.Verify(o => o.Revert(), Times.Never);
|
|
||||||
operationC.Verify(o => o.Perform(), Times.Never);
|
|
||||||
operationC.Verify(o => o.Repeat(), Times.Once);
|
|
||||||
operationC.Verify(o => o.Revert(), Times.Never);
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustRepeatOperationsInSequence()
|
|
||||||
{
|
|
||||||
int current = 0, a = 0, b = 0, c = 0;
|
|
||||||
var operationA = new Mock<IOperation>();
|
|
||||||
var operationB = new Mock<IOperation>();
|
|
||||||
var operationC = new Mock<IOperation>();
|
|
||||||
var operations = new Queue<IOperation>();
|
|
||||||
|
|
||||||
operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success).Callback(() => a = ++current);
|
|
||||||
operationB.Setup(o => o.Repeat()).Returns(OperationResult.Success).Callback(() => b = ++current);
|
|
||||||
operationC.Setup(o => o.Repeat()).Returns(OperationResult.Success).Callback(() => c = ++current);
|
|
||||||
|
|
||||||
operations.Enqueue(operationA.Object);
|
|
||||||
operations.Enqueue(operationB.Object);
|
|
||||||
operations.Enqueue(operationC.Object);
|
|
||||||
|
|
||||||
var sut = new OperationSequence(loggerMock.Object, operations);
|
|
||||||
var result = sut.TryRepeat();
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
|
||||||
Assert.IsTrue(a == 1);
|
|
||||||
Assert.IsTrue(b == 2);
|
|
||||||
Assert.IsTrue(c == 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustNotRevertOperationsInCaseOfError()
|
|
||||||
{
|
|
||||||
var operationA = new Mock<IOperation>();
|
|
||||||
var operationB = new Mock<IOperation>();
|
|
||||||
var operationC = new Mock<IOperation>();
|
|
||||||
var operationD = new Mock<IOperation>();
|
|
||||||
var operations = new Queue<IOperation>();
|
|
||||||
|
|
||||||
operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
|
||||||
operationB.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
|
||||||
operationC.Setup(o => o.Repeat()).Throws<Exception>();
|
|
||||||
|
|
||||||
operations.Enqueue(operationA.Object);
|
|
||||||
operations.Enqueue(operationB.Object);
|
|
||||||
operations.Enqueue(operationC.Object);
|
|
||||||
operations.Enqueue(operationD.Object);
|
|
||||||
|
|
||||||
var sut = new OperationSequence(loggerMock.Object, operations);
|
|
||||||
var result = sut.TryRepeat();
|
|
||||||
|
|
||||||
operationA.Verify(o => o.Repeat(), Times.Once);
|
|
||||||
operationA.Verify(o => o.Revert(), Times.Never);
|
|
||||||
operationB.Verify(o => o.Repeat(), Times.Once);
|
|
||||||
operationB.Verify(o => o.Revert(), Times.Never);
|
|
||||||
operationC.Verify(o => o.Repeat(), Times.Once);
|
|
||||||
operationC.Verify(o => o.Revert(), Times.Never);
|
|
||||||
operationD.Verify(o => o.Repeat(), Times.Never);
|
|
||||||
operationD.Verify(o => o.Revert(), Times.Never);
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Failed, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustSucceedRepeatingWithEmptyQueue()
|
|
||||||
{
|
|
||||||
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
|
||||||
var result = sut.TryRepeat();
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustSucceedRepeatingWithoutCallingPerform()
|
|
||||||
{
|
|
||||||
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
|
||||||
var result = sut.TryRepeat();
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustNotFailInCaseOfUnexpectedErrorWhenRepeating()
|
|
||||||
{
|
|
||||||
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
|
||||||
|
|
||||||
sut.ProgressChanged += (args) => throw new Exception();
|
|
||||||
|
|
||||||
var result = sut.TryRepeat();
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Failed, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Revert Tests
|
#region Revert Tests
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -467,11 +314,11 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
var operations = new Queue<IOperation>();
|
var operations = new Queue<IOperation>();
|
||||||
|
|
||||||
operationA.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
operationA.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
||||||
operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
operationA.Setup(o => o.Revert()).Returns(OperationResult.Success);
|
||||||
operationB.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
operationB.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
||||||
operationB.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
operationB.Setup(o => o.Revert()).Returns(OperationResult.Success);
|
||||||
operationC.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
operationC.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
||||||
operationC.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
operationC.Setup(o => o.Revert()).Returns(OperationResult.Success);
|
||||||
|
|
||||||
operations.Enqueue(operationA.Object);
|
operations.Enqueue(operationA.Object);
|
||||||
operations.Enqueue(operationB.Object);
|
operations.Enqueue(operationB.Object);
|
||||||
|
@ -481,13 +328,13 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
|
|
||||||
sut.TryPerform();
|
sut.TryPerform();
|
||||||
|
|
||||||
var success = sut.TryRevert();
|
var result = sut.TryRevert();
|
||||||
|
|
||||||
operationA.Verify(o => o.Revert(), Times.Once);
|
operationA.Verify(o => o.Revert(), Times.Once);
|
||||||
operationB.Verify(o => o.Revert(), Times.Once);
|
operationB.Verify(o => o.Revert(), Times.Once);
|
||||||
operationC.Verify(o => o.Revert(), Times.Once);
|
operationC.Verify(o => o.Revert(), Times.Once);
|
||||||
|
|
||||||
Assert.IsTrue(success);
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -515,9 +362,9 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
|
|
||||||
sut.TryPerform();
|
sut.TryPerform();
|
||||||
|
|
||||||
var success = sut.TryRevert();
|
var result = sut.TryRevert();
|
||||||
|
|
||||||
Assert.IsTrue(success);
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
Assert.IsTrue(c == 1);
|
Assert.IsTrue(c == 1);
|
||||||
Assert.IsTrue(b == 2);
|
Assert.IsTrue(b == 2);
|
||||||
Assert.IsTrue(a == 3);
|
Assert.IsTrue(a == 3);
|
||||||
|
@ -547,13 +394,13 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
|
|
||||||
sut.TryPerform();
|
sut.TryPerform();
|
||||||
|
|
||||||
var success = sut.TryRevert();
|
var result = sut.TryRevert();
|
||||||
|
|
||||||
operationA.Verify(o => o.Revert(), Times.Once);
|
operationA.Verify(o => o.Revert(), Times.Once);
|
||||||
operationB.Verify(o => o.Revert(), Times.Once);
|
operationB.Verify(o => o.Revert(), Times.Once);
|
||||||
operationC.Verify(o => o.Revert(), Times.Once);
|
operationC.Verify(o => o.Revert(), Times.Once);
|
||||||
|
|
||||||
Assert.IsFalse(success);
|
Assert.AreEqual(OperationResult.Failed, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -565,9 +412,9 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
var operations = new Queue<IOperation>();
|
var operations = new Queue<IOperation>();
|
||||||
|
|
||||||
operationA.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
operationA.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
||||||
operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
operationA.Setup(o => o.Revert()).Returns(OperationResult.Success);
|
||||||
operationB.Setup(o => o.Perform()).Returns(OperationResult.Aborted);
|
operationB.Setup(o => o.Perform()).Returns(OperationResult.Aborted);
|
||||||
operationB.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
operationB.Setup(o => o.Revert()).Returns(OperationResult.Success);
|
||||||
|
|
||||||
operations.Enqueue(operationA.Object);
|
operations.Enqueue(operationA.Object);
|
||||||
operations.Enqueue(operationB.Object);
|
operations.Enqueue(operationB.Object);
|
||||||
|
@ -577,13 +424,13 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
|
|
||||||
sut.TryPerform();
|
sut.TryPerform();
|
||||||
|
|
||||||
var success = sut.TryRevert();
|
var result = sut.TryRevert();
|
||||||
|
|
||||||
operationA.Verify(o => o.Revert(), Times.Once);
|
operationA.Verify(o => o.Revert(), Times.Once);
|
||||||
operationB.Verify(o => o.Revert(), Times.Once);
|
operationB.Verify(o => o.Revert(), Times.Once);
|
||||||
operationC.Verify(o => o.Revert(), Times.Never);
|
operationC.Verify(o => o.Revert(), Times.Never);
|
||||||
|
|
||||||
Assert.IsTrue(success);
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -592,16 +439,19 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
||||||
|
|
||||||
sut.TryPerform();
|
sut.TryPerform();
|
||||||
sut.TryRevert();
|
|
||||||
|
var result = sut.TryRevert();
|
||||||
|
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustSucceedRevertingWithoutCallingPerform()
|
public void MustSucceedRevertingWithoutCallingPerform()
|
||||||
{
|
{
|
||||||
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
||||||
var success = sut.TryRevert();
|
var result = sut.TryRevert();
|
||||||
|
|
||||||
Assert.IsTrue(success);
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -611,9 +461,9 @@ namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
|
|
||||||
sut.ProgressChanged += (args) => throw new Exception();
|
sut.ProgressChanged += (args) => throw new Exception();
|
||||||
|
|
||||||
var success = sut.TryRevert();
|
var result = sut.TryRevert();
|
||||||
|
|
||||||
Assert.IsFalse(success);
|
Assert.AreEqual(OperationResult.Failed, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.UnitTests.OperationModel
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class RepeatableOperationSequenceTests
|
||||||
|
{
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TODO()
|
||||||
|
{
|
||||||
|
Assert.Fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
//[TestMethod]
|
||||||
|
//public void MustCorrectlyAbortRepeat()
|
||||||
|
//{
|
||||||
|
// var operationA = new Mock<IOperation>();
|
||||||
|
// var operationB = new Mock<IOperation>();
|
||||||
|
// var operationC = new Mock<IOperation>();
|
||||||
|
// var operations = new Queue<IOperation>();
|
||||||
|
|
||||||
|
// operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
||||||
|
// operationB.Setup(o => o.Repeat()).Returns(OperationResult.Aborted);
|
||||||
|
|
||||||
|
// operations.Enqueue(operationA.Object);
|
||||||
|
// operations.Enqueue(operationB.Object);
|
||||||
|
// operations.Enqueue(operationC.Object);
|
||||||
|
|
||||||
|
// var sut = new OperationSequence(loggerMock.Object, operations);
|
||||||
|
// var result = sut.TryRepeat();
|
||||||
|
|
||||||
|
// operationA.Verify(o => o.Repeat(), Times.Once);
|
||||||
|
// operationA.Verify(o => o.Revert(), Times.Never);
|
||||||
|
// operationB.Verify(o => o.Repeat(), Times.Once);
|
||||||
|
// operationB.Verify(o => o.Revert(), Times.Never);
|
||||||
|
// operationC.Verify(o => o.Repeat(), Times.Never);
|
||||||
|
// operationC.Verify(o => o.Revert(), Times.Never);
|
||||||
|
|
||||||
|
// Assert.AreEqual(OperationResult.Aborted, result);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[TestMethod]
|
||||||
|
//public void MustRepeatOperations()
|
||||||
|
//{
|
||||||
|
// var operationA = new Mock<IOperation>();
|
||||||
|
// var operationB = new Mock<IOperation>();
|
||||||
|
// var operationC = new Mock<IOperation>();
|
||||||
|
// var operations = new Queue<IOperation>();
|
||||||
|
|
||||||
|
// operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
||||||
|
// operationB.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
||||||
|
// operationC.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
||||||
|
|
||||||
|
// operations.Enqueue(operationA.Object);
|
||||||
|
// operations.Enqueue(operationB.Object);
|
||||||
|
// operations.Enqueue(operationC.Object);
|
||||||
|
|
||||||
|
// var sut = new OperationSequence(loggerMock.Object, operations);
|
||||||
|
// var result = sut.TryRepeat();
|
||||||
|
|
||||||
|
// operationA.Verify(o => o.Perform(), Times.Never);
|
||||||
|
// operationA.Verify(o => o.Repeat(), Times.Once);
|
||||||
|
// operationA.Verify(o => o.Revert(), Times.Never);
|
||||||
|
// operationB.Verify(o => o.Perform(), Times.Never);
|
||||||
|
// operationB.Verify(o => o.Repeat(), Times.Once);
|
||||||
|
// operationB.Verify(o => o.Revert(), Times.Never);
|
||||||
|
// operationC.Verify(o => o.Perform(), Times.Never);
|
||||||
|
// operationC.Verify(o => o.Repeat(), Times.Once);
|
||||||
|
// operationC.Verify(o => o.Revert(), Times.Never);
|
||||||
|
|
||||||
|
// Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[TestMethod]
|
||||||
|
//public void MustRepeatOperationsInSequence()
|
||||||
|
//{
|
||||||
|
// int current = 0, a = 0, b = 0, c = 0;
|
||||||
|
// var operationA = new Mock<IOperation>();
|
||||||
|
// var operationB = new Mock<IOperation>();
|
||||||
|
// var operationC = new Mock<IOperation>();
|
||||||
|
// var operations = new Queue<IOperation>();
|
||||||
|
|
||||||
|
// operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success).Callback(() => a = ++current);
|
||||||
|
// operationB.Setup(o => o.Repeat()).Returns(OperationResult.Success).Callback(() => b = ++current);
|
||||||
|
// operationC.Setup(o => o.Repeat()).Returns(OperationResult.Success).Callback(() => c = ++current);
|
||||||
|
|
||||||
|
// operations.Enqueue(operationA.Object);
|
||||||
|
// operations.Enqueue(operationB.Object);
|
||||||
|
// operations.Enqueue(operationC.Object);
|
||||||
|
|
||||||
|
// var sut = new OperationSequence(loggerMock.Object, operations);
|
||||||
|
// var result = sut.TryRepeat();
|
||||||
|
|
||||||
|
// Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
// Assert.IsTrue(a == 1);
|
||||||
|
// Assert.IsTrue(b == 2);
|
||||||
|
// Assert.IsTrue(c == 3);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[TestMethod]
|
||||||
|
//public void MustNotRevertOperationsInCaseOfError()
|
||||||
|
//{
|
||||||
|
// var operationA = new Mock<IOperation>();
|
||||||
|
// var operationB = new Mock<IOperation>();
|
||||||
|
// var operationC = new Mock<IOperation>();
|
||||||
|
// var operationD = new Mock<IOperation>();
|
||||||
|
// var operations = new Queue<IOperation>();
|
||||||
|
|
||||||
|
// operationA.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
||||||
|
// operationB.Setup(o => o.Repeat()).Returns(OperationResult.Success);
|
||||||
|
// operationC.Setup(o => o.Repeat()).Throws<Exception>();
|
||||||
|
|
||||||
|
// operations.Enqueue(operationA.Object);
|
||||||
|
// operations.Enqueue(operationB.Object);
|
||||||
|
// operations.Enqueue(operationC.Object);
|
||||||
|
// operations.Enqueue(operationD.Object);
|
||||||
|
|
||||||
|
// var sut = new OperationSequence(loggerMock.Object, operations);
|
||||||
|
// var result = sut.TryRepeat();
|
||||||
|
|
||||||
|
// operationA.Verify(o => o.Repeat(), Times.Once);
|
||||||
|
// operationA.Verify(o => o.Revert(), Times.Never);
|
||||||
|
// operationB.Verify(o => o.Repeat(), Times.Once);
|
||||||
|
// operationB.Verify(o => o.Revert(), Times.Never);
|
||||||
|
// operationC.Verify(o => o.Repeat(), Times.Once);
|
||||||
|
// operationC.Verify(o => o.Revert(), Times.Never);
|
||||||
|
// operationD.Verify(o => o.Repeat(), Times.Never);
|
||||||
|
// operationD.Verify(o => o.Revert(), Times.Never);
|
||||||
|
|
||||||
|
// Assert.AreEqual(OperationResult.Failed, result);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[TestMethod]
|
||||||
|
//public void MustSucceedRepeatingWithEmptyQueue()
|
||||||
|
//{
|
||||||
|
// var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
||||||
|
// var result = sut.TryRepeat();
|
||||||
|
|
||||||
|
// Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[TestMethod]
|
||||||
|
//public void MustSucceedRepeatingWithoutCallingPerform()
|
||||||
|
//{
|
||||||
|
// var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
||||||
|
// var result = sut.TryRepeat();
|
||||||
|
|
||||||
|
// Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[TestMethod]
|
||||||
|
//public void MustNotFailInCaseOfUnexpectedErrorWhenRepeating()
|
||||||
|
//{
|
||||||
|
// var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
|
||||||
|
|
||||||
|
// sut.ProgressChanged += (args) => throw new Exception();
|
||||||
|
|
||||||
|
// var result = sut.TryRepeat();
|
||||||
|
|
||||||
|
// Assert.AreEqual(OperationResult.Failed, result);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,11 +58,11 @@ namespace SafeExamBrowser.Core.UnitTests.Operations
|
||||||
|
|
||||||
var perform = sut.Perform();
|
var perform = sut.Perform();
|
||||||
var repeat = sut.Repeat();
|
var repeat = sut.Repeat();
|
||||||
|
var revert = sut.Revert();
|
||||||
sut.Revert();
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, perform);
|
Assert.AreEqual(OperationResult.Success, perform);
|
||||||
Assert.AreEqual(OperationResult.Success, repeat);
|
Assert.AreEqual(OperationResult.Success, repeat);
|
||||||
|
Assert.AreEqual(OperationResult.Success, revert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
|
@ -52,12 +51,5 @@ namespace SafeExamBrowser.Core.UnitTests.Operations
|
||||||
|
|
||||||
text.VerifyNoOtherCalls();
|
text.VerifyNoOtherCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(InvalidOperationException))]
|
|
||||||
public void MustNotAllowRepeating()
|
|
||||||
{
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,20 +45,6 @@ namespace SafeExamBrowser.Core.UnitTests.Operations
|
||||||
Assert.IsTrue(initialized);
|
Assert.IsTrue(initialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[ExpectedException(typeof(NullReferenceException))]
|
|
||||||
public void MustNotInstantiateOperationOnRepeat()
|
|
||||||
{
|
|
||||||
IOperation initialize()
|
|
||||||
{
|
|
||||||
return operationMock.Object;
|
|
||||||
};
|
|
||||||
|
|
||||||
var sut = new LazyInitializationOperation(initialize);
|
|
||||||
|
|
||||||
sut.Repeat();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[ExpectedException(typeof(NullReferenceException))]
|
[ExpectedException(typeof(NullReferenceException))]
|
||||||
public void MustNotInstantiateOperationOnRevert()
|
public void MustNotInstantiateOperationOnRevert()
|
||||||
|
@ -82,16 +68,14 @@ namespace SafeExamBrowser.Core.UnitTests.Operations
|
||||||
};
|
};
|
||||||
|
|
||||||
operationMock.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
operationMock.Setup(o => o.Perform()).Returns(OperationResult.Success);
|
||||||
operationMock.Setup(o => o.Repeat()).Returns(OperationResult.Failed);
|
operationMock.Setup(o => o.Revert()).Returns(OperationResult.Failed);
|
||||||
|
|
||||||
var sut = new LazyInitializationOperation(initialize);
|
var sut = new LazyInitializationOperation(initialize);
|
||||||
var perform = sut.Perform();
|
var perform = sut.Perform();
|
||||||
var repeat = sut.Repeat();
|
var revert = sut.Revert();
|
||||||
|
|
||||||
sut.Revert();
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, perform);
|
Assert.AreEqual(OperationResult.Success, perform);
|
||||||
Assert.AreEqual(OperationResult.Failed, repeat);
|
Assert.AreEqual(OperationResult.Failed, revert);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -147,6 +131,8 @@ namespace SafeExamBrowser.Core.UnitTests.Operations
|
||||||
{
|
{
|
||||||
if (first)
|
if (first)
|
||||||
{
|
{
|
||||||
|
first = false;
|
||||||
|
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,11 +142,9 @@ namespace SafeExamBrowser.Core.UnitTests.Operations
|
||||||
var sut = new LazyInitializationOperation(initialize);
|
var sut = new LazyInitializationOperation(initialize);
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
sut.Repeat();
|
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
|
||||||
operationMock.Verify(o => o.Perform(), Times.Once);
|
operationMock.Verify(o => o.Perform(), Times.Once);
|
||||||
operationMock.Verify(o => o.Repeat(), Times.Once);
|
|
||||||
operationMock.Verify(o => o.Revert(), Times.Once);
|
operationMock.Verify(o => o.Revert(), Times.Once);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="OperationModel\QueueExtensionTests.cs" />
|
<Compile Include="OperationModel\QueueExtensionTests.cs" />
|
||||||
|
<Compile Include="OperationModel\RepeatableOperationSequenceTests.cs" />
|
||||||
<Compile Include="Operations\CommunicationHostOperationTests.cs" />
|
<Compile Include="Operations\CommunicationHostOperationTests.cs" />
|
||||||
<Compile Include="Operations\LazyInitializationOperationTests.cs" />
|
<Compile Include="Operations\LazyInitializationOperationTests.cs" />
|
||||||
<Compile Include="Operations\I18nOperationTests.cs" />
|
<Compile Include="Operations\I18nOperationTests.cs" />
|
||||||
|
|
|
@ -20,9 +20,9 @@ namespace SafeExamBrowser.Core.OperationModel
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OperationSequence : IOperationSequence
|
public class OperationSequence : IOperationSequence
|
||||||
{
|
{
|
||||||
private ILogger logger;
|
protected ILogger logger;
|
||||||
private Queue<IOperation> operations = new Queue<IOperation>();
|
protected Queue<IOperation> operations = new Queue<IOperation>();
|
||||||
private Stack<IOperation> stack = new Stack<IOperation>();
|
protected Stack<IOperation> stack = new Stack<IOperation>();
|
||||||
|
|
||||||
public event ActionRequiredEventHandler ActionRequired
|
public event ActionRequiredEventHandler ActionRequired
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,7 @@ namespace SafeExamBrowser.Core.OperationModel
|
||||||
this.operations = new Queue<IOperation>(operations);
|
this.operations = new Queue<IOperation>(operations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult TryPerform()
|
public virtual OperationResult TryPerform()
|
||||||
{
|
{
|
||||||
var result = OperationResult.Failed;
|
var result = OperationResult.Failed;
|
||||||
|
|
||||||
|
@ -66,53 +66,36 @@ namespace SafeExamBrowser.Core.OperationModel
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult TryRepeat()
|
public virtual OperationResult TryRevert()
|
||||||
{
|
{
|
||||||
var result = OperationResult.Failed;
|
var result = OperationResult.Failed;
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
result = Repeat();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
logger.Error("Failed to repeat operations!", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryRevert()
|
|
||||||
{
|
|
||||||
var success = false;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Initialize(true);
|
Initialize(true);
|
||||||
success = Revert();
|
result = Revert();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger.Error("Failed to revert operations!", e);
|
logger.Error("Failed to revert operations!", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Initialize(bool indeterminate = false)
|
protected virtual void Initialize(bool indeterminate = false)
|
||||||
{
|
{
|
||||||
if (indeterminate)
|
if (indeterminate)
|
||||||
{
|
{
|
||||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { IsIndeterminate = true });
|
UpdateProgress(new ProgressChangedEventArgs { IsIndeterminate = true });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { CurrentValue = 0, MaxValue = operations.Count });
|
UpdateProgress(new ProgressChangedEventArgs { CurrentValue = 0, MaxValue = operations.Count });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private OperationResult Perform()
|
protected virtual OperationResult Perform()
|
||||||
{
|
{
|
||||||
foreach (var operation in operations)
|
foreach (var operation in operations)
|
||||||
{
|
{
|
||||||
|
@ -134,39 +117,13 @@ namespace SafeExamBrowser.Core.OperationModel
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { Progress = true });
|
UpdateProgress(new ProgressChangedEventArgs { Progress = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OperationResult Repeat()
|
protected virtual OperationResult Revert(bool regress = false)
|
||||||
{
|
|
||||||
foreach (var operation in operations)
|
|
||||||
{
|
|
||||||
var result = OperationResult.Failed;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = operation.Repeat();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
logger.Error($"Caught unexpected exception while repeating operation '{operation.GetType().Name}'!", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != OperationResult.Success)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { Progress = true });
|
|
||||||
}
|
|
||||||
|
|
||||||
return OperationResult.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool Revert(bool regress = false)
|
|
||||||
{
|
{
|
||||||
var success = true;
|
var success = true;
|
||||||
|
|
||||||
|
@ -176,21 +133,31 @@ namespace SafeExamBrowser.Core.OperationModel
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
operation.Revert();
|
var result = operation.Revert();
|
||||||
|
|
||||||
|
if (result != OperationResult.Success)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger.Error($"Failed to revert operation '{operation.GetType().Name}'!", e);
|
logger.Error($"Caught unexpected exception while reverting operation '{operation.GetType().Name}'!", e);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regress)
|
if (regress)
|
||||||
{
|
{
|
||||||
ProgressChanged?.Invoke(new ProgressChangedEventArgs { Regress = true });
|
UpdateProgress(new ProgressChangedEventArgs { Regress = true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success ? OperationResult.Success : OperationResult.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void UpdateProgress(ProgressChangedEventArgs args)
|
||||||
|
{
|
||||||
|
ProgressChanged?.Invoke(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
|
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.OperationModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default implementation of the <see cref="IRepeatableOperationSequence"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class RepeatableOperationSequence : OperationSequence, IRepeatableOperationSequence
|
||||||
|
{
|
||||||
|
private new Queue<IRepeatableOperation> operations;
|
||||||
|
|
||||||
|
public RepeatableOperationSequence(ILogger logger, Queue<IRepeatableOperation> operations) : base(logger, new Queue<IOperation>(operations))
|
||||||
|
{
|
||||||
|
this.operations = new Queue<IRepeatableOperation>(operations);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationResult TryRepeat()
|
||||||
|
{
|
||||||
|
var result = OperationResult.Failed;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
result = Repeat();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error("Failed to repeat operations!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OperationResult Repeat()
|
||||||
|
{
|
||||||
|
foreach (var operation in operations)
|
||||||
|
{
|
||||||
|
var result = OperationResult.Failed;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = operation.Repeat();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error($"Caught unexpected exception while repeating operation '{operation.GetType().Name}'!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != OperationResult.Success)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateProgress(new ProgressChangedEventArgs { Progress = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ namespace SafeExamBrowser.Core.Operations
|
||||||
/// An operation to handle the lifetime of an <see cref="ICommunicationHost"/>. The host is started during <see cref="Perform"/>,
|
/// An operation to handle the lifetime of an <see cref="ICommunicationHost"/>. The host is started during <see cref="Perform"/>,
|
||||||
/// stopped and restarted during <see cref="Repeat"/> (if not running) and stopped during <see cref="Revert"/>.
|
/// stopped and restarted during <see cref="Repeat"/> (if not running) and stopped during <see cref="Revert"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CommunicationHostOperation : IOperation
|
public class CommunicationHostOperation : IRepeatableOperation
|
||||||
{
|
{
|
||||||
private ICommunicationHost host;
|
private ICommunicationHost host;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
@ -56,12 +56,14 @@ namespace SafeExamBrowser.Core.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Revert()
|
public OperationResult Revert()
|
||||||
{
|
{
|
||||||
logger.Info("Stopping communication host...");
|
logger.Info("Stopping communication host...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_StopCommunicationHost);
|
StatusChanged?.Invoke(TextKey.OperationStatus_StopCommunicationHost);
|
||||||
|
|
||||||
host.Stop();
|
host.Stop();
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace SafeExamBrowser.Core.Operations
|
||||||
/// A generic operation to allow for the (inline) definition of an operation via delegates. Useful if implementing a complete
|
/// A generic operation to allow for the (inline) definition of an operation via delegates. Useful if implementing a complete
|
||||||
/// <see cref="IOperation"/> would be an unnecessary overhead.
|
/// <see cref="IOperation"/> would be an unnecessary overhead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DelegateOperation : IOperation
|
public class DelegateOperation : IRepeatableOperation
|
||||||
{
|
{
|
||||||
private Action perform;
|
private Action perform;
|
||||||
private Action repeat;
|
private Action repeat;
|
||||||
|
@ -46,9 +46,11 @@ namespace SafeExamBrowser.Core.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Revert()
|
public OperationResult Revert()
|
||||||
{
|
{
|
||||||
revert?.Invoke();
|
revert?.Invoke();
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
||||||
|
@ -43,14 +42,9 @@ namespace SafeExamBrowser.Core.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"The '{nameof(I18nOperation)}' is not meant to be repeated!");
|
return OperationResult.Success;
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
|
||||||
// Nothing to do here...
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,14 +83,9 @@ namespace SafeExamBrowser.Core.Operations
|
||||||
return operation.Perform();
|
return operation.Perform();
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Revert()
|
||||||
{
|
{
|
||||||
return operation.Repeat();
|
return operation.Revert();
|
||||||
}
|
|
||||||
|
|
||||||
public void Revert()
|
|
||||||
{
|
|
||||||
operation.Revert();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="OperationModel\QueueExtensions.cs" />
|
<Compile Include="OperationModel\QueueExtensions.cs" />
|
||||||
|
<Compile Include="OperationModel\RepeatableOperationSequence.cs" />
|
||||||
<Compile Include="Operations\CommunicationHostOperation.cs" />
|
<Compile Include="Operations\CommunicationHostOperation.cs" />
|
||||||
<Compile Include="Operations\LazyInitializationOperation.cs" />
|
<Compile Include="Operations\LazyInitializationOperation.cs" />
|
||||||
<Compile Include="Operations\I18nOperation.cs" />
|
<Compile Include="Operations\I18nOperation.cs" />
|
||||||
|
|
|
@ -117,7 +117,7 @@ namespace SafeExamBrowser.Monitoring.Windows
|
||||||
|
|
||||||
private void OnWindowChanged(IntPtr window)
|
private void OnWindowChanged(IntPtr window)
|
||||||
{
|
{
|
||||||
if (activeWindow != window)
|
if (window != IntPtr.Zero && activeWindow != window)
|
||||||
{
|
{
|
||||||
logger.Debug($"Window has changed from {activeWindow} to {window}.");
|
logger.Debug($"Window has changed from {activeWindow} to {window}.");
|
||||||
activeWindow = window;
|
activeWindow = window;
|
||||||
|
|
|
@ -84,26 +84,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustStartClientWhenRepeating()
|
|
||||||
{
|
|
||||||
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(communication);
|
|
||||||
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), true)).Returns(true);
|
|
||||||
|
|
||||||
result = sut.Repeat();
|
|
||||||
|
|
||||||
session.VerifySet(s => s.ClientProcess = process.Object, Times.Once);
|
|
||||||
session.VerifySet(s => s.ClientProxy = proxy.Object, Times.Once);
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustFailStartupIfClientNotStartedWithinTimeout()
|
public void MustFailStartupIfClientNotStartedWithinTimeout()
|
||||||
{
|
{
|
||||||
|
@ -153,6 +133,87 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
Assert.AreEqual(OperationResult.Failed, result);
|
Assert.AreEqual(OperationResult.Failed, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustStartClientWhenRepeating()
|
||||||
|
{
|
||||||
|
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(communication);
|
||||||
|
proxy.Setup(p => p.Connect(It.IsAny<Guid>(), true)).Returns(true);
|
||||||
|
|
||||||
|
result = sut.Repeat();
|
||||||
|
|
||||||
|
session.VerifySet(s => s.ClientProcess = process.Object, Times.Once);
|
||||||
|
session.VerifySet(s => s.ClientProxy = proxy.Object, Times.Once);
|
||||||
|
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustTerminateClientOnRepeat()
|
||||||
|
{
|
||||||
|
var terminated = new Action(() =>
|
||||||
|
{
|
||||||
|
runtimeHost.Raise(h => h.ClientDisconnected += null);
|
||||||
|
process.Raise(p => p.Terminated += null, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
proxy.Setup(p => p.Disconnect()).Callback(terminated);
|
||||||
|
session.SetupGet(s => s.ClientProcess).Returns(process.Object);
|
||||||
|
|
||||||
|
var result = sut.Repeat();
|
||||||
|
|
||||||
|
proxy.Verify(p => p.InitiateShutdown(), Times.Once);
|
||||||
|
proxy.Verify(p => p.Disconnect(), Times.Once);
|
||||||
|
process.Verify(p => p.Kill(), Times.Never);
|
||||||
|
session.VerifySet(s => s.ClientProcess = null, Times.Once);
|
||||||
|
session.VerifySet(s => s.ClientProxy = null, Times.Once);
|
||||||
|
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustDoNothingIfNoClientCreated()
|
||||||
|
{
|
||||||
|
session.SetupGet(s => s.ClientProcess).Returns(null as IProcess);
|
||||||
|
|
||||||
|
var result = sut.Repeat();
|
||||||
|
|
||||||
|
session.VerifyGet(s => s.ClientProcess, Times.Once);
|
||||||
|
|
||||||
|
process.VerifyNoOtherCalls();
|
||||||
|
processFactory.VerifyNoOtherCalls();
|
||||||
|
proxy.VerifyNoOtherCalls();
|
||||||
|
proxyFactory.VerifyNoOtherCalls();
|
||||||
|
runtimeHost.VerifyNoOtherCalls();
|
||||||
|
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustDoNothingIfNoClientRunning()
|
||||||
|
{
|
||||||
|
process.SetupGet(p => p.HasTerminated).Returns(true);
|
||||||
|
session.SetupGet(s => s.ClientProcess).Returns(process.Object);
|
||||||
|
|
||||||
|
var result = sut.Repeat();
|
||||||
|
|
||||||
|
process.VerifyGet(p => p.HasTerminated, Times.Once);
|
||||||
|
session.VerifyGet(s => s.ClientProcess, Times.Exactly(2));
|
||||||
|
|
||||||
|
process.VerifyNoOtherCalls();
|
||||||
|
processFactory.VerifyNoOtherCalls();
|
||||||
|
proxy.VerifyNoOtherCalls();
|
||||||
|
proxyFactory.VerifyNoOtherCalls();
|
||||||
|
runtimeHost.VerifyNoOtherCalls();
|
||||||
|
|
||||||
|
Assert.AreEqual(OperationResult.Success, result);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustStopClientWhenReverting()
|
public void MustStopClientWhenReverting()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,144 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using Moq;
|
|
||||||
using SafeExamBrowser.Contracts.Communication.Hosts;
|
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
|
||||||
using SafeExamBrowser.Contracts.WindowsApi;
|
|
||||||
using SafeExamBrowser.Runtime.Operations;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
|
||||||
{
|
|
||||||
[TestClass]
|
|
||||||
public class ClientTerminationOperationTests
|
|
||||||
{
|
|
||||||
private Action clientReady;
|
|
||||||
private AppConfig appConfig;
|
|
||||||
private Mock<IConfigurationRepository> configuration;
|
|
||||||
private Mock<IClientProxy> proxy;
|
|
||||||
private Mock<ILogger> logger;
|
|
||||||
private Mock<IProcess> process;
|
|
||||||
private Mock<IProcessFactory> processFactory;
|
|
||||||
private Mock<IProxyFactory> proxyFactory;
|
|
||||||
private Mock<IRuntimeHost> runtimeHost;
|
|
||||||
private Mock<ISessionData> session;
|
|
||||||
private ClientTerminationOperation sut;
|
|
||||||
|
|
||||||
[TestInitialize]
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
appConfig = new AppConfig();
|
|
||||||
configuration = new Mock<IConfigurationRepository>();
|
|
||||||
clientReady = new Action(() => runtimeHost.Raise(h => h.ClientReady += null));
|
|
||||||
logger = new Mock<ILogger>();
|
|
||||||
process = new Mock<IProcess>();
|
|
||||||
processFactory = new Mock<IProcessFactory>();
|
|
||||||
proxy = new Mock<IClientProxy>();
|
|
||||||
proxyFactory = new Mock<IProxyFactory>();
|
|
||||||
runtimeHost = new Mock<IRuntimeHost>();
|
|
||||||
session = new Mock<ISessionData>();
|
|
||||||
|
|
||||||
configuration.SetupGet(c => c.CurrentSession).Returns(session.Object);
|
|
||||||
configuration.SetupGet(c => c.AppConfig).Returns(appConfig);
|
|
||||||
proxyFactory.Setup(f => f.CreateClientProxy(It.IsAny<string>())).Returns(proxy.Object);
|
|
||||||
session.SetupGet(s => s.ClientProxy).Returns(proxy.Object);
|
|
||||||
|
|
||||||
sut = new ClientTerminationOperation(configuration.Object, logger.Object, processFactory.Object, proxyFactory.Object, runtimeHost.Object, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustDoNothingOnPerform()
|
|
||||||
{
|
|
||||||
sut.Perform();
|
|
||||||
|
|
||||||
process.VerifyNoOtherCalls();
|
|
||||||
processFactory.VerifyNoOtherCalls();
|
|
||||||
proxy.VerifyNoOtherCalls();
|
|
||||||
proxyFactory.VerifyNoOtherCalls();
|
|
||||||
runtimeHost.VerifyNoOtherCalls();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustDoNothingOnRevert()
|
|
||||||
{
|
|
||||||
sut.Revert();
|
|
||||||
|
|
||||||
process.VerifyNoOtherCalls();
|
|
||||||
processFactory.VerifyNoOtherCalls();
|
|
||||||
proxy.VerifyNoOtherCalls();
|
|
||||||
proxyFactory.VerifyNoOtherCalls();
|
|
||||||
runtimeHost.VerifyNoOtherCalls();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustTerminateClientOnRepeat()
|
|
||||||
{
|
|
||||||
var terminated = new Action(() =>
|
|
||||||
{
|
|
||||||
runtimeHost.Raise(h => h.ClientDisconnected += null);
|
|
||||||
process.Raise(p => p.Terminated += null, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
proxy.Setup(p => p.Disconnect()).Callback(terminated);
|
|
||||||
session.SetupGet(s => s.ClientProcess).Returns(process.Object);
|
|
||||||
|
|
||||||
var result = sut.Repeat();
|
|
||||||
|
|
||||||
proxy.Verify(p => p.InitiateShutdown(), Times.Once);
|
|
||||||
proxy.Verify(p => p.Disconnect(), Times.Once);
|
|
||||||
process.Verify(p => p.Kill(), Times.Never);
|
|
||||||
session.VerifySet(s => s.ClientProcess = null, Times.Once);
|
|
||||||
session.VerifySet(s => s.ClientProxy = null, Times.Once);
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustDoNothingIfNoClientCreated()
|
|
||||||
{
|
|
||||||
session.SetupGet(s => s.ClientProcess).Returns(null as IProcess);
|
|
||||||
|
|
||||||
var result = sut.Repeat();
|
|
||||||
|
|
||||||
session.VerifyGet(s => s.ClientProcess, Times.Once);
|
|
||||||
|
|
||||||
process.VerifyNoOtherCalls();
|
|
||||||
processFactory.VerifyNoOtherCalls();
|
|
||||||
proxy.VerifyNoOtherCalls();
|
|
||||||
proxyFactory.VerifyNoOtherCalls();
|
|
||||||
runtimeHost.VerifyNoOtherCalls();
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MustDoNothingIfNoClientRunning()
|
|
||||||
{
|
|
||||||
process.SetupGet(p => p.HasTerminated).Returns(true);
|
|
||||||
session.SetupGet(s => s.ClientProcess).Returns(process.Object);
|
|
||||||
|
|
||||||
var result = sut.Repeat();
|
|
||||||
|
|
||||||
process.VerifyGet(p => p.HasTerminated, Times.Once);
|
|
||||||
session.VerifyGet(s => s.ClientProcess, Times.Exactly(2));
|
|
||||||
|
|
||||||
process.VerifyNoOtherCalls();
|
|
||||||
processFactory.VerifyNoOtherCalls();
|
|
||||||
proxy.VerifyNoOtherCalls();
|
|
||||||
proxyFactory.VerifyNoOtherCalls();
|
|
||||||
runtimeHost.VerifyNoOtherCalls();
|
|
||||||
|
|
||||||
Assert.AreEqual(OperationResult.Success, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -90,8 +90,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustCorrectlyRevertCreateNewDesktop()
|
public void MustCorrectlyRevertCreateNewDesktop()
|
||||||
{
|
{
|
||||||
var originalDesktop = new Mock<IDesktop>();
|
|
||||||
var newDesktop = new Mock<IDesktop>();
|
var newDesktop = new Mock<IDesktop>();
|
||||||
|
var originalDesktop = new Mock<IDesktop>();
|
||||||
var order = 0;
|
var order = 0;
|
||||||
var activate = 0;
|
var activate = 0;
|
||||||
var setStartup = 0;
|
var setStartup = 0;
|
||||||
|
@ -135,8 +135,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustCorrectlySwitchToOtherKioskModeWhenRepeating()
|
public void MustCorrectlySwitchToOtherKioskModeWhenRepeating()
|
||||||
{
|
{
|
||||||
var originalDesktop = new Mock<IDesktop>();
|
|
||||||
var newDesktop = new Mock<IDesktop>();
|
var newDesktop = new Mock<IDesktop>();
|
||||||
|
var originalDesktop = new Mock<IDesktop>();
|
||||||
|
|
||||||
desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object);
|
desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object);
|
||||||
desktopFactory.Setup(f => f.CreateNew(It.IsAny<string>())).Returns(newDesktop.Object);
|
desktopFactory.Setup(f => f.CreateNew(It.IsAny<string>())).Returns(newDesktop.Object);
|
||||||
|
@ -192,8 +192,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustNotReinitializeCreateNewDesktopWhenRepeating()
|
public void MustNotReinitializeCreateNewDesktopWhenRepeating()
|
||||||
{
|
{
|
||||||
var originalDesktop = new Mock<IDesktop>();
|
|
||||||
var newDesktop = new Mock<IDesktop>();
|
var newDesktop = new Mock<IDesktop>();
|
||||||
|
var originalDesktop = new Mock<IDesktop>();
|
||||||
|
|
||||||
settings.KioskMode = KioskMode.CreateNewDesktop;
|
settings.KioskMode = KioskMode.CreateNewDesktop;
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,6 @@
|
||||||
<Compile Include="Operations\KioskModeOperationTests.cs" />
|
<Compile Include="Operations\KioskModeOperationTests.cs" />
|
||||||
<Compile Include="Operations\ServiceOperationTests.cs" />
|
<Compile Include="Operations\ServiceOperationTests.cs" />
|
||||||
<Compile Include="Operations\ClientOperationTests.cs" />
|
<Compile Include="Operations\ClientOperationTests.cs" />
|
||||||
<Compile Include="Operations\ClientTerminationOperationTests.cs" />
|
|
||||||
<Compile Include="Operations\SessionInitializationOperationTests.cs" />
|
<Compile Include="Operations\SessionInitializationOperationTests.cs" />
|
||||||
<Compile Include="RuntimeControllerTests.cs" />
|
<Compile Include="RuntimeControllerTests.cs" />
|
||||||
<Compile Include="Communication\RuntimeHostTests.cs" />
|
<Compile Include="Communication\RuntimeHostTests.cs" />
|
||||||
|
|
|
@ -66,20 +66,21 @@ namespace SafeExamBrowser.Runtime
|
||||||
var uiFactory = new UserInterfaceFactory(text);
|
var uiFactory = new UserInterfaceFactory(text);
|
||||||
|
|
||||||
var bootstrapOperations = new Queue<IOperation>();
|
var bootstrapOperations = new Queue<IOperation>();
|
||||||
var sessionOperations = new Queue<IOperation>();
|
var sessionOperations = new Queue<IRepeatableOperation>();
|
||||||
|
|
||||||
bootstrapOperations.Enqueue(new I18nOperation(logger, text, textResource));
|
bootstrapOperations.Enqueue(new I18nOperation(logger, text, textResource));
|
||||||
bootstrapOperations.Enqueue(new CommunicationHostOperation(runtimeHost, logger));
|
bootstrapOperations.Enqueue(new CommunicationHostOperation(runtimeHost, logger));
|
||||||
|
|
||||||
sessionOperations.Enqueue(new ConfigurationOperation(appConfig, configuration, logger, resourceLoader, args));
|
sessionOperations.Enqueue(new ConfigurationOperation(appConfig, configuration, logger, resourceLoader, args));
|
||||||
|
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, FIFTEEN_SECONDS));
|
||||||
|
sessionOperations.Enqueue(new KioskModeTerminationOperation(configuration, desktopFactory, explorerShell, logger, processFactory));
|
||||||
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
|
sessionOperations.Enqueue(new SessionInitializationOperation(configuration, logger, runtimeHost));
|
||||||
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy));
|
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy));
|
||||||
sessionOperations.Enqueue(new ClientTerminationOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, FIFTEEN_SECONDS));
|
|
||||||
sessionOperations.Enqueue(new KioskModeOperation(configuration, desktopFactory, explorerShell, logger, processFactory));
|
sessionOperations.Enqueue(new KioskModeOperation(configuration, desktopFactory, explorerShell, logger, processFactory));
|
||||||
sessionOperations.Enqueue(new ClientOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, FIFTEEN_SECONDS));
|
sessionOperations.Enqueue(new ClientOperation(configuration, logger, processFactory, proxyFactory, runtimeHost, FIFTEEN_SECONDS));
|
||||||
|
|
||||||
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
var bootstrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||||
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
var sessionSequence = new RepeatableOperationSequence(logger, sessionOperations);
|
||||||
|
|
||||||
RuntimeController = new RuntimeController(appConfig, configuration, logger, messageBox, bootstrapSequence, sessionSequence, runtimeHost, serviceProxy, shutdown, text, uiFactory);
|
RuntimeController = new RuntimeController(appConfig, configuration, logger, messageBox, bootstrapSequence, sessionSequence, runtimeHost, serviceProxy, shutdown, text, uiFactory);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,26 +20,26 @@ using SafeExamBrowser.Contracts.WindowsApi.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Operations
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
internal class ClientOperation : IOperation
|
internal class ClientOperation : IRepeatableOperation
|
||||||
{
|
{
|
||||||
private readonly int timeout_ms;
|
private readonly int timeout_ms;
|
||||||
|
|
||||||
protected IConfigurationRepository configuration;
|
private IConfigurationRepository configuration;
|
||||||
protected ILogger logger;
|
private ILogger logger;
|
||||||
protected IProcessFactory processFactory;
|
private IProcessFactory processFactory;
|
||||||
protected IProxyFactory proxyFactory;
|
private IProxyFactory proxyFactory;
|
||||||
protected IRuntimeHost runtimeHost;
|
private IRuntimeHost runtimeHost;
|
||||||
|
|
||||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||||
public event StatusChangedEventHandler StatusChanged;
|
public event StatusChangedEventHandler StatusChanged;
|
||||||
|
|
||||||
protected IProcess ClientProcess
|
private IProcess ClientProcess
|
||||||
{
|
{
|
||||||
get { return configuration.CurrentSession.ClientProcess; }
|
get { return configuration.CurrentSession.ClientProcess; }
|
||||||
set { configuration.CurrentSession.ClientProcess = value; }
|
set { configuration.CurrentSession.ClientProcess = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IClientProxy ClientProxy
|
private IClientProxy ClientProxy
|
||||||
{
|
{
|
||||||
get { return configuration.CurrentSession.ClientProxy; }
|
get { return configuration.CurrentSession.ClientProxy; }
|
||||||
set { configuration.CurrentSession.ClientProxy = value; }
|
set { configuration.CurrentSession.ClientProxy = value; }
|
||||||
|
@ -84,16 +84,20 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return Perform();
|
return Perform();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Revert()
|
public virtual OperationResult Revert()
|
||||||
{
|
{
|
||||||
|
var success = true;
|
||||||
|
|
||||||
if (ClientProcess != null && !ClientProcess.HasTerminated)
|
if (ClientProcess != null && !ClientProcess.HasTerminated)
|
||||||
{
|
{
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_StopClient);
|
StatusChanged?.Invoke(TextKey.OperationStatus_StopClient);
|
||||||
TryStopClient();
|
success = TryStopClient();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool TryStartClient()
|
return success ? OperationResult.Success : OperationResult.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryStartClient()
|
||||||
{
|
{
|
||||||
var clientReady = false;
|
var clientReady = false;
|
||||||
var clientReadyEvent = new AutoResetEvent(false);
|
var clientReadyEvent = new AutoResetEvent(false);
|
||||||
|
@ -146,7 +150,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool TryStopClient()
|
private bool TryStopClient()
|
||||||
{
|
{
|
||||||
var success = false;
|
var success = false;
|
||||||
|
|
||||||
|
@ -206,7 +210,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool TryKillClient(int attempt = 0)
|
private bool TryKillClient(int attempt = 0)
|
||||||
{
|
{
|
||||||
const int MAX_ATTEMPTS = 5;
|
const int MAX_ATTEMPTS = 5;
|
||||||
|
|
||||||
|
|
|
@ -10,18 +10,13 @@ using SafeExamBrowser.Contracts.Communication.Hosts;
|
||||||
using SafeExamBrowser.Contracts.Communication.Proxies;
|
using SafeExamBrowser.Contracts.Communication.Proxies;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel;
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
using SafeExamBrowser.Contracts.Core.OperationModel.Events;
|
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.WindowsApi;
|
using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Operations
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
internal class ClientTerminationOperation : ClientOperation
|
internal class ClientTerminationOperation : ClientOperation, IRepeatableOperation
|
||||||
{
|
{
|
||||||
public new event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
|
||||||
public new event StatusChangedEventHandler StatusChanged;
|
|
||||||
|
|
||||||
public ClientTerminationOperation(
|
public ClientTerminationOperation(
|
||||||
IConfigurationRepository configuration,
|
IConfigurationRepository configuration,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
|
@ -39,20 +34,12 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
public override OperationResult Repeat()
|
public override OperationResult Repeat()
|
||||||
{
|
{
|
||||||
var success = true;
|
return base.Revert();
|
||||||
|
}
|
||||||
|
|
||||||
if (ClientProcess != null && !ClientProcess.HasTerminated)
|
public override OperationResult Revert()
|
||||||
{
|
{
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_StopClient);
|
return OperationResult.Success;
|
||||||
success = TryStopClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
return success ? OperationResult.Success : OperationResult.Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Revert()
|
|
||||||
{
|
|
||||||
// Nothing to do here...
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ using SafeExamBrowser.Runtime.Operations.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Operations
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
internal class ConfigurationOperation : IOperation
|
internal class ConfigurationOperation : IRepeatableOperation
|
||||||
{
|
{
|
||||||
private IConfigurationRepository configuration;
|
private IConfigurationRepository configuration;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
@ -92,9 +92,9 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return OperationResult.Failed;
|
return OperationResult.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Revert()
|
public OperationResult Revert()
|
||||||
{
|
{
|
||||||
// Nothing to do here...
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OperationResult LoadSettings(Uri uri)
|
private OperationResult LoadSettings(Uri uri)
|
||||||
|
|
|
@ -16,7 +16,7 @@ using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Operations
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
internal class KioskModeOperation : IOperation
|
internal class KioskModeOperation : IRepeatableOperation
|
||||||
{
|
{
|
||||||
private IConfigurationRepository configuration;
|
private IConfigurationRepository configuration;
|
||||||
private IDesktopFactory desktopFactory;
|
private IDesktopFactory desktopFactory;
|
||||||
|
@ -24,12 +24,22 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
private KioskMode kioskMode;
|
private KioskMode kioskMode;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private IProcessFactory processFactory;
|
private IProcessFactory processFactory;
|
||||||
private IDesktop newDesktop;
|
|
||||||
private IDesktop originalDesktop;
|
|
||||||
|
|
||||||
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||||
public event StatusChangedEventHandler StatusChanged;
|
public event StatusChangedEventHandler StatusChanged;
|
||||||
|
|
||||||
|
private IDesktop NewDesktop
|
||||||
|
{
|
||||||
|
get { return configuration.CurrentSession.NewDesktop; }
|
||||||
|
set { configuration.CurrentSession.NewDesktop = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private IDesktop OriginalDesktop
|
||||||
|
{
|
||||||
|
get { return configuration.CurrentSession.OriginalDesktop; }
|
||||||
|
set { configuration.CurrentSession.OriginalDesktop = value; }
|
||||||
|
}
|
||||||
|
|
||||||
public KioskModeOperation(
|
public KioskModeOperation(
|
||||||
IConfigurationRepository configuration,
|
IConfigurationRepository configuration,
|
||||||
IDesktopFactory desktopFactory,
|
IDesktopFactory desktopFactory,
|
||||||
|
@ -44,7 +54,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
this.processFactory = processFactory;
|
this.processFactory = processFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Perform()
|
public virtual OperationResult Perform()
|
||||||
{
|
{
|
||||||
kioskMode = configuration.CurrentSettings.KioskMode;
|
kioskMode = configuration.CurrentSettings.KioskMode;
|
||||||
|
|
||||||
|
@ -64,7 +74,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public virtual OperationResult Repeat()
|
||||||
{
|
{
|
||||||
var oldMode = kioskMode;
|
var oldMode = kioskMode;
|
||||||
var newMode = configuration.CurrentSettings.KioskMode;
|
var newMode = configuration.CurrentSettings.KioskMode;
|
||||||
|
@ -72,19 +82,14 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
if (newMode == oldMode)
|
if (newMode == oldMode)
|
||||||
{
|
{
|
||||||
logger.Info($"New kiosk mode '{newMode}' is equal to the currently active '{oldMode}', skipping re-initialization...");
|
logger.Info($"New kiosk mode '{newMode}' is equal to the currently active '{oldMode}', skipping re-initialization...");
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Revert();
|
|
||||||
Perform();
|
|
||||||
}
|
|
||||||
|
|
||||||
kioskMode = newMode;
|
|
||||||
|
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Revert()
|
return Perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual OperationResult Revert()
|
||||||
{
|
{
|
||||||
logger.Info($"Reverting kiosk mode '{kioskMode}'...");
|
logger.Info($"Reverting kiosk mode '{kioskMode}'...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_RevertKioskMode);
|
StatusChanged?.Invoke(TextKey.OperationStatus_RevertKioskMode);
|
||||||
|
@ -98,18 +103,20 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
RestartExplorerShell();
|
RestartExplorerShell();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateNewDesktop()
|
private void CreateNewDesktop()
|
||||||
{
|
{
|
||||||
originalDesktop = desktopFactory.GetCurrent();
|
OriginalDesktop = desktopFactory.GetCurrent();
|
||||||
logger.Info($"Current desktop is {originalDesktop}.");
|
logger.Info($"Current desktop is {OriginalDesktop}.");
|
||||||
|
|
||||||
newDesktop = desktopFactory.CreateNew(nameof(SafeExamBrowser));
|
NewDesktop = desktopFactory.CreateNew(nameof(SafeExamBrowser));
|
||||||
logger.Info($"Created new desktop {newDesktop}.");
|
logger.Info($"Created new desktop {NewDesktop}.");
|
||||||
|
|
||||||
newDesktop.Activate();
|
NewDesktop.Activate();
|
||||||
processFactory.StartupDesktop = newDesktop;
|
processFactory.StartupDesktop = NewDesktop;
|
||||||
logger.Info("Successfully activated new desktop.");
|
logger.Info("Successfully activated new desktop.");
|
||||||
|
|
||||||
explorerShell.Suspend();
|
explorerShell.Suspend();
|
||||||
|
@ -117,21 +124,21 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
private void CloseNewDesktop()
|
private void CloseNewDesktop()
|
||||||
{
|
{
|
||||||
if (originalDesktop != null)
|
if (OriginalDesktop != null)
|
||||||
{
|
{
|
||||||
originalDesktop.Activate();
|
OriginalDesktop.Activate();
|
||||||
processFactory.StartupDesktop = originalDesktop;
|
processFactory.StartupDesktop = OriginalDesktop;
|
||||||
logger.Info($"Switched back to original desktop {originalDesktop}.");
|
logger.Info($"Switched back to original desktop {OriginalDesktop}.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.Warn($"No original desktop found when attempting to close new desktop!");
|
logger.Warn($"No original desktop found when attempting to close new desktop!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newDesktop != null)
|
if (NewDesktop != null)
|
||||||
{
|
{
|
||||||
newDesktop.Close();
|
NewDesktop.Close();
|
||||||
logger.Info($"Closed new desktop {newDesktop}.");
|
logger.Info($"Closed new desktop {NewDesktop}.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
|
using SafeExamBrowser.Contracts.Core.OperationModel;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
using SafeExamBrowser.Contracts.WindowsApi;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
{
|
||||||
|
internal class KioskModeTerminationOperation : KioskModeOperation, IRepeatableOperation
|
||||||
|
{
|
||||||
|
private IConfigurationRepository configuration;
|
||||||
|
private KioskMode kioskMode;
|
||||||
|
private ILogger logger;
|
||||||
|
|
||||||
|
public KioskModeTerminationOperation(
|
||||||
|
IConfigurationRepository configuration,
|
||||||
|
IDesktopFactory desktopFactory,
|
||||||
|
IExplorerShell explorerShell,
|
||||||
|
ILogger logger,
|
||||||
|
IProcessFactory processFactory) : base(configuration, desktopFactory, explorerShell, logger, processFactory)
|
||||||
|
{
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override OperationResult Perform()
|
||||||
|
{
|
||||||
|
kioskMode = configuration.CurrentSettings.KioskMode;
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override OperationResult Repeat()
|
||||||
|
{
|
||||||
|
var oldMode = kioskMode;
|
||||||
|
var newMode = configuration.CurrentSettings.KioskMode;
|
||||||
|
|
||||||
|
if (newMode == oldMode)
|
||||||
|
{
|
||||||
|
logger.Info($"New kiosk mode '{newMode}' is equal to the currently active '{oldMode}', skipping termination...");
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.Revert();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override OperationResult Revert()
|
||||||
|
{
|
||||||
|
return OperationResult.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ using SafeExamBrowser.Contracts.Logging;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Operations
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
internal class ServiceOperation : IOperation
|
internal class ServiceOperation : IRepeatableOperation
|
||||||
{
|
{
|
||||||
private bool connected, mandatory;
|
private bool connected, mandatory;
|
||||||
private IConfigurationRepository configuration;
|
private IConfigurationRepository configuration;
|
||||||
|
@ -43,7 +43,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
if (mandatory && !connected)
|
if (mandatory && !connected)
|
||||||
{
|
{
|
||||||
logger.Error("Aborting startup because the service is mandatory but not available!");
|
logger.Error("Failed to initialize a service session since the service is mandatory but not available!");
|
||||||
|
|
||||||
return OperationResult.Failed;
|
return OperationResult.Failed;
|
||||||
}
|
}
|
||||||
|
@ -61,17 +61,17 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Repeat()
|
||||||
{
|
{
|
||||||
// TODO: Re-check if mandatory, if so, try to connect (if not connected) - otherwise, no action required (except maybe logging of status?)
|
var result = Revert();
|
||||||
if (connected)
|
|
||||||
|
if (result != OperationResult.Success)
|
||||||
{
|
{
|
||||||
StopServiceSession();
|
return result;
|
||||||
StartServiceSession();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OperationResult.Success;
|
return Perform();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Revert()
|
public OperationResult Revert()
|
||||||
{
|
{
|
||||||
logger.Info("Finalizing service session...");
|
logger.Info("Finalizing service session...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServiceSession);
|
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServiceSession);
|
||||||
|
@ -91,6 +91,8 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
logger.Error("Failed to disconnect from the service!");
|
logger.Error("Failed to disconnect from the service!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartServiceSession()
|
private void StartServiceSession()
|
||||||
|
|
|
@ -15,7 +15,7 @@ using SafeExamBrowser.Contracts.Logging;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Operations
|
namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
internal class SessionInitializationOperation : IOperation
|
internal class SessionInitializationOperation : IRepeatableOperation
|
||||||
{
|
{
|
||||||
private IConfigurationRepository configuration;
|
private IConfigurationRepository configuration;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
@ -40,14 +40,12 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
public OperationResult Repeat()
|
public OperationResult Repeat()
|
||||||
{
|
{
|
||||||
InitializeSessionConfiguration();
|
return Perform();
|
||||||
|
|
||||||
return OperationResult.Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Revert()
|
public OperationResult Revert()
|
||||||
{
|
{
|
||||||
// Nothing to do here...
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeSessionConfiguration()
|
private void InitializeSessionConfiguration()
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private IMessageBox messageBox;
|
private IMessageBox messageBox;
|
||||||
private IOperationSequence bootstrapSequence;
|
private IOperationSequence bootstrapSequence;
|
||||||
private IOperationSequence sessionSequence;
|
private IRepeatableOperationSequence sessionSequence;
|
||||||
private IRuntimeHost runtimeHost;
|
private IRuntimeHost runtimeHost;
|
||||||
private IRuntimeWindow runtimeWindow;
|
private IRuntimeWindow runtimeWindow;
|
||||||
private IServiceProxy service;
|
private IServiceProxy service;
|
||||||
|
@ -50,7 +50,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IMessageBox messageBox,
|
IMessageBox messageBox,
|
||||||
IOperationSequence bootstrapSequence,
|
IOperationSequence bootstrapSequence,
|
||||||
IOperationSequence sessionSequence,
|
IRepeatableOperationSequence sessionSequence,
|
||||||
IRuntimeHost runtimeHost,
|
IRuntimeHost runtimeHost,
|
||||||
IServiceProxy service,
|
IServiceProxy service,
|
||||||
Action shutdown,
|
Action shutdown,
|
||||||
|
@ -127,7 +127,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
logger.Log(string.Empty);
|
logger.Log(string.Empty);
|
||||||
logger.Info("Initiating shutdown procedure...");
|
logger.Info("Initiating shutdown procedure...");
|
||||||
|
|
||||||
var success = bootstrapSequence.TryRevert();
|
var success = bootstrapSequence.TryRevert() == OperationResult.Success;
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
|
@ -181,8 +181,8 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
if (result == OperationResult.Failed)
|
if (result == OperationResult.Failed)
|
||||||
{
|
{
|
||||||
// TODO: Check if message box is rendered on new desktop as well! -> E.g. if settings for reconfiguration are invalid
|
// TODO: Find solution for this; maybe manually switch back to original desktop?
|
||||||
messageBox.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error, parent: runtimeWindow);
|
// messageBox.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error, parent: runtimeWindow);
|
||||||
|
|
||||||
if (!initial)
|
if (!initial)
|
||||||
{
|
{
|
||||||
|
@ -202,7 +202,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
DeregisterSessionEvents();
|
DeregisterSessionEvents();
|
||||||
|
|
||||||
var success = sessionSequence.TryRevert();
|
var success = sessionSequence.TryRevert() == OperationResult.Success;
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
|
@ -235,38 +235,21 @@ namespace SafeExamBrowser.Runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeregisterSessionEvents()
|
private void DeregisterSessionEvents()
|
||||||
|
{
|
||||||
|
if (configuration.CurrentSession.ClientProcess != null)
|
||||||
{
|
{
|
||||||
configuration.CurrentSession.ClientProcess.Terminated -= ClientProcess_Terminated;
|
configuration.CurrentSession.ClientProcess.Terminated -= ClientProcess_Terminated;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuration.CurrentSession.ClientProxy != null)
|
||||||
|
{
|
||||||
configuration.CurrentSession.ClientProxy.ConnectionLost -= Client_ConnectionLost;
|
configuration.CurrentSession.ClientProxy.ConnectionLost -= Client_ConnectionLost;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void BootstrapSequence_ProgressChanged(ProgressChangedEventArgs args)
|
private void BootstrapSequence_ProgressChanged(ProgressChangedEventArgs args)
|
||||||
{
|
{
|
||||||
// TODO: Duplicated code (for splashScreen as well as runtimeWindow)!
|
MapProgress(splashScreen, args);
|
||||||
if (args.CurrentValue.HasValue)
|
|
||||||
{
|
|
||||||
splashScreen?.SetValue(args.CurrentValue.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.IsIndeterminate == true)
|
|
||||||
{
|
|
||||||
splashScreen?.SetIndeterminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.MaxValue.HasValue)
|
|
||||||
{
|
|
||||||
splashScreen?.SetMaxValue(args.MaxValue.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Progress == true)
|
|
||||||
{
|
|
||||||
splashScreen?.Progress();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Regress == true)
|
|
||||||
{
|
|
||||||
splashScreen?.Regress();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BootstrapSequence_StatusChanged(TextKey status)
|
private void BootstrapSequence_StatusChanged(TextKey status)
|
||||||
|
@ -277,7 +260,12 @@ namespace SafeExamBrowser.Runtime
|
||||||
private void ClientProcess_Terminated(int exitCode)
|
private void ClientProcess_Terminated(int exitCode)
|
||||||
{
|
{
|
||||||
logger.Error($"Client application has unexpectedly terminated with exit code {exitCode}!");
|
logger.Error($"Client application has unexpectedly terminated with exit code {exitCode}!");
|
||||||
// TODO: Check if message box is rendered on new desktop as well -> otherwise shutdown is blocked! Check if parent needed!
|
|
||||||
|
if (sessionRunning)
|
||||||
|
{
|
||||||
|
StopSession();
|
||||||
|
}
|
||||||
|
|
||||||
messageBox.Show(TextKey.MessageBox_ApplicationError, TextKey.MessageBox_ApplicationErrorTitle, icon: MessageBoxIcon.Error);
|
messageBox.Show(TextKey.MessageBox_ApplicationError, TextKey.MessageBox_ApplicationErrorTitle, icon: MessageBoxIcon.Error);
|
||||||
|
|
||||||
shutdown.Invoke();
|
shutdown.Invoke();
|
||||||
|
@ -286,7 +274,12 @@ namespace SafeExamBrowser.Runtime
|
||||||
private void Client_ConnectionLost()
|
private void Client_ConnectionLost()
|
||||||
{
|
{
|
||||||
logger.Error("Lost connection to the client application!");
|
logger.Error("Lost connection to the client application!");
|
||||||
// TODO: Check if message box is rendered on new desktop as well -> otherwise shutdown is blocked! Check if parent needed!
|
|
||||||
|
if (sessionRunning)
|
||||||
|
{
|
||||||
|
StopSession();
|
||||||
|
}
|
||||||
|
|
||||||
messageBox.Show(TextKey.MessageBox_ApplicationError, TextKey.MessageBox_ApplicationErrorTitle, icon: MessageBoxIcon.Error);
|
messageBox.Show(TextKey.MessageBox_ApplicationError, TextKey.MessageBox_ApplicationErrorTitle, icon: MessageBoxIcon.Error);
|
||||||
|
|
||||||
shutdown.Invoke();
|
shutdown.Invoke();
|
||||||
|
@ -400,35 +393,40 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
private void SessionSequence_ProgressChanged(ProgressChangedEventArgs args)
|
private void SessionSequence_ProgressChanged(ProgressChangedEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.CurrentValue.HasValue)
|
MapProgress(runtimeWindow, args);
|
||||||
{
|
|
||||||
runtimeWindow?.SetValue(args.CurrentValue.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.IsIndeterminate == true)
|
|
||||||
{
|
|
||||||
runtimeWindow?.SetIndeterminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.MaxValue.HasValue)
|
|
||||||
{
|
|
||||||
runtimeWindow?.SetMaxValue(args.MaxValue.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Progress == true)
|
|
||||||
{
|
|
||||||
runtimeWindow?.Progress();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Regress == true)
|
|
||||||
{
|
|
||||||
runtimeWindow?.Regress();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SessionSequence_StatusChanged(TextKey status)
|
private void SessionSequence_StatusChanged(TextKey status)
|
||||||
{
|
{
|
||||||
runtimeWindow?.UpdateStatus(status, true);
|
runtimeWindow?.UpdateStatus(status, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MapProgress(IProgressIndicator progressIndicator, ProgressChangedEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.CurrentValue.HasValue)
|
||||||
|
{
|
||||||
|
progressIndicator?.SetValue(args.CurrentValue.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.IsIndeterminate == true)
|
||||||
|
{
|
||||||
|
progressIndicator?.SetIndeterminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.MaxValue.HasValue)
|
||||||
|
{
|
||||||
|
progressIndicator?.SetMaxValue(args.MaxValue.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Progress == true)
|
||||||
|
{
|
||||||
|
progressIndicator?.Progress();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Regress == true)
|
||||||
|
{
|
||||||
|
progressIndicator?.Regress();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@
|
||||||
<Compile Include="Operations\Events\ConfigurationCompletedEventArgs.cs" />
|
<Compile Include="Operations\Events\ConfigurationCompletedEventArgs.cs" />
|
||||||
<Compile Include="Operations\Events\PasswordRequiredEventArgs.cs" />
|
<Compile Include="Operations\Events\PasswordRequiredEventArgs.cs" />
|
||||||
<Compile Include="Operations\KioskModeOperation.cs" />
|
<Compile Include="Operations\KioskModeOperation.cs" />
|
||||||
|
<Compile Include="Operations\KioskModeTerminationOperation.cs" />
|
||||||
<Compile Include="Operations\ServiceOperation.cs" />
|
<Compile Include="Operations\ServiceOperation.cs" />
|
||||||
<Compile Include="Operations\SessionInitializationOperation.cs" />
|
<Compile Include="Operations\SessionInitializationOperation.cs" />
|
||||||
<Compile Include="Communication\ProxyFactory.cs" />
|
<Compile Include="Communication\ProxyFactory.cs" />
|
||||||
|
|
Loading…
Reference in a new issue