2020-03-30 03:47:35 +00:00
|
|
|
|
using System;
|
2020-05-19 03:46:33 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO.Compression;
|
2020-03-30 03:47:35 +00:00
|
|
|
|
using System.Reactive.Linq;
|
2020-05-19 03:46:33 +00:00
|
|
|
|
using System.Text;
|
2020-03-30 03:47:35 +00:00
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
|
using Wabbajack.Common;
|
|
|
|
|
using Wabbajack.Common.Http;
|
|
|
|
|
using Wabbajack.Common.StatusFeed;
|
2020-05-19 03:46:33 +00:00
|
|
|
|
using Wabbajack.Lib;
|
|
|
|
|
using Wabbajack.Lib.Downloaders;
|
2020-04-08 04:19:36 +00:00
|
|
|
|
using Wabbajack.Lib.FileUploader;
|
2020-05-19 03:46:33 +00:00
|
|
|
|
using Wabbajack.Lib.ModListRegistry;
|
2020-05-09 05:12:51 +00:00
|
|
|
|
using Wabbajack.Server;
|
|
|
|
|
using Wabbajack.Server.DataLayer;
|
2020-03-30 03:47:35 +00:00
|
|
|
|
using Xunit;
|
|
|
|
|
using Xunit.Abstractions;
|
|
|
|
|
|
|
|
|
|
namespace Wabbajack.BuildServer.Test
|
|
|
|
|
{
|
|
|
|
|
public class BuildServerFixture : ADBTest, IDisposable
|
|
|
|
|
{
|
|
|
|
|
private IHost _host;
|
|
|
|
|
private CancellationTokenSource _token;
|
|
|
|
|
private Task _task;
|
|
|
|
|
|
2020-04-28 04:03:57 +00:00
|
|
|
|
public readonly TempFolder _severTempFolder = TempFolder.Create().Result;
|
2020-04-03 22:33:19 +00:00
|
|
|
|
private bool _disposed = false;
|
2020-03-30 03:47:35 +00:00
|
|
|
|
public AbsolutePath ServerTempFolder => _severTempFolder.Dir;
|
|
|
|
|
|
2020-04-08 04:19:36 +00:00
|
|
|
|
public AbsolutePath ServerPublicFolder => "public".RelativeTo(AbsolutePath.EntryPoint);
|
|
|
|
|
|
2020-04-09 12:46:33 +00:00
|
|
|
|
public AbsolutePath ServerArchivesFolder => "archives".RelativeTo(AbsolutePath.EntryPoint);
|
2020-04-10 03:54:02 +00:00
|
|
|
|
public AbsolutePath ServerUpdatesFolder => "updates".RelativeTo(AbsolutePath.EntryPoint);
|
2020-04-09 12:46:33 +00:00
|
|
|
|
|
2020-03-30 03:47:35 +00:00
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
public static async Task Start()
|
2020-03-30 03:47:35 +00:00
|
|
|
|
{
|
2020-05-25 17:34:25 +00:00
|
|
|
|
var fixture = new BuildServerFixture();
|
|
|
|
|
fixture.ServerArchivesFolder.DeleteDirectory().Wait();
|
|
|
|
|
fixture.ServerArchivesFolder.CreateDirectory();
|
2020-05-13 03:04:32 +00:00
|
|
|
|
|
2020-03-30 03:47:35 +00:00
|
|
|
|
var builder = Program.CreateHostBuilder(
|
|
|
|
|
new[]
|
|
|
|
|
{
|
|
|
|
|
$"WabbajackSettings:DownloadDir={"tmp".RelativeTo(AbsolutePath.EntryPoint)}",
|
|
|
|
|
$"WabbajackSettings:ArchiveDir={"archives".RelativeTo(AbsolutePath.EntryPoint)}",
|
2020-05-25 17:34:25 +00:00
|
|
|
|
$"WabbajackSettings:TempFolder={fixture.ServerTempFolder}",
|
|
|
|
|
$"WabbajackSettings:SQLConnection={fixture.PublicConnStr}",
|
2020-03-30 20:38:46 +00:00
|
|
|
|
$"WabbajackSettings:BunnyCDN_User=TEST",
|
|
|
|
|
$"WabbajackSettings:BunnyCDN_Password=TEST",
|
2020-03-31 22:05:36 +00:00
|
|
|
|
"WabbajackSettings:JobScheduler=false",
|
2020-04-02 21:16:46 +00:00
|
|
|
|
"WabbajackSettings:JobRunner=false",
|
2020-05-09 13:22:02 +00:00
|
|
|
|
"WabbajackSettings:RunBackEndJobs=false",
|
|
|
|
|
"WabbajackSettings:RunFrontEndJobs=false",
|
2020-04-02 21:16:46 +00:00
|
|
|
|
"WabbajackSettinss:DisableNexusForwarding=true"
|
2020-03-30 03:47:35 +00:00
|
|
|
|
}, true);
|
2020-05-25 17:34:25 +00:00
|
|
|
|
fixture._host = builder.Build();
|
|
|
|
|
fixture._token = new CancellationTokenSource();
|
|
|
|
|
fixture._task = fixture._host.RunAsync(fixture._token.Token);
|
2020-03-30 20:38:46 +00:00
|
|
|
|
Consts.WabbajackBuildServerUri = new Uri("http://localhost:8080");
|
2020-04-08 04:19:36 +00:00
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
await "ServerWhitelist.yaml".RelativeTo(fixture.ServerPublicFolder).WriteAllTextAsync(
|
2020-04-08 04:19:36 +00:00
|
|
|
|
"GoogleIDs:\nAllowedPrefixes:\n - http://localhost");
|
2020-05-13 03:04:32 +00:00
|
|
|
|
|
2020-03-30 03:47:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-03 22:33:19 +00:00
|
|
|
|
~BuildServerFixture()
|
|
|
|
|
{
|
|
|
|
|
Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-31 22:05:36 +00:00
|
|
|
|
public T GetService<T>()
|
|
|
|
|
{
|
|
|
|
|
return (T)_host.Services.GetService(typeof(T));
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-09 12:46:33 +00:00
|
|
|
|
|
|
|
|
|
|
2020-03-30 03:47:35 +00:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2020-04-03 22:33:19 +00:00
|
|
|
|
if (_disposed) return;
|
|
|
|
|
_disposed = true;
|
2020-03-30 03:47:35 +00:00
|
|
|
|
if (!_token.IsCancellationRequested)
|
|
|
|
|
_token.Cancel();
|
2020-03-31 22:05:36 +00:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_task.Wait();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-30 03:47:35 +00:00
|
|
|
|
_severTempFolder.DisposeAsync().AsTask().Wait();
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-01 11:47:47 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Bit of a hack to get around that we don't want the system starting and stopping our
|
|
|
|
|
/// HTTP server for each class its testing.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
public class SingletonAdaptor<T> where T : new()
|
|
|
|
|
{
|
|
|
|
|
private static T _singleton = default;
|
|
|
|
|
private static object _lock = new object();
|
|
|
|
|
public SingletonAdaptor()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public T Deref()
|
|
|
|
|
{
|
|
|
|
|
lock (this)
|
|
|
|
|
{
|
|
|
|
|
if (_singleton == null)
|
|
|
|
|
{
|
|
|
|
|
_singleton = new T();
|
|
|
|
|
if (_singleton is IAsyncLifetime d)
|
|
|
|
|
{
|
|
|
|
|
d.InitializeAsync().Wait();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _singleton;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-09 12:46:33 +00:00
|
|
|
|
|
2020-04-01 11:47:47 +00:00
|
|
|
|
}
|
2020-03-30 03:47:35 +00:00
|
|
|
|
|
2020-04-09 12:46:33 +00:00
|
|
|
|
|
2020-04-01 11:47:47 +00:00
|
|
|
|
[Collection("ServerTests")]
|
|
|
|
|
public class ABuildServerSystemTest : XunitContextBase, IClassFixture<SingletonAdaptor<BuildServerFixture>>
|
2020-03-30 03:47:35 +00:00
|
|
|
|
{
|
|
|
|
|
protected readonly Client _client;
|
|
|
|
|
private readonly IDisposable _unsubMsgs;
|
|
|
|
|
private readonly IDisposable _unsubErr;
|
|
|
|
|
protected Client _authedClient;
|
2020-03-30 20:38:46 +00:00
|
|
|
|
protected WorkQueue _queue;
|
2020-04-09 12:46:33 +00:00
|
|
|
|
private Random _random;
|
2020-03-30 03:47:35 +00:00
|
|
|
|
|
|
|
|
|
|
2020-04-01 11:47:47 +00:00
|
|
|
|
public ABuildServerSystemTest(ITestOutputHelper output, SingletonAdaptor<BuildServerFixture> fixture) : base(output)
|
2020-03-30 03:47:35 +00:00
|
|
|
|
{
|
2020-03-30 20:38:46 +00:00
|
|
|
|
Filters.Clear();
|
2020-03-30 03:47:35 +00:00
|
|
|
|
_unsubMsgs = Utils.LogMessages.OfType<IInfo>().Subscribe(onNext: msg => XunitContext.WriteLine(msg.ShortDescription));
|
|
|
|
|
_unsubErr = Utils.LogMessages.OfType<IUserIntervention>().Subscribe(msg =>
|
|
|
|
|
XunitContext.WriteLine("ERROR: User intervention required: " + msg.ShortDescription));
|
|
|
|
|
_client = new Client();
|
|
|
|
|
_authedClient = new Client();
|
2020-04-01 11:47:47 +00:00
|
|
|
|
Fixture = fixture.Deref();
|
|
|
|
|
_authedClient.Headers.Add(("x-api-key", Fixture.APIKey));
|
2020-04-08 04:19:36 +00:00
|
|
|
|
AuthorAPI.ApiKeyOverride = Fixture.APIKey;
|
2020-03-30 20:38:46 +00:00
|
|
|
|
_queue = new WorkQueue();
|
2020-03-31 22:05:36 +00:00
|
|
|
|
Queue = new WorkQueue();
|
2020-04-09 12:46:33 +00:00
|
|
|
|
_random = new Random();
|
|
|
|
|
|
2020-04-08 04:19:36 +00:00
|
|
|
|
Consts.ModlistSummaryURL = MakeURL("lists/status.json");
|
|
|
|
|
Consts.ServerWhitelistURL = MakeURL("ServerWhitelist.yaml");
|
2020-05-13 03:04:32 +00:00
|
|
|
|
|
2020-03-30 03:47:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-31 22:05:36 +00:00
|
|
|
|
public WorkQueue Queue { get; set; }
|
|
|
|
|
|
2020-03-30 03:47:35 +00:00
|
|
|
|
public BuildServerFixture Fixture { get; set; }
|
|
|
|
|
|
|
|
|
|
protected string MakeURL(string path)
|
|
|
|
|
{
|
|
|
|
|
return "http://localhost:8080/" + path;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-09 12:46:33 +00:00
|
|
|
|
|
2020-05-09 22:16:16 +00:00
|
|
|
|
protected byte[] RandomData(long? size = null)
|
2020-04-09 12:46:33 +00:00
|
|
|
|
{
|
2020-05-09 22:16:16 +00:00
|
|
|
|
var arr = new byte[size ?? _random.Next(1024)];
|
2020-04-09 12:46:33 +00:00
|
|
|
|
_random.NextBytes(arr);
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-08 11:26:54 +00:00
|
|
|
|
|
2020-03-30 03:47:35 +00:00
|
|
|
|
public override void Dispose()
|
|
|
|
|
{
|
2020-03-31 22:05:36 +00:00
|
|
|
|
Queue.Dispose();
|
2020-03-30 03:47:35 +00:00
|
|
|
|
base.Dispose();
|
|
|
|
|
_unsubMsgs.Dispose();
|
|
|
|
|
_unsubErr.Dispose();
|
2020-03-31 22:05:36 +00:00
|
|
|
|
|
2020-03-30 03:47:35 +00:00
|
|
|
|
}
|
2020-05-19 03:46:33 +00:00
|
|
|
|
|
2020-05-20 22:36:29 +00:00
|
|
|
|
protected async Task<Uri> MakeModList(string modFileName)
|
2020-05-19 03:46:33 +00:00
|
|
|
|
{
|
|
|
|
|
var archive_data = Encoding.UTF8.GetBytes("Cheese for Everyone!");
|
2020-05-20 22:36:29 +00:00
|
|
|
|
var test_archive_path = modFileName.RelativeTo(Fixture.ServerPublicFolder);
|
2020-05-19 03:46:33 +00:00
|
|
|
|
await test_archive_path.WriteAllBytesAsync(archive_data);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ModListData = new ModList();
|
|
|
|
|
ModListData.Archives.Add(
|
2020-05-20 22:36:29 +00:00
|
|
|
|
new Archive(new HTTPDownloader.State(MakeURL(modFileName.ToString())))
|
2020-05-19 03:46:33 +00:00
|
|
|
|
{
|
|
|
|
|
Hash = await test_archive_path.FileHashAsync(),
|
|
|
|
|
Name = "test_archive",
|
|
|
|
|
Size = test_archive_path.Size,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var modListPath = "test_modlist.wabbajack".RelativeTo(Fixture.ServerPublicFolder);
|
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
await using (var fs = await modListPath.Create())
|
2020-05-19 03:46:33 +00:00
|
|
|
|
{
|
|
|
|
|
using var za = new ZipArchive(fs, ZipArchiveMode.Create);
|
|
|
|
|
var entry = za.CreateEntry("modlist");
|
|
|
|
|
await using var es = entry.Open();
|
|
|
|
|
ModListData.ToJson(es);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ModListMetaData = new List<ModlistMetadata>
|
|
|
|
|
{
|
|
|
|
|
new ModlistMetadata
|
|
|
|
|
{
|
|
|
|
|
Official = false,
|
|
|
|
|
Author = "Test Suite",
|
|
|
|
|
Description = "A test",
|
|
|
|
|
DownloadMetadata = new DownloadMetadata
|
|
|
|
|
{
|
|
|
|
|
Hash = await modListPath.FileHashAsync(),
|
|
|
|
|
Size = modListPath.Size
|
|
|
|
|
},
|
|
|
|
|
Links = new ModlistMetadata.LinksObject
|
|
|
|
|
{
|
|
|
|
|
MachineURL = "test_list",
|
|
|
|
|
Download = MakeURL("test_modlist.wabbajack")
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
new ModlistMetadata
|
|
|
|
|
{
|
|
|
|
|
Official = true,
|
|
|
|
|
Author = "Test Suite",
|
|
|
|
|
Description = "A list with a broken hash",
|
|
|
|
|
DownloadMetadata = new DownloadMetadata()
|
|
|
|
|
{
|
|
|
|
|
Hash = Hash.FromLong(42),
|
|
|
|
|
Size = 42
|
|
|
|
|
},
|
|
|
|
|
Links = new ModlistMetadata.LinksObject
|
|
|
|
|
{
|
|
|
|
|
MachineURL = "broken_list",
|
|
|
|
|
Download = MakeURL("test_modlist.wabbajack")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var metadataPath = "test_mod_list_metadata.json".RelativeTo(Fixture.ServerPublicFolder);
|
|
|
|
|
|
2020-05-25 17:34:25 +00:00
|
|
|
|
await ModListMetaData.ToJsonAsync(metadataPath);
|
2020-05-19 03:46:33 +00:00
|
|
|
|
|
|
|
|
|
return new Uri(MakeURL("test_mod_list_metadata.json"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ModList ModListData { get; set; }
|
|
|
|
|
|
|
|
|
|
public List<ModlistMetadata> ModListMetaData { get; set; }
|
2020-03-30 03:47:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|