mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Moved Wabbajack.Commons tests into Wabbajack.Commons.Test out of Wabbajack.Test. They all pass
This commit is contained in:
parent
006b045348
commit
51bad949ec
@ -20,10 +20,10 @@ namespace Compression.BSA.Test
|
|||||||
[TestClass]
|
[TestClass]
|
||||||
public class BSATests
|
public class BSATests
|
||||||
{
|
{
|
||||||
private static string _stagingFolder = "NexusDownloads";
|
private static AbsolutePath _stagingFolder = ((RelativePath)"NexusDownloads").RelativeToEntryPoint();
|
||||||
private static string _bsaFolder = "BSAs";
|
private static AbsolutePath _bsaFolder = ((RelativePath)"BSAs").RelativeToEntryPoint();
|
||||||
private static string _testDir = "BSA Test Dir";
|
private static AbsolutePath _testDir = ((RelativePath)"BSA Test Dir").RelativeToEntryPoint();
|
||||||
private static string _tempDir = "BSA Temp Dir";
|
private static AbsolutePath _tempDir = ((RelativePath)"BSA Temp Dir").RelativeToEntryPoint();
|
||||||
|
|
||||||
public TestContext TestContext { get; set; }
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
@ -34,11 +34,8 @@ namespace Compression.BSA.Test
|
|||||||
{
|
{
|
||||||
Queue = new WorkQueue();
|
Queue = new WorkQueue();
|
||||||
Utils.LogMessages.Subscribe(f => testContext.WriteLine(f.ShortDescription));
|
Utils.LogMessages.Subscribe(f => testContext.WriteLine(f.ShortDescription));
|
||||||
if (!Directory.Exists(_stagingFolder))
|
_stagingFolder.DeleteDirectory();
|
||||||
Directory.CreateDirectory(_stagingFolder);
|
_bsaFolder.DeleteDirectory();
|
||||||
|
|
||||||
if (!Directory.Exists(_bsaFolder))
|
|
||||||
Directory.CreateDirectory(_bsaFolder);
|
|
||||||
|
|
||||||
var modIDs = new[]
|
var modIDs = new[]
|
||||||
{
|
{
|
||||||
@ -53,22 +50,21 @@ namespace Compression.BSA.Test
|
|||||||
await Task.WhenAll(modIDs.Select(async (info) =>
|
await Task.WhenAll(modIDs.Select(async (info) =>
|
||||||
{
|
{
|
||||||
var filename = await DownloadMod(info);
|
var filename = await DownloadMod(info);
|
||||||
var folder = Path.Combine(_bsaFolder, info.Item1.ToString(), info.Item2.ToString());
|
var folder = _bsaFolder.Combine(info.Item1.ToString(), info.Item2.ToString());
|
||||||
if (!Directory.Exists(folder))
|
folder.CreateDirectory();
|
||||||
Directory.CreateDirectory(folder);
|
|
||||||
await FileExtractor.ExtractAll(Queue, filename, folder);
|
await FileExtractor.ExtractAll(Queue, filename, folder);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> DownloadMod((Game, int) info)
|
private static async Task<AbsolutePath> DownloadMod((Game, int) info)
|
||||||
{
|
{
|
||||||
using var client = await NexusApiClient.Get();
|
using var client = await NexusApiClient.Get();
|
||||||
var results = await client.GetModFiles(info.Item1, info.Item2);
|
var results = await client.GetModFiles(info.Item1, info.Item2);
|
||||||
var file = results.files.FirstOrDefault(f => f.is_primary) ??
|
var file = results.files.FirstOrDefault(f => f.is_primary) ??
|
||||||
results.files.OrderByDescending(f => f.uploaded_timestamp).First();
|
results.files.OrderByDescending(f => f.uploaded_timestamp).First();
|
||||||
var src = Path.Combine(_stagingFolder, file.file_name);
|
var src = _stagingFolder.Combine(file.file_name);
|
||||||
|
|
||||||
if (File.Exists(src)) return src;
|
if (src.Exists) return src;
|
||||||
|
|
||||||
var state = new NexusDownloader.State
|
var state = new NexusDownloader.State
|
||||||
{
|
{
|
||||||
@ -82,41 +78,38 @@ namespace Compression.BSA.Test
|
|||||||
|
|
||||||
public static IEnumerable<object[]> BSAs()
|
public static IEnumerable<object[]> BSAs()
|
||||||
{
|
{
|
||||||
return Directory.EnumerateFiles(_bsaFolder, "*", DirectoryEnumerationOptions.Recursive)
|
return _bsaFolder.EnumerateFiles()
|
||||||
.Where(f => Consts.SupportedBSAs.Contains(Path.GetExtension(f)))
|
.Where(f => Consts.SupportedBSAs.Contains(f.Extension))
|
||||||
.Select(nm => new object[] {nm});
|
.Select(nm => new object[] {nm});
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[DataTestMethod]
|
[DataTestMethod]
|
||||||
[DynamicData(nameof(BSAs), DynamicDataSourceType.Method)]
|
[DynamicData(nameof(BSAs), DynamicDataSourceType.Method)]
|
||||||
public async Task BSACompressionRecompression(string bsa)
|
public async Task BSACompressionRecompression(AbsolutePath bsa)
|
||||||
{
|
{
|
||||||
TestContext.WriteLine($"From {bsa}");
|
TestContext.WriteLine($"From {bsa}");
|
||||||
TestContext.WriteLine("Cleaning Output Dir");
|
TestContext.WriteLine("Cleaning Output Dir");
|
||||||
if (Directory.Exists(_tempDir)) Utils.DeleteDirectory(_tempDir);
|
_tempDir.DeleteDirectory();
|
||||||
Directory.CreateDirectory(_tempDir);
|
_tempDir.CreateDirectory();
|
||||||
|
|
||||||
TestContext.WriteLine($"Reading {bsa}");
|
TestContext.WriteLine($"Reading {bsa}");
|
||||||
string tempFile = Path.Combine("tmp.bsa");
|
var tempFile = ((RelativePath)"tmp.bsa").RelativeToEntryPoint();
|
||||||
var size = File.GetSize(bsa);
|
var size = bsa.Size;
|
||||||
using (var a = BSADispatch.OpenRead(bsa))
|
using (var a = BSADispatch.OpenRead(bsa))
|
||||||
{
|
{
|
||||||
await a.Files.PMap(Queue, file =>
|
await a.Files.PMap(Queue, file =>
|
||||||
{
|
{
|
||||||
var absName = Path.Combine(_tempDir, file.Path);
|
var absName = _tempDir.Combine(file.Path);
|
||||||
ViaJson(file.State);
|
ViaJson(file.State);
|
||||||
|
|
||||||
if (!Directory.Exists(Path.GetDirectoryName(absName)))
|
absName.Parent.CreateDirectory();
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(absName));
|
using (var fs = absName.Create())
|
||||||
|
|
||||||
|
|
||||||
using (var fs = File.Open(absName, FileMode.Create))
|
|
||||||
{
|
{
|
||||||
file.CopyDataTo(fs);
|
file.CopyDataTo(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.AreEqual(file.Size, new FileInfo(absName).Length);
|
Assert.AreEqual(file.Size, absName.Size);
|
||||||
});
|
});
|
||||||
|
|
||||||
Console.WriteLine($"Building {bsa}");
|
Console.WriteLine($"Building {bsa}");
|
||||||
@ -125,8 +118,8 @@ namespace Compression.BSA.Test
|
|||||||
{
|
{
|
||||||
var streams = await a.Files.PMap(Queue, file =>
|
var streams = await a.Files.PMap(Queue, file =>
|
||||||
{
|
{
|
||||||
var absPath = Path.Combine(_tempDir, file.Path);
|
var absPath = _tempDir.Combine(file.Path);
|
||||||
var str = File.OpenRead(absPath);
|
var str = absPath.OpenRead();
|
||||||
w.AddFile(ViaJson(file.State), str);
|
w.AddFile(ViaJson(file.State), str);
|
||||||
return str;
|
return str;
|
||||||
});
|
});
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Xunit;
|
||||||
using Wabbajack.Common;
|
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
namespace Wabbajack.Common.Test
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class AsyncLockTests
|
public class AsyncLockTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task Typical()
|
public async Task Typical()
|
||||||
{
|
{
|
||||||
var asyncLock = new AsyncLock();
|
var asyncLock = new AsyncLock();
|
||||||
@ -29,20 +24,20 @@ namespace Wabbajack.Test
|
|||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
using (await asyncLock.Wait())
|
using (await asyncLock.Wait())
|
||||||
{
|
{
|
||||||
Assert.IsTrue(firstRun);
|
Assert.True(firstRun);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await Task.WhenAll(first, second);
|
await Task.WhenAll(first, second);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task Exception()
|
public async Task Exception()
|
||||||
{
|
{
|
||||||
var asyncLock = new AsyncLock();
|
var asyncLock = new AsyncLock();
|
||||||
bool firstRun = false;
|
bool firstRun = false;
|
||||||
bool secondRun = false;
|
bool secondRun = false;
|
||||||
// Throw exception inside a lock
|
// Throw exception inside a lock
|
||||||
await Assert.ThrowsExceptionAsync<Exception>(() =>
|
await Assert.ThrowsAsync<Exception>(() =>
|
||||||
{
|
{
|
||||||
return Task.Run(async () =>
|
return Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -62,7 +57,7 @@ namespace Wabbajack.Test
|
|||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
using (await asyncLock.Wait())
|
using (await asyncLock.Wait())
|
||||||
{
|
{
|
||||||
Assert.IsTrue(firstRun);
|
Assert.True(firstRun);
|
||||||
secondRun = true;
|
secondRun = true;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
@ -1,18 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using Xunit;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using Wabbajack.Common;
|
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
namespace Wabbajack.Common.Test
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class EncryptedDataTests
|
public class EncryptedDataTests
|
||||||
{
|
{
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task CanDetectNewEncryptedData()
|
public async Task CanDetectNewEncryptedData()
|
||||||
{
|
{
|
||||||
var test_string = Guid.NewGuid().ToString();
|
var test_string = Guid.NewGuid().ToString();
|
||||||
@ -28,7 +24,7 @@ namespace Wabbajack.Test
|
|||||||
test_string.ToEcryptedJson(test_string);
|
test_string.ToEcryptedJson(test_string);
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
|
|
||||||
CollectionAssert.Contains(data, test_string);
|
Assert.Contains(test_string, data);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,18 +1,17 @@
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Xunit;
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
namespace Wabbajack.Common.Test
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class HttpClientTests
|
public class HttpClientTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task DoesntReuseHttpMessages()
|
public async Task DoesntReuseHttpMessages()
|
||||||
{
|
{
|
||||||
var client = new Common.Http.Client();
|
var client = new Common.Http.Client();
|
||||||
// If we reuse the HTTP message this will throw a invalid operation exception
|
// If we reuse the HTTP message this will throw a invalid operation exception
|
||||||
await Assert.ThrowsExceptionAsync<HttpRequestException>(async () => await client.GetAsync("http://blerg.blaz.bloz.buz"));
|
await Assert.ThrowsAsync<HttpRequestException>(async () => await client.GetAsync("http://blerg.blaz.bloz.buz"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,25 +1,23 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Xunit;
|
||||||
using Wabbajack.Common;
|
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
namespace Wabbajack.Common.Test
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class IniTests
|
public class IniTests
|
||||||
{
|
{
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public void TestByteArrayParsing()
|
public void TestByteArrayParsing()
|
||||||
{
|
{
|
||||||
Assert.AreEqual("bar", @"[General]
|
Assert.Equal("bar", @"[General]
|
||||||
foo = bar".LoadIniString().General.foo);
|
foo = bar".LoadIniString().General.foo);
|
||||||
|
|
||||||
Assert.AreEqual("baz\\bar", @"[General]
|
Assert.Equal("baz\\bar", @"[General]
|
||||||
foo = baz\\bar".LoadIniString().General.foo);
|
foo = baz\\bar".LoadIniString().General.foo);
|
||||||
|
|
||||||
Assert.AreEqual("bar", @"[General]
|
Assert.Equal("bar", @"[General]
|
||||||
foo = @ByteArray(bar)".LoadIniString().General.foo);
|
foo = @ByteArray(bar)".LoadIniString().General.foo);
|
||||||
|
|
||||||
Assert.AreEqual("foo\\h̴̹͚̎é̶̘͙̐l̶͕̔͑p̴̯̋͂m̶̞̮͘͠e̸͉͙͆̄\\baz", @"[General]
|
Assert.Equal("foo\\h̴̹͚̎é̶̘͙̐l̶͕̔͑p̴̯̋͂m̶̞̮͘͠e̸͉͙͆̄\\baz", @"[General]
|
||||||
foo = @ByteArray(foo\\\x68\xcc\xb4\xcc\x8e\xcc\xb9\xcd\x9a\x65\xcc\xb6\xcd\x81\xcc\x90\xcc\x98\xcd\x99\x6c\xcc\xb6\xcc\x94\xcd\x91\xcd\x95\x70\xcc\xb4\xcc\x8b\xcd\x82\xcc\xaf\x6d\xcc\xb6\xcd\x98\xcd\xa0\xcc\x9e\xcc\xae\x65\xcc\xb8\xcd\x86\xcc\x84\xcd\x89\xcd\x99\\baz)".LoadIniString().General.foo);
|
foo = @ByteArray(foo\\\x68\xcc\xb4\xcc\x8e\xcc\xb9\xcd\x9a\x65\xcc\xb6\xcd\x81\xcc\x90\xcc\x98\xcd\x99\x6c\xcc\xb6\xcc\x94\xcd\x91\xcd\x95\x70\xcc\xb4\xcc\x8b\xcd\x82\xcc\xaf\x6d\xcc\xb6\xcd\x98\xcd\xa0\xcc\x9e\xcc\xae\x65\xcc\xb8\xcd\x86\xcc\x84\xcd\x89\xcd\x99\\baz)".LoadIniString().General.foo);
|
||||||
}
|
}
|
||||||
|
|
31
Wabbajack.Common.Test/MiscTests.cs
Normal file
31
Wabbajack.Common.Test/MiscTests.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Alphaleonis.Win32.Filesystem;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Wabbajack.Common.Test
|
||||||
|
{
|
||||||
|
public class MiscTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void TestDiskSpeed()
|
||||||
|
{
|
||||||
|
using (var queue = new WorkQueue())
|
||||||
|
{
|
||||||
|
var speed = Utils.TestDiskSpeed(queue, @".\");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TestHash()
|
||||||
|
{
|
||||||
|
var testFile = ((RelativePath)"text.data").RelativeToEntryPoint();
|
||||||
|
const string data = "Cheese for Everyone!";
|
||||||
|
await testFile.WriteAllTextAsync(data);
|
||||||
|
File.WriteAllText("test.data", data);
|
||||||
|
Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), testFile.FileHashCached());
|
||||||
|
Assert.True(Utils.TryGetHashCache(testFile, out var fileHash));
|
||||||
|
Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), fileHash);
|
||||||
|
Assert.NotEqual("eSIyd+KOG3s=", await testFile.WithExtension(Consts.HashFileExtension).ReadAllTextAsync());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
206
Wabbajack.Common.Test/PMapTests.cs
Normal file
206
Wabbajack.Common.Test/PMapTests.cs
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Wabbajack.Common.Test
|
||||||
|
{
|
||||||
|
public class PMapTests
|
||||||
|
{
|
||||||
|
const int TypicalThreadCount = 6;
|
||||||
|
const int TypicalDelayMS = 50;
|
||||||
|
const int TimeoutSeconds = 15;
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Typical_Action()
|
||||||
|
{
|
||||||
|
using var queue = new WorkQueue(TypicalThreadCount);
|
||||||
|
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
||||||
|
var output = new List<int>();
|
||||||
|
var workTask = Utils.PMap(Enumerable.Range(0, TypicalThreadCount * 2), queue, (item) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
Thread.Sleep(TypicalDelayMS);
|
||||||
|
lock (output)
|
||||||
|
{
|
||||||
|
output.Add(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
||||||
|
Assert.True(input.SequenceEqual(output.OrderBy(i => i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Typical_Func()
|
||||||
|
{
|
||||||
|
using var queue = new WorkQueue(TypicalThreadCount);
|
||||||
|
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
||||||
|
var workTask = Utils.PMap(Enumerable.Range(0, TypicalThreadCount * 2), queue, (item) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
Thread.Sleep(TypicalDelayMS);
|
||||||
|
return item.ToString();
|
||||||
|
});
|
||||||
|
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
||||||
|
Assert.True(input.Select(i => i.ToString()).SequenceEqual(results));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Typical_Task()
|
||||||
|
{
|
||||||
|
using var queue = new WorkQueue(TypicalThreadCount);
|
||||||
|
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
||||||
|
var output = new List<int>();
|
||||||
|
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (item) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
await Task.Delay(TypicalDelayMS);
|
||||||
|
lock (output)
|
||||||
|
{
|
||||||
|
output.Add(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
||||||
|
Assert.True(input.SequenceEqual(output.OrderBy(i => i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Typical_TaskReturn()
|
||||||
|
{
|
||||||
|
using var queue = new WorkQueue(TypicalThreadCount);
|
||||||
|
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
||||||
|
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (item) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
await Task.Delay(TypicalDelayMS);
|
||||||
|
return item.ToString();
|
||||||
|
});
|
||||||
|
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
||||||
|
Assert.True(input.Select(i => i.ToString()).SequenceEqual(results));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task NestedAction()
|
||||||
|
{
|
||||||
|
using var queue = new WorkQueue(TypicalThreadCount);
|
||||||
|
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
||||||
|
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
||||||
|
var output = new List<int>();
|
||||||
|
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (item) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
await Enumerable.Range(item * 100, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (subItem) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
Thread.Sleep(TypicalDelayMS);
|
||||||
|
lock (output)
|
||||||
|
{
|
||||||
|
output.Add(subItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
||||||
|
Assert.True(inputConstructedResults.SequenceEqual(output.OrderBy(i => i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Nested_Func()
|
||||||
|
{
|
||||||
|
using var queue = new WorkQueue(TypicalThreadCount);
|
||||||
|
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
||||||
|
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
||||||
|
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (item) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
return await Utils.PMap(Enumerable.Range(item * 100, TypicalThreadCount * 2), queue, (subItem) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
Thread.Sleep(TypicalDelayMS);
|
||||||
|
return subItem;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
||||||
|
Assert.True(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Nested_Task()
|
||||||
|
{
|
||||||
|
using var queue = new WorkQueue(TypicalThreadCount);
|
||||||
|
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
||||||
|
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
||||||
|
var output = new List<int>();
|
||||||
|
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (item) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
await Enumerable.Range(item * 100, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (subItem) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
await Task.Delay(TypicalDelayMS);
|
||||||
|
lock (output)
|
||||||
|
{
|
||||||
|
output.Add(subItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
||||||
|
Assert.True(inputConstructedResults.SequenceEqual(output.OrderBy(i => i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Nested_TaskReturn()
|
||||||
|
{
|
||||||
|
using var queue = new WorkQueue(TypicalThreadCount);
|
||||||
|
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
||||||
|
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
||||||
|
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (item) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (subItem) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
await Task.Delay(TypicalDelayMS);
|
||||||
|
return subItem;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
||||||
|
Assert.True(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Nested_BackgroundThreadsInvolved()
|
||||||
|
{
|
||||||
|
using var queue = new WorkQueue(TypicalThreadCount);
|
||||||
|
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
||||||
|
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
||||||
|
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (item) =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
|
||||||
|
.PMap(queue, async (subItem) =>
|
||||||
|
{
|
||||||
|
return await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
Assert.True(WorkQueue.WorkerThread);
|
||||||
|
await Task.Delay(TypicalDelayMS);
|
||||||
|
return subItem;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
||||||
|
Assert.True(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,25 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Xunit;
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
namespace Wabbajack.Common.Test
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class TaskExtTests
|
public class TaskExtTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task TimeoutButContinue_Typical()
|
public async Task TimeoutButContinue_Typical()
|
||||||
{
|
{
|
||||||
bool timedOut = false;
|
bool timedOut = false;
|
||||||
await Task.Delay(100).TimeoutButContinue(TimeSpan.FromSeconds(1), () => timedOut = true);
|
await Task.Delay(100).TimeoutButContinue(TimeSpan.FromSeconds(1), () => timedOut = true);
|
||||||
Assert.IsFalse(timedOut);
|
Assert.False(timedOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task TimeoutButContinue_TimedOut()
|
public async Task TimeoutButContinue_TimedOut()
|
||||||
{
|
{
|
||||||
bool timedOut = false;
|
bool timedOut = false;
|
||||||
await Task.Delay(300).TimeoutButContinue(TimeSpan.FromMilliseconds(100), () => timedOut = true);
|
await Task.Delay(300).TimeoutButContinue(TimeSpan.FromMilliseconds(100), () => timedOut = true);
|
||||||
Assert.IsTrue(timedOut);
|
Assert.True(timedOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
24
Wabbajack.Common.Test/TestUtils.cs
Normal file
24
Wabbajack.Common.Test/TestUtils.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Wabbajack.Common.Test
|
||||||
|
{
|
||||||
|
public static class TestUtils
|
||||||
|
{
|
||||||
|
private static Random _random = new Random();
|
||||||
|
|
||||||
|
public static byte[] RandomData(int? size = null, int maxSize = 1024)
|
||||||
|
{
|
||||||
|
if (size == null)
|
||||||
|
size = _random.Next(1, maxSize);
|
||||||
|
var arr = new byte[(int) size];
|
||||||
|
_random.NextBytes(arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object RandomOne(params object[] opts)
|
||||||
|
{
|
||||||
|
return opts[_random.Next(0, opts.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -2,33 +2,29 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Xunit;
|
||||||
using Wabbajack.Common;
|
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
namespace Wabbajack.Common.Test
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class UtilsTests
|
public class UtilsTests
|
||||||
{
|
{
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public void IsInPathTests()
|
public void IsInPathTests()
|
||||||
{
|
{
|
||||||
Assert.IsTrue("c:\\foo\\bar.exe".IsInPath("c:\\foo"));
|
Assert.True("c:\\foo\\bar.exe".IsInPath("c:\\foo"));
|
||||||
Assert.IsFalse("c:\\foo\\bar.exe".IsInPath("c:\\fo"));
|
Assert.False("c:\\foo\\bar.exe".IsInPath("c:\\fo"));
|
||||||
Assert.IsTrue("c:\\Foo\\bar.exe".IsInPath("c:\\foo"));
|
Assert.True("c:\\Foo\\bar.exe".IsInPath("c:\\foo"));
|
||||||
Assert.IsTrue("c:\\foo\\bar.exe".IsInPath("c:\\Foo"));
|
Assert.True("c:\\foo\\bar.exe".IsInPath("c:\\Foo"));
|
||||||
Assert.IsTrue("c:\\foo\\bar.exe".IsInPath("c:\\fOo"));
|
Assert.True("c:\\foo\\bar.exe".IsInPath("c:\\fOo"));
|
||||||
Assert.IsTrue("c:\\foo\\bar.exe".IsInPath("c:\\foo\\"));
|
Assert.True("c:\\foo\\bar.exe".IsInPath("c:\\foo\\"));
|
||||||
Assert.IsTrue("c:\\foo\\bar\\".IsInPath("c:\\foo\\"));
|
Assert.True("c:\\foo\\bar\\".IsInPath("c:\\foo\\"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
[Theory]
|
||||||
[DataTestMethod]
|
[ClassData(typeof(PatchData))]
|
||||||
[DynamicData(nameof(PatchData), DynamicDataSourceType.Method)]
|
|
||||||
public async Task DiffCreateAndApply(byte[] src, byte[] dest, DiffMethod method)
|
public async Task DiffCreateAndApply(byte[] src, byte[] dest, DiffMethod method)
|
||||||
{
|
{
|
||||||
await using var ms = new MemoryStream();
|
await using var ms = new MemoryStream();
|
||||||
@ -51,7 +47,7 @@ namespace Wabbajack.Test
|
|||||||
var patch = ms.ToArray();
|
var patch = ms.ToArray();
|
||||||
await using var resultStream = new MemoryStream();
|
await using var resultStream = new MemoryStream();
|
||||||
Utils.ApplyPatch(new MemoryStream(src), () => new MemoryStream(patch), resultStream);
|
Utils.ApplyPatch(new MemoryStream(src), () => new MemoryStream(patch), resultStream);
|
||||||
CollectionAssert.AreEqual(dest, resultStream.ToArray());
|
Assert.Equal(dest, resultStream.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -61,10 +57,18 @@ namespace Wabbajack.Test
|
|||||||
BSDiff,
|
BSDiff,
|
||||||
OctoDiff
|
OctoDiff
|
||||||
}
|
}
|
||||||
public static IEnumerable<object[]> PatchData()
|
public class PatchData : TheoryData<byte[], byte[], DiffMethod>
|
||||||
{
|
{
|
||||||
var maxSize = 1024 * 1024 * 8;
|
public PatchData()
|
||||||
return Enumerable.Range(0, 10).Select(x => new[] {TestUtils.RandomData(maxSize:maxSize), TestUtils.RandomData(maxSize:maxSize), TestUtils.RandomeOne(DiffMethod.Default, DiffMethod.OctoDiff, DiffMethod.BSDiff)});
|
{
|
||||||
|
var maxSize = 64;
|
||||||
|
Enumerable.Range(0, 10).Do(x =>
|
||||||
|
|
||||||
|
{
|
||||||
|
Add(TestUtils.RandomData(maxSize: maxSize), TestUtils.RandomData(maxSize: maxSize),
|
||||||
|
(DiffMethod)TestUtils.RandomOne(DiffMethod.Default, DiffMethod.OctoDiff, DiffMethod.BSDiff));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
20
Wabbajack.Common.Test/Wabbajack.Common.Test.csproj
Normal file
20
Wabbajack.Common.Test/Wabbajack.Common.Test.csproj
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<Platforms>x64</Platforms>
|
||||||
|
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -1,17 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Xunit;
|
||||||
using Wabbajack.Common;
|
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
namespace Wabbajack.Common.Test
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class WorkQueueTests
|
public class WorkQueueTests
|
||||||
{
|
{
|
||||||
#region DynamicNumThreads
|
#region DynamicNumThreads
|
||||||
@ -20,144 +16,144 @@ namespace Wabbajack.Test
|
|||||||
const int Small = 4;
|
const int Small = 4;
|
||||||
public TimeSpan PollMS => TimeSpan.FromSeconds(1);
|
public TimeSpan PollMS => TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public void DynamicNumThreads_Typical()
|
public void DynamicNumThreads_Typical()
|
||||||
{
|
{
|
||||||
using (var queue = new WorkQueue())
|
using (var queue = new WorkQueue())
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Environment.ProcessorCount, queue.DesiredNumWorkers);
|
Assert.Equal(Environment.ProcessorCount, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Environment.ProcessorCount, queue._tasks.Count);
|
Assert.Equal(Environment.ProcessorCount, queue._tasks.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public void DynamicNumThreads_Increased()
|
public void DynamicNumThreads_Increased()
|
||||||
{
|
{
|
||||||
var subj = new BehaviorSubject<int>(Small);
|
var subj = new BehaviorSubject<int>(Small);
|
||||||
using (var queue = new WorkQueue(subj))
|
using (var queue = new WorkQueue(subj))
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Small, queue.DesiredNumWorkers);
|
Assert.Equal(Small, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Small, queue._tasks.Count);
|
Assert.Equal(Small, queue._tasks.Count);
|
||||||
subj.OnNext(Large);
|
subj.OnNext(Large);
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public void DynamicNumThreads_EmptyObs()
|
public void DynamicNumThreads_EmptyObs()
|
||||||
{
|
{
|
||||||
using (var queue = new WorkQueue(Observable.Empty<int>()))
|
using (var queue = new WorkQueue(Observable.Empty<int>()))
|
||||||
{
|
{
|
||||||
Assert.AreEqual(0, queue.DesiredNumWorkers);
|
Assert.Equal(0, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(0, queue._tasks.Count);
|
Assert.Equal(0, queue._tasks.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task DynamicNumThreads_Decreased()
|
public async Task DynamicNumThreads_Decreased()
|
||||||
{
|
{
|
||||||
var subj = new BehaviorSubject<int>(Large);
|
var subj = new BehaviorSubject<int>(Large);
|
||||||
using (var queue = new WorkQueue(subj))
|
using (var queue = new WorkQueue(subj))
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
subj.OnNext(Small);
|
subj.OnNext(Small);
|
||||||
Assert.AreEqual(Small, queue.DesiredNumWorkers);
|
Assert.Equal(Small, queue.DesiredNumWorkers);
|
||||||
// Tasks don't go down immediately
|
// Tasks don't go down immediately
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
// After things re-poll, they should be cleaned
|
// After things re-poll, they should be cleaned
|
||||||
await Task.Delay(PollMS * 2);
|
await Task.Delay(PollMS * 2);
|
||||||
Assert.AreEqual(Small, queue._tasks.Count);
|
Assert.Equal(Small, queue._tasks.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task DynamicNumThreads_IncreasedWhileWorking()
|
public async Task DynamicNumThreads_IncreasedWhileWorking()
|
||||||
{
|
{
|
||||||
var subj = new BehaviorSubject<int>(Small);
|
var subj = new BehaviorSubject<int>(Small);
|
||||||
var tcs = new TaskCompletionSource<bool>();
|
var tcs = new TaskCompletionSource<bool>();
|
||||||
using (var queue = new WorkQueue(subj))
|
using (var queue = new WorkQueue(subj))
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Small, queue.DesiredNumWorkers);
|
Assert.Equal(Small, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Small, queue._tasks.Count);
|
Assert.Equal(Small, queue._tasks.Count);
|
||||||
Enumerable.Range(0, Small).Do(_ => queue.QueueTask(() => tcs.Task));
|
Enumerable.Range(0, Small).Do(_ => queue.QueueTask(() => tcs.Task));
|
||||||
subj.OnNext(Large);
|
subj.OnNext(Large);
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
Task.Run(() => tcs.SetResult(true)).FireAndForget();
|
Task.Run(() => tcs.SetResult(true)).FireAndForget();
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
await Task.Delay(PollMS * 2);
|
await Task.Delay(PollMS * 2);
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task DynamicNumThreads_DecreasedWhileWorking()
|
public async Task DynamicNumThreads_DecreasedWhileWorking()
|
||||||
{
|
{
|
||||||
var subj = new BehaviorSubject<int>(Large);
|
var subj = new BehaviorSubject<int>(Large);
|
||||||
var tcs = new TaskCompletionSource<bool>();
|
var tcs = new TaskCompletionSource<bool>();
|
||||||
using (var queue = new WorkQueue(subj))
|
using (var queue = new WorkQueue(subj))
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
Enumerable.Range(0, Large).Do(_ => queue.QueueTask(() => tcs.Task));
|
Enumerable.Range(0, Large).Do(_ => queue.QueueTask(() => tcs.Task));
|
||||||
subj.OnNext(Small);
|
subj.OnNext(Small);
|
||||||
Assert.AreEqual(Small, queue.DesiredNumWorkers);
|
Assert.Equal(Small, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
// After things re-poll, they should still be working at max
|
// After things re-poll, they should still be working at max
|
||||||
await Task.Delay(PollMS * 2);
|
await Task.Delay(PollMS * 2);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
// Complete, repoll, and check again
|
// Complete, repoll, and check again
|
||||||
Task.Run(() => tcs.SetResult(true)).FireAndForget();
|
Task.Run(() => tcs.SetResult(true)).FireAndForget();
|
||||||
await Task.Delay(PollMS * 2);
|
await Task.Delay(PollMS * 2);
|
||||||
Assert.AreEqual(Small, queue._tasks.Count);
|
Assert.Equal(Small, queue._tasks.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task DynamicNumThreads_IncreasedThenDecreased()
|
public async Task DynamicNumThreads_IncreasedThenDecreased()
|
||||||
{
|
{
|
||||||
var subj = new BehaviorSubject<int>(Small);
|
var subj = new BehaviorSubject<int>(Small);
|
||||||
using (var queue = new WorkQueue(subj))
|
using (var queue = new WorkQueue(subj))
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Small, queue.DesiredNumWorkers);
|
Assert.Equal(Small, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Small, queue._tasks.Count);
|
Assert.Equal(Small, queue._tasks.Count);
|
||||||
subj.OnNext(Large);
|
subj.OnNext(Large);
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
subj.OnNext(Small);
|
subj.OnNext(Small);
|
||||||
// Still large number of threads, as not immediate
|
// Still large number of threads, as not immediate
|
||||||
Assert.AreEqual(Small, queue.DesiredNumWorkers);
|
Assert.Equal(Small, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
// After things re-poll, they should still be working at max
|
// After things re-poll, they should still be working at max
|
||||||
await Task.Delay(PollMS * 2);
|
await Task.Delay(PollMS * 2);
|
||||||
Assert.AreEqual(Small, queue.DesiredNumWorkers);
|
Assert.Equal(Small, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Small, queue._tasks.Count);
|
Assert.Equal(Small, queue._tasks.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task DynamicNumThreads_DecreasedThenIncreased()
|
public async Task DynamicNumThreads_DecreasedThenIncreased()
|
||||||
{
|
{
|
||||||
var subj = new BehaviorSubject<int>(Large);
|
var subj = new BehaviorSubject<int>(Large);
|
||||||
using (var queue = new WorkQueue(subj))
|
using (var queue = new WorkQueue(subj))
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
subj.OnNext(Small);
|
subj.OnNext(Small);
|
||||||
Assert.AreEqual(Small, queue.DesiredNumWorkers);
|
Assert.Equal(Small, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
subj.OnNext(Large);
|
subj.OnNext(Large);
|
||||||
// New threads allocated immediately
|
// New threads allocated immediately
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
// After things re-poll, still here
|
// After things re-poll, still here
|
||||||
await Task.Delay(PollMS * 2);
|
await Task.Delay(PollMS * 2);
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -172,7 +168,7 @@ namespace Wabbajack.Test
|
|||||||
/// The solution to this is just make sure that any work done relating to WorkQueue be done within its own Task.Run() call, so that if it that thread
|
/// The solution to this is just make sure that any work done relating to WorkQueue be done within its own Task.Run() call, so that if it that thread
|
||||||
/// "takes over" a workqueue loop, it doesn't matter as it was a threadpool thread anyway.
|
/// "takes over" a workqueue loop, it doesn't matter as it was a threadpool thread anyway.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestMethod]
|
[Fact]
|
||||||
public async Task Deadlock()
|
public async Task Deadlock()
|
||||||
{
|
{
|
||||||
var task = Task.Run(async () =>
|
var task = Task.Run(async () =>
|
||||||
@ -186,8 +182,8 @@ namespace Wabbajack.Test
|
|||||||
tcs.SetResult(true);
|
tcs.SetResult(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var completed = Task.WhenAny(Task.Delay(3000), task);
|
var completed = await Task.WhenAny(Task.Delay(3000), task);
|
||||||
Assert.ReferenceEquals(completed, task);
|
Assert.Equal(completed, task);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -218,8 +214,8 @@ namespace Wabbajack.Test
|
|||||||
object lockObj = new object();
|
object lockObj = new object();
|
||||||
using (var queue = new WorkQueue(subj))
|
using (var queue = new WorkQueue(subj))
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
|
|
||||||
bool[] workStartedArray = new bool[Large];
|
bool[] workStartedArray = new bool[Large];
|
||||||
async Task Job(int num, bool[] b)
|
async Task Job(int num, bool[] b)
|
||||||
@ -240,7 +236,7 @@ namespace Wabbajack.Test
|
|||||||
// Show that all jobs are started
|
// Show that all jobs are started
|
||||||
lock (lockObj)
|
lock (lockObj)
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Large, workStartedArray.Where(i => i).Count());
|
Assert.Equal(Large, workStartedArray.Where(i => i).Count());
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(15000);
|
await Task.Delay(15000);
|
||||||
@ -251,8 +247,8 @@ namespace Wabbajack.Test
|
|||||||
// that kicked it off and is in charge of the continuation tasks.
|
// that kicked it off and is in charge of the continuation tasks.
|
||||||
// Parallel worker Tasks have now coalesced into a single thread
|
// Parallel worker Tasks have now coalesced into a single thread
|
||||||
Task.Run(() => tcs.SetResult(true)).FireAndForget();
|
Task.Run(() => tcs.SetResult(true)).FireAndForget();
|
||||||
Assert.AreEqual(Large, queue.DesiredNumWorkers);
|
Assert.Equal(Large, queue.DesiredNumWorkers);
|
||||||
Assert.AreEqual(Large, queue._tasks.Count);
|
Assert.Equal(Large, queue._tasks.Count);
|
||||||
|
|
||||||
await Task.Delay(10000);
|
await Task.Delay(10000);
|
||||||
|
|
||||||
@ -264,7 +260,7 @@ namespace Wabbajack.Test
|
|||||||
// Show that only one job was started/worked on (by our one coalesced worker thread)
|
// Show that only one job was started/worked on (by our one coalesced worker thread)
|
||||||
lock (lockObj)
|
lock (lockObj)
|
||||||
{
|
{
|
||||||
Assert.AreEqual(1, secondWorkStartedArray.Where(i => i).Count());
|
Assert.Equal(1, secondWorkStartedArray.Where(i => i).Count());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,7 +16,7 @@ namespace Wabbajack.Common
|
|||||||
{
|
{
|
||||||
public class WorkQueue : IDisposable
|
public class WorkQueue : IDisposable
|
||||||
{
|
{
|
||||||
internal AsyncBlockingCollection<Func<Task>> Queue = new AsyncBlockingCollection<Func<Task>>();
|
internal BlockingCollection<Func<Task>> Queue = new BlockingCollection<Func<Task>>(new ConcurrentStack<Func<Task>>());
|
||||||
|
|
||||||
public const int UnassignedCpuId = 0;
|
public const int UnassignedCpuId = 0;
|
||||||
|
|
||||||
@ -31,7 +31,8 @@ namespace Wabbajack.Common
|
|||||||
public IObservable<CPUStatus> Status => _Status;
|
public IObservable<CPUStatus> Status => _Status;
|
||||||
|
|
||||||
private int _nextCpuID = 1; // Start at 1, as 0 is "Unassigned"
|
private int _nextCpuID = 1; // Start at 1, as 0 is "Unassigned"
|
||||||
internal Dictionary<int, Task> _tasks = new Dictionary<int, Task>();
|
// Public for testing reasons
|
||||||
|
public Dictionary<int, Task> _tasks = new Dictionary<int, Task>();
|
||||||
public int DesiredNumWorkers { get; private set; } = 0;
|
public int DesiredNumWorkers { get; private set; } = 0;
|
||||||
|
|
||||||
private CancellationTokenSource _shutdown = new CancellationTokenSource();
|
private CancellationTokenSource _shutdown = new CancellationTokenSource();
|
||||||
@ -50,7 +51,7 @@ namespace Wabbajack.Common
|
|||||||
|
|
||||||
private readonly Subject<IObservable<int>> _activeNumThreadsObservable = new Subject<IObservable<int>>();
|
private readonly Subject<IObservable<int>> _activeNumThreadsObservable = new Subject<IObservable<int>>();
|
||||||
|
|
||||||
public TimeSpan PollMS = TimeSpan.FromMilliseconds(200);
|
public const int PollMS = 200;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a WorkQueue with the given number of threads
|
/// Creates a WorkQueue with the given number of threads
|
||||||
@ -124,7 +125,7 @@ namespace Wabbajack.Common
|
|||||||
bool got;
|
bool got;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
(got, f) = await Queue.TryTake(PollMS, _shutdown.Token);
|
got = Queue.TryTake(out f, PollMS, _shutdown.Token);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Lib;
|
using Wabbajack.Lib;
|
||||||
using Wabbajack.Lib.LibCefHelpers;
|
using Wabbajack.Lib.LibCefHelpers;
|
||||||
using Wabbajack.Util;
|
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
namespace Wabbajack.Test
|
||||||
{
|
{
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
using Alphaleonis.Win32.Filesystem;
|
|
||||||
using Wabbajack.Common;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using Utils = Wabbajack.Common.Utils;
|
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
|
||||||
{
|
|
||||||
[TestClass]
|
|
||||||
public class MiscTests
|
|
||||||
{
|
|
||||||
[TestMethod]
|
|
||||||
public void TestDiskSpeed()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue())
|
|
||||||
{
|
|
||||||
var speed = Utils.TestDiskSpeed(queue, @".\");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void TestHash()
|
|
||||||
{
|
|
||||||
const string data = "Cheese for Everyone!";
|
|
||||||
File.WriteAllText("test.data", data);
|
|
||||||
Assert.AreEqual("eSIyd+KOG3s=", "test.data".FileHashCached(), "Hash is cached");
|
|
||||||
Assert.IsTrue(Utils.TryGetHashCache("test.data", out var fileHash), "New caching method is invoked");
|
|
||||||
Assert.AreEqual("eSIyd+KOG3s=", fileHash, "The correct hash value is cached");
|
|
||||||
Assert.AreNotEqual("eSIyd+KOG3s=", File.ReadAllText("test.data" + Consts.HashFileExtension), "We don't store the hash in plaintext");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,230 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using Wabbajack.Common;
|
|
||||||
|
|
||||||
namespace Wabbajack.Test
|
|
||||||
{
|
|
||||||
[TestClass]
|
|
||||||
public class PMapTests
|
|
||||||
{
|
|
||||||
const int TypicalThreadCount = 6;
|
|
||||||
const int TypicalDelayMS = 50;
|
|
||||||
const int TimeoutSeconds = 15;
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task Typical_Action()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue(TypicalThreadCount))
|
|
||||||
{
|
|
||||||
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
|
||||||
var output = new List<int>();
|
|
||||||
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, (item) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
Thread.Sleep(TypicalDelayMS);
|
|
||||||
lock (output)
|
|
||||||
{
|
|
||||||
output.Add(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
|
||||||
Assert.IsTrue(input.SequenceEqual(output.OrderBy(i => i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task Typical_Func()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue(TypicalThreadCount))
|
|
||||||
{
|
|
||||||
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
|
||||||
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, (item) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
Thread.Sleep(TypicalDelayMS);
|
|
||||||
return item.ToString();
|
|
||||||
});
|
|
||||||
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
|
||||||
Assert.IsTrue(input.Select(i => i.ToString()).SequenceEqual(results));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task Typical_Task()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue(TypicalThreadCount))
|
|
||||||
{
|
|
||||||
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
|
||||||
var output = new List<int>();
|
|
||||||
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (item) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
await Task.Delay(TypicalDelayMS);
|
|
||||||
lock (output)
|
|
||||||
{
|
|
||||||
output.Add(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
|
||||||
Assert.IsTrue(input.SequenceEqual(output.OrderBy(i => i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task Typical_TaskReturn()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue(TypicalThreadCount))
|
|
||||||
{
|
|
||||||
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
|
||||||
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (item) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
await Task.Delay(TypicalDelayMS);
|
|
||||||
return item.ToString();
|
|
||||||
});
|
|
||||||
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
|
||||||
Assert.IsTrue(input.Select(i => i.ToString()).SequenceEqual(results));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task NestedAction()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue(TypicalThreadCount))
|
|
||||||
{
|
|
||||||
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
|
||||||
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
|
||||||
var output = new List<int>();
|
|
||||||
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (item) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
await Enumerable.Range(item * 100, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (subItem) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
Thread.Sleep(TypicalDelayMS);
|
|
||||||
lock (output)
|
|
||||||
{
|
|
||||||
output.Add(subItem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
|
||||||
Assert.IsTrue(inputConstructedResults.SequenceEqual(output.OrderBy(i => i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task Nested_Func()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue(TypicalThreadCount))
|
|
||||||
{
|
|
||||||
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
|
||||||
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
|
||||||
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (item) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, (subItem) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
Thread.Sleep(TypicalDelayMS);
|
|
||||||
return subItem;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
|
||||||
Assert.IsTrue(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task Nested_Task()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue(TypicalThreadCount))
|
|
||||||
{
|
|
||||||
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
|
||||||
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
|
||||||
var output = new List<int>();
|
|
||||||
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (item) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
await Enumerable.Range(item * 100, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (subItem) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
await Task.Delay(TypicalDelayMS);
|
|
||||||
lock (output)
|
|
||||||
{
|
|
||||||
output.Add(subItem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
|
||||||
Assert.IsTrue(inputConstructedResults.SequenceEqual(output.OrderBy(i => i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task Nested_TaskReturn()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue(TypicalThreadCount))
|
|
||||||
{
|
|
||||||
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
|
||||||
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
|
||||||
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (item) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (subItem) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
await Task.Delay(TypicalDelayMS);
|
|
||||||
return subItem;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
|
||||||
Assert.IsTrue(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task Nested_BackgroundThreadsInvolved()
|
|
||||||
{
|
|
||||||
using (var queue = new WorkQueue(TypicalThreadCount))
|
|
||||||
{
|
|
||||||
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
|
|
||||||
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
|
|
||||||
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (item) =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
|
|
||||||
.PMap(queue, async (subItem) =>
|
|
||||||
{
|
|
||||||
return await Task.Run(async () =>
|
|
||||||
{
|
|
||||||
Assert.IsTrue(WorkQueue.WorkerThread);
|
|
||||||
await Task.Delay(TypicalDelayMS);
|
|
||||||
return subItem;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
|
|
||||||
Assert.IsTrue(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Alphaleonis.Win32.Filesystem;
|
using Alphaleonis.Win32.Filesystem;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
@ -22,37 +23,37 @@ namespace Wabbajack.Test
|
|||||||
WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "tmp_data");
|
WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "tmp_data");
|
||||||
}
|
}
|
||||||
|
|
||||||
public string WorkingDirectory { get;}
|
public AbsolutePath WorkingDirectory { get;}
|
||||||
public string ID { get; }
|
public string ID { get; }
|
||||||
public Random RNG => _rng;
|
public Random RNG => _rng;
|
||||||
|
|
||||||
public Game Game { get; set; }
|
public Game Game { get; set; }
|
||||||
|
|
||||||
public string TestFolder => Path.Combine(WorkingDirectory, ID);
|
public AbsolutePath TestFolder => WorkingDirectory.Combine(ID);
|
||||||
public string GameFolder => Path.Combine(WorkingDirectory, ID, "game_folder");
|
public AbsolutePath GameFolder => WorkingDirectory.Combine(ID, "game_folder");
|
||||||
|
|
||||||
public string MO2Folder => Path.Combine(WorkingDirectory, ID, "mo2_folder");
|
public AbsolutePath MO2Folder => WorkingDirectory.Combine(ID, "mo2_folder");
|
||||||
public string ModsFolder => Path.Combine(MO2Folder, Consts.MO2ModFolderName);
|
public AbsolutePath ModsFolder => MO2Folder.Combine(Consts.MO2ModFolderName);
|
||||||
public string DownloadsFolder => Path.Combine(MO2Folder, "downloads");
|
public AbsolutePath DownloadsFolder => MO2Folder.Combine("downloads");
|
||||||
|
|
||||||
public string InstallFolder => Path.Combine(TestFolder, "installed");
|
public AbsolutePath InstallFolder => TestFolder.Combine("installed");
|
||||||
|
|
||||||
public HashSet<string> Profiles = new HashSet<string>();
|
public HashSet<string> Profiles = new HashSet<string>();
|
||||||
|
|
||||||
public List<string> Mods = new List<string>();
|
public List<string> Mods = new List<string>();
|
||||||
|
|
||||||
public void Configure()
|
public async Task Configure()
|
||||||
{
|
{
|
||||||
File.WriteAllLines(Path.Combine(MO2Folder, "ModOrganizer.ini"), new []
|
await MO2Folder.Combine("ModOrganizer.ini").WriteAllLinesAsync(new []
|
||||||
{
|
{
|
||||||
"[General]",
|
"[General]",
|
||||||
$"gameName={Game.MetaData().MO2Name}",
|
$"gameName={Game.MetaData().MO2Name}",
|
||||||
$"gamePath={GameFolder.Replace("\\", "\\\\")}",
|
$"gamePath={((string)GameFolder).Replace("\\", "\\\\")}",
|
||||||
$"download_directory={DownloadsFolder}"
|
$"download_directory={DownloadsFolder}"
|
||||||
});
|
});
|
||||||
|
|
||||||
Directory.CreateDirectory(DownloadsFolder);
|
DownloadsFolder.CreateDirectory();
|
||||||
Directory.CreateDirectory(Path.Combine(GameFolder, "Data"));
|
GameFolder.Combine("Data").CreateDirectory();
|
||||||
|
|
||||||
Profiles.Do(profile =>
|
Profiles.Do(profile =>
|
||||||
{
|
{
|
||||||
@ -260,9 +261,6 @@ namespace Wabbajack.Test
|
|||||||
return full_path;
|
return full_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static object RandomeOne(params object[] opts)
|
|
||||||
{
|
|
||||||
return opts[_rng.Next(0, opts.Length)];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
@ -26,7 +26,6 @@
|
|||||||
<ProjectReference Include="..\Wabbajack.Common.CSP\Wabbajack.Common.CSP.csproj" />
|
<ProjectReference Include="..\Wabbajack.Common.CSP\Wabbajack.Common.CSP.csproj" />
|
||||||
<ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj" />
|
<ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj" />
|
||||||
<ProjectReference Include="..\Wabbajack.Lib\Wabbajack.Lib.csproj" />
|
<ProjectReference Include="..\Wabbajack.Lib\Wabbajack.Lib.csproj" />
|
||||||
<ProjectReference Include="..\Wabbajack\Wabbajack.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
|
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -38,6 +38,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.CLI", "Wabbajack.
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.Launcher", "Wabbajack.Launcher\Wabbajack.Launcher.csproj", "{D6856DBF-C959-4867-A8A8-343DA2D2715E}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.Launcher", "Wabbajack.Launcher\Wabbajack.Launcher.csproj", "{D6856DBF-C959-4867-A8A8-343DA2D2715E}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Common.Test", "Wabbajack.Common.Test\Wabbajack.Common.Test.csproj", "{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -76,12 +78,6 @@ Global
|
|||||||
{5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E}.Release|Any CPU.ActiveCfg = Release|x64
|
{5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E}.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
{5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E}.Release|x64.ActiveCfg = Release|x64
|
{5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E}.Release|x64.ActiveCfg = Release|x64
|
||||||
{5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E}.Release|x64.Build.0 = Release|x64
|
{5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E}.Release|x64.Build.0 = Release|x64
|
||||||
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Debug|Any CPU.ActiveCfg = Debug|x64
|
|
||||||
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Release|Any CPU.ActiveCfg = Release|x64
|
|
||||||
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Release|x64.Build.0 = Release|x64
|
|
||||||
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
@ -128,6 +124,14 @@ Global
|
|||||||
{D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|x64.ActiveCfg = Release|Any CPU
|
{D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|x64.Build.0 = Release|Any CPU
|
{D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|x64.Build.0 = Debug|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
Loading…
Reference in New Issue
Block a user