Restore SEBPatch
This commit is contained in:
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Client.Communication;
|
||||
using SafeExamBrowser.Communication.Contracts;
|
||||
using SafeExamBrowser.Communication.Contracts.Data;
|
||||
using SafeExamBrowser.Communication.Contracts.Hosts;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||
|
||||
namespace SafeExamBrowser.Client.UnitTests.Communication
|
||||
{
|
||||
[TestClass]
|
||||
public class ClientHostTests
|
||||
{
|
||||
private const int PROCESS_ID = 1234;
|
||||
|
||||
private Mock<IConfigurationRepository> configuration;
|
||||
private Mock<IHostObject> hostObject;
|
||||
private Mock<IHostObjectFactory> hostObjectFactory;
|
||||
private Mock<ILogger> logger;
|
||||
private ClientHost sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
configuration = new Mock<IConfigurationRepository>();
|
||||
hostObject = new Mock<IHostObject>();
|
||||
hostObjectFactory = new Mock<IHostObjectFactory>();
|
||||
logger = new Mock<ILogger>();
|
||||
|
||||
hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object);
|
||||
|
||||
sut = new ClientHost("net:pipe://some/address", hostObjectFactory.Object, logger.Object, PROCESS_ID, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustOnlyAllowConnectionIfTokenIsValid()
|
||||
{
|
||||
var token = Guid.NewGuid();
|
||||
|
||||
sut.AuthenticationToken = token;
|
||||
|
||||
var response = sut.Connect(token);
|
||||
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsTrue(response.ConnectionEstablished);
|
||||
Assert.IsTrue(sut.IsConnected);
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void MustRejectConnectionIfTokenInvalid()
|
||||
{
|
||||
var token = Guid.NewGuid();
|
||||
|
||||
sut.AuthenticationToken = token;
|
||||
|
||||
var response = sut.Connect(Guid.NewGuid());
|
||||
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsFalse(response.ConnectionEstablished);
|
||||
Assert.IsFalse(sut.IsConnected);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustOnlyAllowOneConcurrentConnection()
|
||||
{
|
||||
var token = Guid.NewGuid();
|
||||
|
||||
sut.AuthenticationToken = token;
|
||||
|
||||
var response1 = sut.Connect(token);
|
||||
var response2 = sut.Connect(token);
|
||||
var response3 = sut.Connect(token);
|
||||
|
||||
Assert.IsNotNull(response1);
|
||||
Assert.IsNotNull(response2);
|
||||
Assert.IsNotNull(response3);
|
||||
Assert.IsNotNull(response1.CommunicationToken);
|
||||
Assert.IsNull(response2.CommunicationToken);
|
||||
Assert.IsNull(response3.CommunicationToken);
|
||||
Assert.IsTrue(response1.ConnectionEstablished);
|
||||
Assert.IsFalse(response2.ConnectionEstablished);
|
||||
Assert.IsFalse(response3.ConnectionEstablished);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustCorrectlyDisconnect()
|
||||
{
|
||||
var eventFired = false;
|
||||
var token = Guid.NewGuid();
|
||||
|
||||
sut.RuntimeDisconnected += () => eventFired = true;
|
||||
sut.AuthenticationToken = token;
|
||||
|
||||
var connectionResponse = sut.Connect(token);
|
||||
var message = new DisconnectionMessage
|
||||
{
|
||||
CommunicationToken = connectionResponse.CommunicationToken.Value,
|
||||
Interlocutor = Interlocutor.Runtime
|
||||
};
|
||||
var response = sut.Disconnect(message);
|
||||
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsTrue(response.ConnectionTerminated);
|
||||
Assert.IsTrue(eventFired);
|
||||
Assert.IsFalse(sut.IsConnected);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotAllowReconnectionAfterDisconnection()
|
||||
{
|
||||
var token = sut.AuthenticationToken = Guid.NewGuid();
|
||||
var response = sut.Connect(token);
|
||||
var message = new DisconnectionMessage
|
||||
{
|
||||
CommunicationToken = response.CommunicationToken.Value,
|
||||
Interlocutor = Interlocutor.Runtime
|
||||
};
|
||||
|
||||
sut.Disconnect(message);
|
||||
sut.AuthenticationToken = token = Guid.NewGuid();
|
||||
|
||||
response = sut.Connect(token);
|
||||
|
||||
Assert.IsFalse(response.ConnectionEstablished);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustHandleAuthenticationRequestCorrectly()
|
||||
{
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
var message = new SimpleMessage(SimpleMessagePurport.Authenticate) { CommunicationToken = token };
|
||||
var response = sut.Send(message);
|
||||
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(AuthenticationResponse));
|
||||
Assert.AreEqual(PROCESS_ID, (response as AuthenticationResponse)?.ProcessId);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustHandleExamSelectionRequestCorrectly()
|
||||
{
|
||||
var examSelectionRequested = false;
|
||||
var requestId = Guid.NewGuid();
|
||||
var resetEvent = new AutoResetEvent(false);
|
||||
|
||||
sut.ExamSelectionRequested += (args) =>
|
||||
{
|
||||
examSelectionRequested = true;
|
||||
resetEvent.Set();
|
||||
};
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
var request = new ExamSelectionRequestMessage(Enumerable.Empty<(string id, string lms, string name, string url)>(), requestId) { CommunicationToken = token };
|
||||
var response = sut.Send(request);
|
||||
|
||||
resetEvent.WaitOne();
|
||||
|
||||
Assert.IsTrue(examSelectionRequested);
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||
Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustHandleMessageBoxRequestCorrectly()
|
||||
{
|
||||
var action = (int) MessageBoxAction.YesNo;
|
||||
var icon = (int) MessageBoxIcon.Question;
|
||||
var message = "Qwert kndorz safie abcd?";
|
||||
var messageBoxRequested = false;
|
||||
var requestId = Guid.NewGuid();
|
||||
var resetEvent = new AutoResetEvent(false);
|
||||
var title = "Poiuztrewq!";
|
||||
|
||||
sut.MessageBoxRequested += (args) =>
|
||||
{
|
||||
messageBoxRequested = args.Action == action && args.Icon == icon && args.Message == message && args.RequestId == requestId && args.Title == title;
|
||||
resetEvent.Set();
|
||||
};
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
var request = new MessageBoxRequestMessage(action, icon, message, requestId, title) { CommunicationToken = token };
|
||||
var response = sut.Send(request);
|
||||
|
||||
resetEvent.WaitOne();
|
||||
|
||||
Assert.IsTrue(messageBoxRequested);
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||
Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustHandlePasswordRequestCorrectly()
|
||||
{
|
||||
var passwordRequested = false;
|
||||
var purpose = PasswordRequestPurpose.LocalAdministrator;
|
||||
var requestId = Guid.NewGuid();
|
||||
var resetEvent = new AutoResetEvent(false);
|
||||
|
||||
sut.PasswordRequested += (args) =>
|
||||
{
|
||||
passwordRequested = args.Purpose == purpose && args.RequestId == requestId;
|
||||
resetEvent.Set();
|
||||
};
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
var message = new PasswordRequestMessage(purpose, requestId) { CommunicationToken = token };
|
||||
var response = sut.Send(message);
|
||||
|
||||
resetEvent.WaitOne();
|
||||
|
||||
Assert.IsTrue(passwordRequested);
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||
Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustHandleReconfigurationAbortionCorrectly()
|
||||
{
|
||||
var reconfigurationAborted = false;
|
||||
var resetEvent = new AutoResetEvent(false);
|
||||
|
||||
sut.ReconfigurationAborted += () =>
|
||||
{
|
||||
reconfigurationAborted = true;
|
||||
resetEvent.Set();
|
||||
};
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
var message = new SimpleMessage(SimpleMessagePurport.ReconfigurationAborted) { CommunicationToken = token };
|
||||
var response = sut.Send(message);
|
||||
|
||||
resetEvent.WaitOne();
|
||||
|
||||
Assert.IsTrue(reconfigurationAborted);
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||
Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustHandleReconfigurationDenialCorrectly()
|
||||
{
|
||||
var filePath = @"C:\Some\Random\Path\To\A\File.seb";
|
||||
var reconfigurationDenied = false;
|
||||
var resetEvent = new AutoResetEvent(false);
|
||||
|
||||
sut.ReconfigurationDenied += (args) =>
|
||||
{
|
||||
reconfigurationDenied = new Uri(args.ConfigurationPath).Equals(new Uri(filePath));
|
||||
resetEvent.Set();
|
||||
};
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
var message = new ReconfigurationDeniedMessage(filePath) { CommunicationToken = token };
|
||||
var response = sut.Send(message);
|
||||
|
||||
resetEvent.WaitOne();
|
||||
|
||||
Assert.IsTrue(reconfigurationDenied);
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||
Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustHandleServerFailureCorrectly()
|
||||
{
|
||||
var serverFailureActionRequested = false;
|
||||
var requestId = Guid.NewGuid();
|
||||
var resetEvent = new AutoResetEvent(false);
|
||||
|
||||
sut.ServerFailureActionRequested += (args) =>
|
||||
{
|
||||
serverFailureActionRequested = true;
|
||||
resetEvent.Set();
|
||||
};
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
var request = new ServerFailureActionRequestMessage("", true, requestId) { CommunicationToken = token };
|
||||
var response = sut.Send(request);
|
||||
|
||||
resetEvent.WaitOne();
|
||||
|
||||
Assert.IsTrue(serverFailureActionRequested);
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||
Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustHandleShutdownRequestCorrectly()
|
||||
{
|
||||
var shutdownRequested = false;
|
||||
|
||||
sut.Shutdown += () => shutdownRequested = true;
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
var message = new SimpleMessage(SimpleMessagePurport.Shutdown) { CommunicationToken = token };
|
||||
var response = sut.Send(message);
|
||||
|
||||
Assert.IsTrue(shutdownRequested);
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||
Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustReturnUnknownMessageAsDefault()
|
||||
{
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
var message = new TestMessage { CommunicationToken = token } as Message;
|
||||
var response = sut.Send(message);
|
||||
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||
Assert.AreEqual(SimpleResponsePurport.UnknownMessage, (response as SimpleResponse)?.Purport);
|
||||
|
||||
message = new SimpleMessage(default(SimpleMessagePurport)) { CommunicationToken = token };
|
||||
response = sut.Send(message);
|
||||
|
||||
Assert.IsNotNull(response);
|
||||
Assert.IsInstanceOfType(response, typeof(SimpleResponse));
|
||||
Assert.AreEqual(SimpleResponsePurport.UnknownMessage, (response as SimpleResponse)?.Purport);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailIfNoEventHandlersSubscribed()
|
||||
{
|
||||
sut.AuthenticationToken = Guid.Empty;
|
||||
|
||||
var token = sut.Connect(Guid.Empty).CommunicationToken.Value;
|
||||
|
||||
sut.Send(new MessageBoxRequestMessage(default(int), default(int), "", Guid.Empty, "") { CommunicationToken = token });
|
||||
sut.Send(new PasswordRequestMessage(default(PasswordRequestPurpose), Guid.Empty) { CommunicationToken = token });
|
||||
sut.Send(new SimpleMessage(SimpleMessagePurport.ReconfigurationAborted));
|
||||
sut.Send(new ReconfigurationDeniedMessage("") { CommunicationToken = token });
|
||||
sut.Send(new SimpleMessage(SimpleMessagePurport.Shutdown) { CommunicationToken = token });
|
||||
sut.Disconnect(new DisconnectionMessage { CommunicationToken = token, Interlocutor = Interlocutor.Runtime });
|
||||
}
|
||||
|
||||
private class TestMessage : Message { };
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user