seb-win-refactoring/SafeExamBrowser.Lockdown.UnitTests/FeatureConfigurationMonitorTests.cs

196 lines
5.2 KiB
C#

/*
* 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.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SafeExamBrowser.Lockdown.Contracts;
using SafeExamBrowser.Logging.Contracts;
namespace SafeExamBrowser.Lockdown.UnitTests
{
[TestClass]
public class FeatureConfigurationMonitorTests
{
private Mock<ILogger> logger;
private FeatureConfigurationMonitor sut;
[TestInitialize]
public void Initialize()
{
logger = new Mock<ILogger>();
sut = new FeatureConfigurationMonitor(logger.Object, 0);
}
[TestMethod]
public void MustEnforceConfigurations()
{
var configuration1 = new Mock<IFeatureConfiguration>();
var configuration2 = new Mock<IFeatureConfiguration>();
var configuration3 = new Mock<IFeatureConfiguration>();
var counter = 0;
var limit = new Random().Next(5, 50);
var sync = new AutoResetEvent(false);
configuration1.Setup(c => c.GetStatus()).Returns(FeatureConfigurationStatus.Disabled);
configuration2.Setup(c => c.GetStatus()).Returns(FeatureConfigurationStatus.Enabled);
configuration3.Setup(c => c.GetStatus()).Returns(FeatureConfigurationStatus.Disabled).Callback(() =>
{
if (++counter >= limit)
{
sync.Set();
}
});
sut = new FeatureConfigurationMonitor(logger.Object, 2);
sut.Observe(configuration1.Object, FeatureConfigurationStatus.Enabled);
sut.Observe(configuration2.Object, FeatureConfigurationStatus.Disabled);
sut.Observe(configuration3.Object, FeatureConfigurationStatus.Undefined);
sut.Start();
sync.WaitOne();
sut.Reset();
configuration1.Verify(c => c.EnableFeature(), Times.Exactly(limit));
configuration2.Verify(c => c.DisableFeature(), Times.Exactly(limit));
configuration3.Verify(c => c.DisableFeature(), Times.Never);
configuration3.Verify(c => c.EnableFeature(), Times.Never);
}
[TestMethod]
public void MustExecuteAsynchronously()
{
var configuration = new Mock<IFeatureConfiguration>();
var sync = new AutoResetEvent(false);
var threadId = Thread.CurrentThread.ManagedThreadId;
configuration.Setup(c => c.GetStatus()).Callback(() => { threadId = Thread.CurrentThread.ManagedThreadId; sync.Set(); });
sut.Observe(configuration.Object, FeatureConfigurationStatus.Disabled);
sut.Start();
sync.WaitOne();
sut.Reset();
Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId);
}
[TestMethod]
public void MustNotStartMultipleTimes()
{
var configuration = new Mock<IFeatureConfiguration>();
var counter = 0;
var sync = new AutoResetEvent(false);
configuration.Setup(c => c.GetStatus()).Returns(() =>
{
counter++;
Thread.Sleep(50);
sync.Set();
sut.Reset();
return FeatureConfigurationStatus.Disabled;
});
sut.Observe(configuration.Object, FeatureConfigurationStatus.Enabled);
sut.Start();
sut.Start();
sut.Start();
sut.Start();
sut.Start();
sut.Start();
sut.Start();
sync.WaitOne();
sut.Reset();
Assert.AreEqual(1, counter);
}
[TestMethod]
public void MustRespectTimeout()
{
const int TIMEOUT = 50;
var after = default(DateTime);
var before = default(DateTime);
var configuration = new Mock<IFeatureConfiguration>();
var counter = 0;
var sync = new AutoResetEvent(false);
sut = new FeatureConfigurationMonitor(logger.Object, TIMEOUT);
configuration.Setup(c => c.GetStatus()).Returns(FeatureConfigurationStatus.Undefined).Callback(() =>
{
switch (++counter)
{
case 1:
before = DateTime.Now;
break;
case 2:
after = DateTime.Now;
sync.Set();
break;
}
});
sut.Observe(configuration.Object, FeatureConfigurationStatus.Disabled);
sut.Start();
sync.WaitOne();
sut.Reset();
Assert.IsTrue(after - before >= new TimeSpan(0, 0, 0, 0, TIMEOUT));
}
[TestMethod]
public void MustStopWhenReset()
{
var configuration = new Mock<IFeatureConfiguration>();
var counter = 0;
configuration.Setup(c => c.GetStatus()).Returns(FeatureConfigurationStatus.Disabled).Callback(() => counter++);
sut.Observe(configuration.Object, FeatureConfigurationStatus.Enabled);
sut.Start();
Thread.Sleep(10);
sut.Reset();
Thread.Sleep(10);
configuration.Verify(c => c.GetStatus(), Times.Exactly(counter));
}
[TestMethod]
public void MustRemoveConfigurationsWhenReset()
{
var configuration = new Mock<IFeatureConfiguration>();
var counter = 0;
configuration.Setup(c => c.GetStatus()).Returns(FeatureConfigurationStatus.Disabled).Callback(() => counter++);
sut.Observe(configuration.Object, FeatureConfigurationStatus.Enabled);
sut.Start();
Thread.Sleep(10);
sut.Reset();
configuration.Verify(c => c.GetStatus(), Times.Exactly(counter));
configuration.Reset();
sut.Start();
Thread.Sleep(10);
sut.Reset();
configuration.Verify(c => c.GetStatus(), Times.Never);
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void MustValidateTimeout()
{
new FeatureConfigurationMonitor(logger.Object, new Random().Next(int.MinValue, -1));
}
}
}