/* * 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.Collections.Generic; using System.IO; using System.Reflection; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Configuration.ConfigurationData; using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts.Cryptography; using SafeExamBrowser.Configuration.Contracts.DataFormats; using SafeExamBrowser.Configuration.Contracts.DataResources; using SafeExamBrowser.Logging.Contracts; namespace SafeExamBrowser.Configuration.UnitTests { [TestClass] public class ConfigurationRepositoryTests { private ConfigurationRepository sut; private Mock binaryParser; private Mock binarySerializer; private Mock certificateStore; private Mock fileLoader; private Mock fileSaver; private Mock logger; private Mock networkLoader; private Mock xmlParser; private Mock xmlSerializer; [TestInitialize] public void Initialize() { binaryParser = new Mock(); binarySerializer = new Mock(); certificateStore = new Mock(); fileLoader = new Mock(); fileSaver = new Mock(); logger = new Mock(); networkLoader = new Mock(); xmlParser = new Mock(); xmlSerializer = new Mock(); fileLoader.Setup(f => f.CanLoad(It.IsAny())).Returns(u => u.IsFile); fileSaver.Setup(f => f.CanSave(It.IsAny())).Returns(u => u.IsFile); networkLoader.Setup(n => n.CanLoad(It.IsAny())).Returns(u => u.Scheme.Equals("http") || u.Scheme.Equals("seb")); SetEntryAssembly(); sut = new ConfigurationRepository(certificateStore.Object, logger.Object); sut.InitializeAppConfig(); } [TestMethod] public void ConfigureClient_MustWorkAsExpected() { var stream = new MemoryStream() as Stream; var password = new PasswordParameters { Password = "test123" }; var parseResult = new ParseResult { Format = FormatType.Binary, RawData = new Dictionary(), Status = LoadStatus.Success }; var serializeResult = new SerializeResult { Data = new MemoryStream(), Status = SaveStatus.Success }; RegisterModules(); fileLoader.Setup(n => n.TryLoad(It.IsAny(), out stream)).Returns(LoadStatus.Success); binaryParser.Setup(b => b.CanParse(It.IsAny())).Returns(true); binaryParser.Setup(b => b.TryParse(It.IsAny(), It.IsAny())).Returns(parseResult); binarySerializer.Setup(b => b.CanSerialize(FormatType.Binary)).Returns(true); binarySerializer.Setup(b => b.TrySerialize(It.IsAny>(), It.IsAny())).Returns(serializeResult); fileSaver.Setup(f => f.TrySave(It.IsAny(), It.IsAny())).Returns(SaveStatus.Success); var status = sut.ConfigureClientWith(new Uri("C:\\TEMP\\Some\\file.seb"), password); fileLoader.Verify(n => n.TryLoad(It.IsAny(), out stream), Times.Once); binaryParser.Verify(b => b.TryParse(It.IsAny(), It.IsAny()), Times.Once); certificateStore.Verify(c => c.ExtractAndImportIdentities(It.IsAny>()), Times.Once); binarySerializer.Verify(b => b.TrySerialize( It.IsAny>(), It.Is(p => p.IsHash == true && p.Password == string.Empty)), Times.Once); fileSaver.Verify(f => f.TrySave(It.IsAny(), It.IsAny()), Times.Once); Assert.AreEqual(SaveStatus.Success, status); } [TestMethod] public void ConfigureClient_MustKeepSameEncryptionAccordingToConfiguration() { var stream = new MemoryStream() as Stream; var password = new PasswordParameters { Password = "test123" }; var parseResult = new ParseResult { Encryption = new PublicKeyParameters { InnerEncryption = password, SymmetricEncryption = true }, Format = FormatType.Binary, RawData = new Dictionary { { Keys.ConfigurationFile.KeepClientConfigEncryption, true } }, Status = LoadStatus.Success }; var serializeResult = new SerializeResult { Data = new MemoryStream(), Status = SaveStatus.Success }; RegisterModules(); fileLoader.Setup(n => n.TryLoad(It.IsAny(), out stream)).Returns(LoadStatus.Success); binaryParser.Setup(b => b.CanParse(It.IsAny())).Returns(true); binaryParser.Setup(b => b.TryParse(It.IsAny(), It.IsAny())).Returns(parseResult); binarySerializer.Setup(b => b.CanSerialize(FormatType.Binary)).Returns(true); binarySerializer.Setup(b => b.TrySerialize(It.IsAny>(), It.IsAny())).Returns(serializeResult); fileSaver.Setup(f => f.TrySave(It.IsAny(), It.IsAny())).Returns(SaveStatus.Success); var status = sut.ConfigureClientWith(new Uri("C:\\TEMP\\Some\\file.seb"), password); binarySerializer.Verify(b => b.TrySerialize( It.IsAny>(), It.Is(p => p.InnerEncryption == password && p.SymmetricEncryption)), Times.Once); Assert.AreEqual(SaveStatus.Success, status); } [TestMethod] public void ConfigureClient_MustAbortProcessOnError() { var stream = new MemoryStream() as Stream; var password = new PasswordParameters { Password = "test123" }; var parseResult = new ParseResult { Format = FormatType.Binary, RawData = new Dictionary(), Status = LoadStatus.Success }; var serializeResult = new SerializeResult { Data = new MemoryStream(), Status = SaveStatus.Success }; RegisterModules(); fileLoader.Setup(n => n.TryLoad(It.IsAny(), out stream)).Returns(LoadStatus.Success); binaryParser.Setup(b => b.CanParse(It.IsAny())).Throws(); var status = sut.ConfigureClientWith(new Uri("C:\\TEMP\\Some\\file.seb"), password); fileLoader.Verify(n => n.TryLoad(It.IsAny(), out stream), Times.Once); binaryParser.Verify(b => b.TryParse(It.IsAny(), It.IsAny()), Times.Never); certificateStore.Verify(c => c.ExtractAndImportIdentities(It.IsAny>()), Times.Never); binarySerializer.Verify(b => b.TrySerialize(It.IsAny>(), It.IsAny()), Times.Never); fileSaver.Verify(f => f.TrySave(It.IsAny(), It.IsAny()), Times.Never); Assert.AreEqual(SaveStatus.UnexpectedError, status); } [TestMethod] public void TryLoad_MustWorkAsExpected() { var stream = new MemoryStream() as Stream; var parseResult = new ParseResult { RawData = new Dictionary(), Status = LoadStatus.Success }; RegisterModules(); networkLoader.Setup(n => n.TryLoad(It.IsAny(), out stream)).Returns(LoadStatus.Success); binaryParser.Setup(b => b.CanParse(It.IsAny())).Returns(true); binaryParser.Setup(b => b.TryParse(It.IsAny(), It.IsAny())).Returns(parseResult); var result = sut.TryLoadSettings(new Uri("http://www.blubb.org"), out _); fileLoader.Verify(f => f.CanLoad(It.IsAny()), Times.Once); fileLoader.Verify(f => f.TryLoad(It.IsAny(), out stream), Times.Never); networkLoader.Verify(n => n.CanLoad(It.IsAny()), Times.Once); networkLoader.Verify(n => n.TryLoad(It.IsAny(), out stream), Times.Once); binaryParser.Verify(b => b.CanParse(It.IsAny()), Times.Once); binaryParser.Verify(b => b.TryParse(It.IsAny(), It.IsAny()), Times.Once); xmlParser.Verify(x => x.CanParse(It.IsAny()), Times.AtMostOnce); xmlParser.Verify(x => x.TryParse(It.IsAny(), It.IsAny()), Times.Never); Assert.AreEqual(LoadStatus.Success, result); } [TestMethod] public void TryLoad_MustReportPasswordNeed() { var stream = new MemoryStream() as Stream; var parseResult = new ParseResult { Status = LoadStatus.PasswordNeeded }; RegisterModules(); networkLoader.Setup(n => n.TryLoad(It.IsAny(), out stream)).Returns(LoadStatus.Success); binaryParser.Setup(b => b.CanParse(It.IsAny())).Returns(true); binaryParser.Setup(b => b.TryParse(It.IsAny(), It.IsAny())).Returns(parseResult); var result = sut.TryLoadSettings(new Uri("http://www.blubb.org"), out _); Assert.AreEqual(LoadStatus.PasswordNeeded, result); } [TestMethod] public void TryLoad_MustNotFailToIfNoLoaderRegistered() { var result = sut.TryLoadSettings(new Uri("http://www.blubb.org"), out _); Assert.AreEqual(LoadStatus.NotSupported, result); sut.Register(fileLoader.Object); sut.Register(networkLoader.Object); result = sut.TryLoadSettings(new Uri("ftp://www.blubb.org"), out _); fileLoader.Verify(f => f.CanLoad(It.IsAny()), Times.Once); networkLoader.Verify(n => n.CanLoad(It.IsAny()), Times.Once); Assert.AreEqual(LoadStatus.NotSupported, result); } [TestMethod] public void TryLoad_MustNotFailIfNoParserRegistered() { var data = default(Stream); networkLoader.Setup(l => l.TryLoad(It.IsAny(), out data)).Returns(LoadStatus.Success); sut.Register(networkLoader.Object); var result = sut.TryLoadSettings(new Uri("http://www.blubb.org"), out _); networkLoader.Verify(n => n.TryLoad(It.IsAny(), out data), Times.Once); Assert.AreEqual(LoadStatus.NotSupported, result); } [TestMethod] public void TryLoad_MustNotFailInCaseOfUnexpectedError() { var data = default(Stream); networkLoader.Setup(l => l.TryLoad(It.IsAny(), out data)).Throws(); sut.Register(networkLoader.Object); var result = sut.TryLoadSettings(new Uri("http://www.blubb.org"), out _); Assert.AreEqual(LoadStatus.UnexpectedError, result); binaryParser.Setup(b => b.CanParse(It.IsAny())).Throws(); networkLoader.Setup(l => l.TryLoad(It.IsAny(), out data)).Returns(LoadStatus.Success); sut.Register(binaryParser.Object); result = sut.TryLoadSettings(new Uri("http://www.blubb.org"), out _); Assert.AreEqual(LoadStatus.UnexpectedError, result); } [TestMethod] public void MustInitializeSessionConfiguration() { var appConfig = sut.InitializeAppConfig(); var configuration = sut.InitializeSessionConfiguration(); Assert.IsNull(configuration.Settings); Assert.IsInstanceOfType(configuration.AppConfig, typeof(AppConfig)); Assert.IsInstanceOfType(configuration.ClientAuthenticationToken, typeof(Guid)); Assert.IsInstanceOfType(configuration.SessionId, typeof(Guid)); } [TestMethod] public void MustUpdateAppConfig() { var appConfig = sut.InitializeAppConfig(); var clientAddress = appConfig.ClientAddress; var clientId = appConfig.ClientId; var clientLogFilePath = appConfig.ClientLogFilePath; var runtimeAddress = appConfig.RuntimeAddress; var runtimeId = appConfig.RuntimeId; var runtimeLogFilePath = appConfig.RuntimeLogFilePath; var serviceEventName = appConfig.ServiceEventName; var configuration = sut.InitializeSessionConfiguration(); Assert.AreEqual(configuration.AppConfig.ClientLogFilePath, clientLogFilePath); Assert.AreEqual(configuration.AppConfig.RuntimeAddress, runtimeAddress); Assert.AreEqual(configuration.AppConfig.RuntimeId, runtimeId); Assert.AreEqual(configuration.AppConfig.RuntimeLogFilePath, runtimeLogFilePath); Assert.AreNotEqual(configuration.AppConfig.ClientAddress, clientAddress); Assert.AreNotEqual(configuration.AppConfig.ClientId, clientId); Assert.AreNotEqual(configuration.AppConfig.ServiceEventName, serviceEventName); } [TestMethod] public void MustUpdateSessionConfiguration() { var appConfig = sut.InitializeAppConfig(); var firstSession = sut.InitializeSessionConfiguration(); var secondSession = sut.InitializeSessionConfiguration(); var thirdSession = sut.InitializeSessionConfiguration(); Assert.AreNotEqual(firstSession.SessionId, secondSession.SessionId); Assert.AreNotEqual(firstSession.ClientAuthenticationToken, secondSession.ClientAuthenticationToken); Assert.AreNotEqual(secondSession.SessionId, thirdSession.SessionId); Assert.AreNotEqual(secondSession.ClientAuthenticationToken, thirdSession.ClientAuthenticationToken); } private void RegisterModules() { sut.Register(binaryParser.Object); sut.Register(binarySerializer.Object); sut.Register(fileLoader.Object); sut.Register(fileSaver.Object); sut.Register(networkLoader.Object); sut.Register(xmlParser.Object); sut.Register(xmlSerializer.Object); } /// /// Required for unit tests to be able to retrieve the while executing. /// public void SetEntryAssembly() { var assembly = Assembly.GetCallingAssembly(); var manager = new AppDomainManager(); var entryAssemblyfield = manager.GetType().GetField("m_entryAssembly", BindingFlags.Instance | BindingFlags.NonPublic); entryAssemblyfield.SetValue(manager, assembly); var domain = AppDomain.CurrentDomain; var domainManagerField = domain.GetType().GetField("_domainManager", BindingFlags.Instance | BindingFlags.NonPublic); domainManagerField.SetValue(domain, manager); } } }