diff --git a/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyImpl.cs b/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyImpl.cs index cf0d2b7d..efc4d2f2 100644 --- a/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyImpl.cs +++ b/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyImpl.cs @@ -35,5 +35,30 @@ namespace SafeExamBrowser.Core.UnitTests.Communication { return base.Send(message); } + + public new Response Send(SimpleMessagePurport purport) + { + return base.Send(purport); + } + + public new bool IsAcknowledged(Response response) + { + return base.IsAcknowledged(response); + } + + public new void TestConnection() + { + base.TestConnection(); + } + + public new string ToString(Message message) + { + return base.ToString(message); + } + + public new string ToString(Response response) + { + return base.ToString(response); + } } } diff --git a/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyTests.cs b/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyTests.cs index a1d55c10..8bb613d6 100644 --- a/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Communication/BaseProxyTests.cs @@ -14,7 +14,6 @@ using SafeExamBrowser.Contracts.Communication; using SafeExamBrowser.Contracts.Communication.Messages; using SafeExamBrowser.Contracts.Communication.Responses; using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Core.Communication; namespace SafeExamBrowser.Core.UnitTests.Communication { @@ -23,7 +22,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication { private Mock proxyObjectFactory; private Mock logger; - private BaseProxy sut; + private BaseProxyImpl sut; [TestInitialize] public void Initialize() @@ -139,7 +138,7 @@ namespace SafeExamBrowser.Core.UnitTests.Communication [ExpectedException(typeof(InvalidOperationException))] public void MustFailToSendIfNotConnected() { - (sut as BaseProxyImpl).Send(new Mock().Object); + sut.Send(new Mock().Object); } [TestMethod] @@ -160,14 +159,14 @@ namespace SafeExamBrowser.Core.UnitTests.Communication var token = Guid.NewGuid(); sut.Connect(token); - (sut as BaseProxyImpl).Send(new Mock().Object); + sut.Send(new Mock().Object); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void MustNotAllowSendingNull() { - (sut as BaseProxyImpl).Send(null); + sut.Send(null); } [TestMethod] @@ -189,10 +188,143 @@ namespace SafeExamBrowser.Core.UnitTests.Communication var token = Guid.NewGuid(); var connected = sut.Connect(token); - var received = (sut as BaseProxyImpl).Send(message); + var received = sut.Send(message); Assert.AreEqual(response.Object, received); Assert.AreEqual(connectionResponse.CommunicationToken, message.CommunicationToken); } + + [TestMethod] + public void MustSendSimpleMessageCorrectly() + { + var proxy = new Mock(); + var connectionResponse = new ConnectionResponse + { + CommunicationToken = Guid.NewGuid(), + ConnectionEstablished = true + }; + var purport = SimpleMessagePurport.Authenticate; + var response = new Mock(); + + proxy.Setup(p => p.Connect(It.IsAny())).Returns(connectionResponse); + proxy.Setup(p => p.Send(It.IsAny())).Returns(response.Object); + proxy.As().Setup(o => o.State).Returns(CommunicationState.Opened); + proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).Returns(proxy.Object); + + var token = Guid.NewGuid(); + var connected = sut.Connect(token); + var received = sut.Send(purport); + + proxy.Verify(p => p.Send(It.Is(m => m.Purport == purport))); + } + + [TestMethod] + public void MustTestAcknowledgeResponsesCorrectly() + { + var nullResponse = sut.IsAcknowledged(null); + var notAcknowledge = sut.IsAcknowledged(new SimpleResponse(SimpleResponsePurport.Unauthorized)); + var acknowledge = sut.IsAcknowledged(new SimpleResponse(SimpleResponsePurport.Acknowledged)); + + Assert.IsFalse(nullResponse); + Assert.IsFalse(notAcknowledge); + Assert.IsTrue(acknowledge); + } + + [TestMethod] + public void MustToStringSafely() + { + var message = new Mock(); + var response = new Mock(); + + message.Setup(m => m.ToString()).Returns(nameof(Message)); + response.Setup(r => r.ToString()).Returns(nameof(Response)); + + var nullStringMessage = sut.ToString(null as Message); + var nullStringResponse = sut.ToString(null as Response); + var messageString = sut.ToString(message.Object); + var responseString = sut.ToString(response.Object); + + Assert.IsNotNull(nullStringMessage); + Assert.IsNotNull(nullStringResponse); + Assert.IsNotNull(messageString); + Assert.IsNotNull(responseString); + Assert.AreEqual(message.Object.ToString(), messageString); + Assert.AreEqual(response.Object.ToString(), responseString); + } + + [TestMethod] + public void TestConnectionMustPingHost() + { + var proxy = new Mock(); + var connectionResponse = new ConnectionResponse + { + CommunicationToken = Guid.NewGuid(), + ConnectionEstablished = true + }; + + proxy.Setup(p => p.Connect(It.IsAny())).Returns(connectionResponse); + proxy.Setup(p => p.Send(It.Is(m => m.Purport == SimpleMessagePurport.Ping))).Returns(new SimpleResponse(SimpleResponsePurport.Acknowledged)); + proxy.As().Setup(o => o.State).Returns(CommunicationState.Opened); + proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).Returns(proxy.Object); + + var token = Guid.NewGuid(); + var connected = sut.Connect(token); + + sut.TestConnection(); + + proxy.Verify(); + } + + [TestMethod] + public void TestConnectionMustInvokeConnectionLostEvent() + { + var lost = false; + var proxy = new Mock(); + var connectionResponse = new ConnectionResponse + { + CommunicationToken = Guid.NewGuid(), + ConnectionEstablished = true + }; + + sut.ConnectionLost += () => lost = true; + + proxy.Setup(p => p.Connect(It.IsAny())).Returns(connectionResponse); + proxy.Setup(p => p.Send(It.Is(m => m.Purport == SimpleMessagePurport.Ping))).Returns(new SimpleResponse(SimpleResponsePurport.UnknownMessage)); + proxy.As().Setup(o => o.State).Returns(CommunicationState.Opened); + proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).Returns(proxy.Object); + + var token = Guid.NewGuid(); + var connected = sut.Connect(token); + + sut.TestConnection(); + + Assert.IsTrue(lost); + } + + [TestMethod] + public void TestConnectionMustNotFail() + { + var lost = false; + var proxy = new Mock(); + var connectionResponse = new ConnectionResponse + { + CommunicationToken = Guid.NewGuid(), + ConnectionEstablished = true + }; + + sut.ConnectionLost += () => lost = true; + + proxy.Setup(p => p.Connect(It.IsAny())).Returns(connectionResponse); + proxy.Setup(p => p.Send(It.IsAny())).Throws(); + proxy.As().Setup(o => o.State).Returns(CommunicationState.Opened); + proxyObjectFactory.Setup(f => f.CreateObject(It.IsAny())).Returns(proxy.Object); + + var token = Guid.NewGuid(); + var connected = sut.Connect(token); + + sut.TestConnection(); + + Assert.IsTrue(lost); + } } } diff --git a/SafeExamBrowser.Core/Communication/BaseProxy.cs b/SafeExamBrowser.Core/Communication/BaseProxy.cs index 1a6088d0..7cd2b884 100644 --- a/SafeExamBrowser.Core/Communication/BaseProxy.cs +++ b/SafeExamBrowser.Core/Communication/BaseProxy.cs @@ -122,6 +122,35 @@ namespace SafeExamBrowser.Core.Communication return response is SimpleResponse simpleResponse && simpleResponse.Purport == SimpleResponsePurport.Acknowledged; } + /// + /// Tests whether the connection to the host is alive by sending a ping message. If the transmission of the message fails or it is + /// not acknowledged, the event is fired and the auto-ping timer stopped (if it was initialized). + /// + protected void TestConnection() + { + try + { + var response = Send(SimpleMessagePurport.Ping); + + if (IsAcknowledged(response)) + { + Logger.Info("Pinged host, connection is alive."); + } + else + { + Logger.Error($"Host did not acknowledge ping message! Received: {ToString(response)}."); + timer?.Stop(); + ConnectionLost?.Invoke(); + } + } + catch (Exception e) + { + Logger.Error("Failed to ping host!", e); + timer?.Stop(); + ConnectionLost?.Invoke(); + } + } + /// /// Retrieves the string representation of the given , or indicates that a message is null. /// @@ -205,27 +234,7 @@ namespace SafeExamBrowser.Core.Communication { if (timer.Enabled) { - try - { - var response = Send(SimpleMessagePurport.Ping); - - if (IsAcknowledged(response)) - { - Logger.Info("Pinged host, connection is alive."); - } - else - { - Logger.Error($"Host did not acknowledge ping message! Received: {ToString(response)}."); - timer.Stop(); - ConnectionLost?.Invoke(); - } - } - catch (Exception e) - { - Logger.Error("Failed to ping host!", e); - timer.Stop(); - ConnectionLost?.Invoke(); - } + TestConnection(); } } }