/* * Copyright (c) 2020 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.IO; using System.Threading; using CefSharp; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Browser.Contracts.Events; using SafeExamBrowser.Browser.Handlers; using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.UserInterface.Contracts.Browser.Data; using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings; namespace SafeExamBrowser.Browser.UnitTests.Handlers { [TestClass] public class DownloadHandlerTests { private AppConfig appConfig; private BrowserSettings settings; private Mock logger; private DownloadHandler sut; [TestInitialize] public void Initialize() { appConfig = new AppConfig(); settings = new BrowserSettings(); logger = new Mock(); sut = new DownloadHandler(appConfig, settings, logger.Object); } [TestMethod] public void MustCorrectlyHandleConfigurationByFileExtension() { var item = new DownloadItem { SuggestedFileName = "File.seb", Url = "https://somehost.org/some-path" }; RequestConfigurationDownload(item); } [TestMethod] public void MustCorrectlyHandleConfigurationByUrlExtension() { var item = new DownloadItem { SuggestedFileName = "Abc.xyz", Url = "https://somehost.org/some-path-to/file.seb" }; RequestConfigurationDownload(item); } [TestMethod] public void MustCorrectlyHandleConfigurationByMimeType() { appConfig.ConfigurationFileMimeType = "some/mime-type"; var item = new DownloadItem { MimeType = appConfig.ConfigurationFileMimeType, SuggestedFileName = "Abc.xyz", Url = "https://somehost.org/some-path" }; RequestConfigurationDownload(item); } [TestMethod] public void MustCorrectlyHandleDeniedConfigurationFileDownload() { var args = default(DownloadEventArgs); var callback = new Mock(); var failed = false; var fileName = default(string); var item = new DownloadItem { SuggestedFileName = "File.seb", Url = "https://somehost.org/some-path" }; var sync = new AutoResetEvent(false); var threadId = default(int); settings.AllowDownloads = false; settings.AllowConfigurationDownloads = true; sut.ConfigurationDownloadRequested += (f, a) => { args = a; args.AllowDownload = false; fileName = f; threadId = Thread.CurrentThread.ManagedThreadId; sync.Set(); }; sut.DownloadUpdated += (state) => failed = true; sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); sync.WaitOne(); callback.VerifyNoOtherCalls(); Assert.IsFalse(failed); Assert.IsFalse(args.AllowDownload); Assert.AreEqual(item.SuggestedFileName, fileName); Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); } [TestMethod] public void MustCorrectlyHandleFileDownload() { var callback = new Mock(); var downloadPath = default(string); var failed = false; var item = new DownloadItem { MimeType = "application/something", SuggestedFileName = "File.txt", Url = "https://somehost.org/somefile.abc" }; var sync = new AutoResetEvent(false); var threadId = default(int); callback.Setup(c => c.Continue(It.IsAny(), It.IsAny())).Callback((f, s) => { downloadPath = f; threadId = Thread.CurrentThread.ManagedThreadId; sync.Set(); }); settings.AllowDownloads = true; settings.AllowConfigurationDownloads = false; sut.ConfigurationDownloadRequested += (f, a) => failed = true; sut.DownloadUpdated += (state) => failed = true; sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); sync.WaitOne(); callback.Verify(c => c.Continue(It.Is(p => p.Equals(downloadPath)), false), Times.Once); Assert.IsFalse(failed); Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); } [TestMethod] public void MustCorrectlyHandleFileDownloadWithCustomDirectory() { var callback = new Mock(); var failed = false; var item = new DownloadItem { MimeType = "application/something", SuggestedFileName = "File.txt", Url = "https://somehost.org/somefile.abc" }; var sync = new AutoResetEvent(false); var threadId = default(int); callback.Setup(c => c.Continue(It.IsAny(), It.IsAny())).Callback(() => { threadId = Thread.CurrentThread.ManagedThreadId; sync.Set(); }); settings.AllowDownloads = true; settings.AllowConfigurationDownloads = false; settings.AllowCustomDownloadLocation = true; settings.DownloadDirectory = @"%APPDATA%\Downloads"; sut.ConfigurationDownloadRequested += (f, a) => failed = true; sut.DownloadUpdated += (state) => failed = true; sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); sync.WaitOne(); var downloadPath = Path.Combine(Environment.ExpandEnvironmentVariables(settings.DownloadDirectory), item.SuggestedFileName); callback.Verify(c => c.Continue(It.Is(p => p.Equals(downloadPath)), true), Times.Once); Assert.IsFalse(failed); Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); } [TestMethod] public void MustDoNothingIfDownloadsNotAllowed() { var callback = new Mock(); var fail = false; var item = new DownloadItem { SuggestedFileName = "File.txt", Url = "https://somehost.org/somefile.abc" }; settings.AllowDownloads = false; settings.AllowConfigurationDownloads = false; sut.ConfigurationDownloadRequested += (file, args) => fail = true; sut.DownloadUpdated += (state) => fail = true; sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); callback.VerifyNoOtherCalls(); Assert.IsFalse(fail); } [TestMethod] public void MustUpdateDownloadProgress() { var callback = new Mock(); var failed = false; var item = new DownloadItem { MimeType = "application/something", SuggestedFileName = "File.txt", Url = "https://somehost.org/somefile.abc" }; var state = default(DownloadItemState); var sync = new AutoResetEvent(false); var threadId = default(int); callback.Setup(c => c.Continue(It.IsAny(), It.IsAny())).Callback(() => sync.Set()); settings.AllowDownloads = true; settings.AllowConfigurationDownloads = false; sut.ConfigurationDownloadRequested += (f, a) => failed = true; sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); sync.WaitOne(); Assert.IsFalse(failed); sut.DownloadUpdated += (s) => { state = s; threadId = Thread.CurrentThread.ManagedThreadId; sync.Set(); }; item.PercentComplete = 10; sut.OnDownloadUpdated(default(IWebBrowser), default(IBrowser), item, default(IDownloadItemCallback)); sync.WaitOne(); Assert.IsFalse(state.IsCancelled); Assert.IsFalse(state.IsComplete); Assert.AreEqual(0.1, state.Completion); Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); item.PercentComplete = 20; sut.OnDownloadUpdated(default(IWebBrowser), default(IBrowser), item, default(IDownloadItemCallback)); sync.WaitOne(); Assert.IsFalse(state.IsCancelled); Assert.IsFalse(state.IsComplete); Assert.AreEqual(0.2, state.Completion); Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); item.PercentComplete = 50; item.IsCancelled = true; sut.OnDownloadUpdated(default(IWebBrowser), default(IBrowser), item, default(IDownloadItemCallback)); sync.WaitOne(); Assert.IsFalse(failed); Assert.IsTrue(state.IsCancelled); Assert.IsFalse(state.IsComplete); Assert.AreEqual(0.5, state.Completion); Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); } private void RequestConfigurationDownload(DownloadItem item) { var args = default(DownloadEventArgs); var callback = new Mock(); var failed = false; var fileName = default(string); var sync = new AutoResetEvent(false); var threadId = default(int); callback.Setup(c => c.Continue(It.IsAny(), It.IsAny())).Callback(() => sync.Set()); settings.AllowDownloads = false; settings.AllowConfigurationDownloads = true; sut.ConfigurationDownloadRequested += (f, a) => { args = a; args.AllowDownload = true; args.DownloadPath = @"C:\Downloads\File.seb"; fileName = f; threadId = Thread.CurrentThread.ManagedThreadId; }; sut.DownloadUpdated += (state) => failed = true; sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); sync.WaitOne(); callback.Verify(c => c.Continue(It.Is(p => p.Equals(args.DownloadPath)), false), Times.Once); Assert.IsFalse(failed); Assert.IsTrue(args.AllowDownload); Assert.AreEqual(item.SuggestedFileName, fileName); Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); } } }