/* * Copyright (c) 2021 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.ServiceModel; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Communication.Contracts; using SafeExamBrowser.Communication.Contracts.Data; using SafeExamBrowser.Communication.Contracts.Hosts; using SafeExamBrowser.Logging.Contracts; namespace SafeExamBrowser.Communication.UnitTests.Hosts { [TestClass] public class BaseHostTests { private Mock hostObject; private Mock hostObjectFactory; private Mock logger; private BaseHostStub sut; [TestInitialize] public void Initialize() { hostObject = new Mock(); hostObjectFactory = new Mock(); logger = new Mock(); hostObjectFactory.Setup(f => f.CreateObject(It.IsAny(), It.IsAny())).Returns(hostObject.Object); sut = new BaseHostStub("net.pipe://some/address/here", hostObjectFactory.Object, logger.Object, 10); } [TestMethod] public void MustCorrectlyStartHost() { var threadId = Thread.CurrentThread.ManagedThreadId; hostObject.Setup(h => h.Open()).Callback(() => threadId = Thread.CurrentThread.ManagedThreadId); sut.Start(); hostObjectFactory.Verify(f => f.CreateObject(It.IsAny(), sut), Times.Once); Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); } [TestMethod] [ExpectedException(typeof(CommunicationException))] public void MustCorrectlyHandleStartupException() { hostObject.Setup(h => h.Open()).Throws(); sut.Start(); } [TestMethod] public void MustCorrectlyStopHost() { sut.Start(); sut.Stop(); hostObject.Verify(h => h.Close(), Times.Once); } [TestMethod] [ExpectedException(typeof(CommunicationException))] public void MustCorrectlyHandleShutdownException() { hostObject.Setup(h => h.Close()).Throws(); sut.Start(); sut.Stop(); } [TestMethod] public void MustNotFailToStopIfNotRunning() { sut.Stop(); sut.Stop(); sut.Stop(); } [TestMethod] public void MustNotFailToEvaluateIsRunningIfNotRunning() { var running = sut.IsRunning; Assert.IsFalse(running); } [TestMethod] public void MustCorrectlyIndicateWhetherHostIsRunning() { hostObject.SetupGet(h => h.State).Returns(CommunicationState.Faulted); sut.Start(); Assert.IsFalse(sut.IsRunning); hostObject.SetupGet(h => h.State).Returns(CommunicationState.Opened); Assert.IsTrue(sut.IsRunning); } [TestMethod] public void MustCorrectlyHandleConnectionRequest() { var token = Guid.NewGuid(); var receivedToken = default(Guid?); sut.OnConnectStub = (t) => { receivedToken = t; return true; }; var response = sut.Connect(token); Assert.IsTrue(response.ConnectionEstablished); Assert.AreEqual(token, receivedToken); Assert.AreEqual(sut.GetCommunicationToken(), response.CommunicationToken); } [TestMethod] public void MustCorrectlyHandleDeniedConnectionRequest() { var token = Guid.NewGuid(); var receivedToken = default(Guid?); sut.OnConnectStub = (t) => { receivedToken = t; return false; }; var response = sut.Connect(token); Assert.IsFalse(response.ConnectionEstablished); Assert.AreEqual(token, receivedToken); Assert.IsNull(sut.GetCommunicationToken()); Assert.IsNull(response.CommunicationToken); } [TestMethod] public void MustCorrectlyHandleDisconnectionRequest() { var message = new DisconnectionMessage { Interlocutor = Interlocutor.Runtime }; var disconnected = false; var interlocutor = Interlocutor.Unknown; sut.OnConnectStub = (t) => { return true; }; sut.OnDisconnectStub = (i) => { disconnected = true; interlocutor = i; }; sut.Connect(); message.CommunicationToken = sut.GetCommunicationToken().Value; var response = sut.Disconnect(message); Assert.AreEqual(message.Interlocutor, interlocutor); Assert.IsTrue(disconnected); Assert.IsTrue(response.ConnectionTerminated); Assert.IsNull(sut.GetCommunicationToken()); } [TestMethod] public void MustCorrectlyHandleUnauthorizedDisconnectionRequest() { var disconnected = false; sut.OnConnectStub = (t) => { return true; }; sut.OnDisconnectStub = (i) => disconnected = true; sut.Connect(); var response = sut.Disconnect(new DisconnectionMessage()); Assert.IsFalse(disconnected); Assert.IsFalse(response.ConnectionTerminated); Assert.IsNotNull(sut.GetCommunicationToken()); } [TestMethod] public void MustCorrectlyHandleUnauthorizedTransmission() { var received = false; var simpleReceived = false; sut.OnReceiveStub = (m) => { received = true; return null; }; sut.OnReceiveSimpleMessageStub = (m) => { simpleReceived = true; return null; }; var response = sut.Send(new DisconnectionMessage()); Assert.IsFalse(received); Assert.IsFalse(simpleReceived); Assert.IsInstanceOfType(response, typeof(SimpleResponse)); Assert.AreEqual(SimpleResponsePurport.Unauthorized, (response as SimpleResponse)?.Purport); } [TestMethod] public void MustCorrectlyHandlePingMessage() { var received = false; var simpleReceived = false; var message = new SimpleMessage(SimpleMessagePurport.Ping); sut.OnReceiveStub = (m) => { received = true; return null; }; sut.OnReceiveSimpleMessageStub = (m) => { simpleReceived = true; return null; }; sut.OnConnectStub = (t) => { return true; }; sut.Connect(); message.CommunicationToken = sut.GetCommunicationToken().Value; var response = sut.Send(message); Assert.IsFalse(received); Assert.IsFalse(simpleReceived); Assert.IsInstanceOfType(response, typeof(SimpleResponse)); Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport); } [TestMethod] public void MustCorrectlyReceiveSimpleMessage() { var received = false; var simpleReceived = false; var purport = default(SimpleMessagePurport); var message = new SimpleMessage(SimpleMessagePurport.ConfigurationNeeded); var simpleResponse = new SimpleResponse(SimpleResponsePurport.UnknownMessage); sut.OnReceiveStub = (m) => { received = true; return null; }; sut.OnReceiveSimpleMessageStub = (m) => { simpleReceived = true; purport = m; return simpleResponse; }; sut.OnConnectStub = (t) => { return true; }; sut.Connect(); message.CommunicationToken = sut.GetCommunicationToken().Value; var response = sut.Send(message); Assert.IsFalse(received); Assert.IsTrue(simpleReceived); Assert.IsInstanceOfType(response, typeof(SimpleResponse)); Assert.AreEqual(SimpleMessagePurport.ConfigurationNeeded, purport); Assert.AreSame(simpleResponse, response); } [TestMethod] public void MustCorrectlyReceiveMessage() { var received = false; var simpleReceived = false; var message = new ReconfigurationMessage(null, null); var configurationResponse = new ConfigurationResponse(); sut.OnReceiveStub = (m) => { received = true; return configurationResponse; }; sut.OnReceiveSimpleMessageStub = (m) => { simpleReceived = true; return null; }; sut.OnConnectStub = (t) => { return true; }; sut.Connect(); message.CommunicationToken = sut.GetCommunicationToken().Value; var response = sut.Send(message); Assert.IsTrue(received); Assert.IsFalse(simpleReceived); Assert.IsInstanceOfType(response, typeof(ConfigurationResponse)); Assert.AreSame(configurationResponse, response); } [TestMethod] public void MustLogStatusChangesOfHost() { sut.Start(); hostObject.Raise(h => h.Closed += null, It.IsAny()); hostObject.Raise(h => h.Closing += null, It.IsAny()); hostObject.Raise(h => h.Faulted += null, It.IsAny()); hostObject.Raise(h => h.Opened += null, It.IsAny()); hostObject.Raise(h => h.Opening += null, It.IsAny()); logger.Verify(l => l.Debug(It.IsAny()), Times.AtLeast(4)); logger.Verify(l => l.Error(It.IsAny()), Times.Once); } } }