Files
coverlet/test/coverlet.core.tests/Instrumentation/ModuleTrackerTemplateTests.cs
T
2019-01-15 10:37:37 +01:00

174 lines
5.7 KiB
C#

using Coverlet.Core.Instrumentation;
using Coverlet.Core.Helpers;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace Coverlet.Core.Tests.Instrumentation
{
public class ModuleTrackerTemplateTestsFixture : IDisposable
{
public void Dispose()
{
AppDomain.CurrentDomain.ProcessExit -= ModuleTrackerTemplate.UnloadModule;
AppDomain.CurrentDomain.DomainUnload -= ModuleTrackerTemplate.UnloadModule;
}
}
[CollectionDefinition(nameof(ModuleTrackerTemplate))]
public class ModuleTrackerTemplateCollection : ICollectionFixture<ModuleTrackerTemplateTestsFixture>
{
}
[Collection(nameof(ModuleTrackerTemplate))]
public class ModuleTrackerTemplateTests : IDisposable
{
private readonly MemoryMappedFile _mmap;
public ModuleTrackerTemplateTests()
{
ModuleTrackerTemplate.HitsArraySize = 4;
ModuleTrackerTemplate.HitsMemoryMapName = Guid.NewGuid().ToString();
ModuleTrackerTemplate.HitsFilePath = Path.Combine(Path.GetTempPath(), $"coverlet.test_{ModuleTrackerTemplate.HitsMemoryMapName}");
var size = (ModuleTrackerTemplate.HitsArraySize + Coverage.HitsResultHeaderSize) * sizeof(int);
try
{
_mmap = MemoryMappedFile.CreateNew(ModuleTrackerTemplate.HitsMemoryMapName, size);
}
catch (PlatformNotSupportedException)
{
_mmap = MemoryMappedFile.CreateFromFile(ModuleTrackerTemplate.HitsFilePath, FileMode.CreateNew, null, size);
}
}
public void Dispose()
{
var hitsFilePath = ModuleTrackerTemplate.HitsFilePath;
_mmap.Dispose();
InstrumentationHelper.DeleteHitsFile(hitsFilePath);
}
[Fact]
public void HitsFileCorrectlyWritten()
{
RecordHits(1, 2, 0, 3);
ModuleTrackerTemplate.UnloadModule(null, null);
var expectedHitsArray = new[] { 1, 2, 0, 3 };
Assert.Equal(expectedHitsArray, ReadHits());
}
[Fact]
public void HitsOnMultipleThreadsCorrectlyCounted()
{
ModuleTrackerTemplate.HitsArraySize = 4;
for (int i = 0; i < ModuleTrackerTemplate.HitsArraySize; ++i)
{
var t = new Thread(HitIndex);
t.Start(i);
t.Join();
}
ModuleTrackerTemplate.UnloadModule(null, null);
var expectedHitsArray = new[] { 4, 3, 2, 1 };
Assert.Equal(expectedHitsArray, ReadHits());
void HitIndex(object index)
{
var hitIndex = (int)index;
for (int i = 0; i <= hitIndex; ++i)
{
ModuleTrackerTemplate.RecordHit(i);
}
}
}
[Fact]
public void MultipleSequentialUnloadsHaveCorrectTotalData()
{
RecordHits(0, 3, 2, 1);
ModuleTrackerTemplate.UnloadModule(null, null);
RecordHits(0, 1, 2, 3);
ModuleTrackerTemplate.UnloadModule(null, null);
var expectedHitsArray = new[] { 0, 4, 4, 4 };
Assert.Equal(expectedHitsArray, ReadHits(2));
}
[Fact]
public async void MutexBlocksMultipleWriters()
{
using (var mutex = new Mutex(
true, Path.GetFileNameWithoutExtension(ModuleTrackerTemplate.HitsMemoryMapName) + "_Mutex", out bool createdNew))
{
Assert.True(createdNew);
RecordHits(0, 1, 2, 3);
var unloadTask = Task.Run(() => ModuleTrackerTemplate.UnloadModule(null, null));
Assert.False(unloadTask.Wait(5));
var expectedHitsArray = new[] { 0, 0, 0, 0 };
Assert.Equal(expectedHitsArray, ReadHits(0));
mutex.ReleaseMutex();
await unloadTask;
expectedHitsArray = new[] { 0, 1, 2, 3 };
Assert.Equal(expectedHitsArray, ReadHits());
}
}
private void RecordHits(params int[] hitCounts)
{
// Since the hit array is held in a thread local member that is
// then dropped by UnloadModule the hit counting must be done
// in a new thread for each test
Assert.Equal(ModuleTrackerTemplate.HitsArraySize, hitCounts.Length);
var thread = new Thread(() =>
{
for (var i = 0; i < hitCounts.Length; i++)
{
var count = hitCounts[i];
while (count-- > 0)
{
ModuleTrackerTemplate.RecordHit(i);
}
}
});
thread.Start();
thread.Join();
}
private int[] ReadHits(int expectedUnloads = 1)
{
var mmapAccessor = _mmap.CreateViewAccessor();
var unloadStarted = mmapAccessor.ReadInt32(Coverage.HitsResultUnloadStarted * sizeof(int));
var unloadFinished = mmapAccessor.ReadInt32(Coverage.HitsResultUnloadFinished * sizeof(int));
Assert.Equal(expectedUnloads, unloadStarted);
Assert.Equal(expectedUnloads, unloadFinished);
var hits = new List<int>();
for (int i = 0; i < ModuleTrackerTemplate.HitsArraySize; ++i)
{
hits.Add(mmapAccessor.ReadInt32((i + Coverage.HitsResultHeaderSize) * sizeof(int)));
}
return hits.ToArray();
}
}
}