Add tests for RepositoryFactory

This commit is contained in:
Jordan Brown
2020-04-20 13:12:49 -04:00
parent 4802806bdc
commit daf5d113e3
7 changed files with 129 additions and 61 deletions
@@ -250,12 +250,21 @@ namespace Tgstation.Server.Host.Components
throw;
}
}
#pragma warning restore CA1506
#pragma warning restore CA1506
/// <inheritdoc />
public Task StartAsync(CancellationToken cancellationToken) => byondInstaller.CleanCache(cancellationToken);
public Task StartAsync(CancellationToken cancellationToken)
{
CheckSystemCompatibility();
return byondInstaller.CleanCache(cancellationToken);
}
/// <inheritdoc />
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <summary>
/// Test that the <see cref="repositoryFactory"/> is functional.
/// </summary>
private void CheckSystemCompatibility() => repositoryFactory.CreateInMemory().Dispose();
}
}
@@ -10,6 +10,7 @@ using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.Jobs;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.System;
namespace Tgstation.Server.Host.Components
@@ -52,6 +53,11 @@ namespace Tgstation.Server.Host.Components
/// </summary>
readonly IPlatformIdentifier platformIdentifier;
/// <summary>
/// The <see cref="ISystemIdentityFactory"/> for the <see cref="InstanceManager"/>
/// </summary>
readonly ISystemIdentityFactory systemIdentityFactory;
/// <summary>
/// The <see cref="ILogger"/> for the <see cref="InstanceManager"/>
/// </summary>
@@ -82,6 +88,7 @@ namespace Tgstation.Server.Host.Components
/// <param name="jobManager">The value of <see cref="jobManager"/></param>
/// <param name="serverControl">The value of <see cref="serverControl"/></param>
/// <param name="platformIdentifier">The value of <see cref="platformIdentifier"/>.</param>
/// <param name="systemIdentityFactory">The value of <see cref="systemIdentityFactory"/>.</param>
/// <param name="logger">The value of <see cref="logger"/></param>
public InstanceManager(
IInstanceFactory instanceFactory,
@@ -91,6 +98,7 @@ namespace Tgstation.Server.Host.Components
IJobManager jobManager,
IServerControl serverControl,
IPlatformIdentifier platformIdentifier,
ISystemIdentityFactory systemIdentityFactory,
ILogger<InstanceManager> logger)
{
this.instanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
@@ -100,6 +108,7 @@ namespace Tgstation.Server.Host.Components
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
this.serverControl = serverControl ?? throw new ArgumentNullException(nameof(serverControl));
this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier));
this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
serverControl.RegisterForRestart(this);
@@ -228,7 +237,7 @@ namespace Tgstation.Server.Host.Components
{
try
{
platformIdentifier.CheckCompatibility();
CheckSystemCompatibility();
var factoryStartup = instanceFactory.StartAsync(cancellationToken);
await databaseContext.Initialize(cancellationToken).ConfigureAwait(false);
await jobManager.StartAsync(cancellationToken).ConfigureAwait(false);
@@ -283,5 +292,15 @@ namespace Tgstation.Server.Host.Components
downgradeVersion = updateVersion != null && updateVersion < application.Version ? updateVersion : null;
return Task.CompletedTask;
}
/// <summary>
/// Check we have a valid system identity.
/// </summary>
private void CheckSystemCompatibility()
{
using var systemIdentity = systemIdentityFactory.GetCurrent();
if (!systemIdentity.CanCreateSymlinks)
throw new InvalidOperationException("The user running tgstation-server cannot create symlinks! Please try running as an administrative user!");
}
}
}
@@ -175,7 +175,7 @@ namespace Tgstation.Server.Host.Components.Repository
progressReporter(50 + ((int)(50 * ((float)sentBytes) / totalBytes)));
return !cancellationToken.IsCancellationRequested;
},
CredentialsProvider = credentialsProvider.GenerateHandler(username, password)
CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password)
};
/// <summary>
@@ -262,7 +262,7 @@ namespace Tgstation.Server.Host.Components.Repository
return !cancellationToken.IsCancellationRequested;
},
OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested,
CredentialsProvider = credentialsProvider.GenerateHandler(username, password)
CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password)
}, logMessage);
}
catch (UserCancelledException) { }
@@ -375,7 +375,7 @@ namespace Tgstation.Server.Host.Components.Repository
return !cancellationToken.IsCancellationRequested;
},
OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested,
CredentialsProvider = credentialsProvider.GenerateHandler(username, password)
CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password)
}, "Fetch origin commits");
}
catch (UserCancelledException)
@@ -70,11 +70,12 @@ namespace Tgstation.Server.Host.Components.Repository
ILogger<RepositoryManager> logger,
RepositorySettings repositorySettings)
{
this.repositorySettings = repositorySettings ?? throw new ArgumentNullException(nameof(repositorySettings));
this.repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory));
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer));
this.repositoryLogger = repositoryLogger ?? throw new ArgumentNullException(nameof(repositoryLogger));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
this.repositorySettings = repositorySettings ?? throw new ArgumentNullException(nameof(repositorySettings));
semaphore = new SemaphoreSlim(1);
}
@@ -14,10 +14,5 @@
/// The extension of executable script files for the system
/// </summary>
string ScriptFileExtension { get; }
/// <summary>
/// Check if the system is capable of running tgstation-server.
/// </summary>
void CheckCompatibility();
}
}
@@ -1,8 +1,4 @@
using Microsoft.Extensions.Logging;
using System;
using System.Runtime.InteropServices;
using Tgstation.Server.Host.Components.Repository;
using Tgstation.Server.Host.Security;
using System.Runtime.InteropServices;
namespace Tgstation.Server.Host.System
{
@@ -15,56 +11,13 @@ namespace Tgstation.Server.Host.System
/// <inheritdoc />
public string ScriptFileExtension { get; }
/// <summary>
/// The <see cref="ISystemIdentityFactory"/> for the <see cref="PlatformIdentifier"/>.
/// </summary>
readonly ISystemIdentityFactory systemIdentityFactory;
/// <summary>
/// The <see cref="IRepositoryFactory"/> for the <see cref="PlatformIdentifier"/>.
/// </summary>
readonly IRepositoryFactory repositoryFactory;
/// <summary>
/// The <see cref="ILogger"/> for the <see cref="PlatformIdentifier"/>.
/// </summary>
readonly ILogger<PlatformIdentifier> logger;
/// <summary>
/// Construct a <see cref="PlatformIdentifier"/>
/// </summary>
/// <param name="systemIdentityFactory">The value of <see cref="systemIdentityFactory"/>.</param>
/// <param name="repositoryFactory">The value of <see cref="repositoryFactory"/>.</param>
/// <param name="logger">The value of <see cref="logger"/>.</param>
public PlatformIdentifier(
ISystemIdentityFactory systemIdentityFactory,
IRepositoryFactory repositoryFactory,
ILogger<PlatformIdentifier> logger)
public PlatformIdentifier()
{
this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
this.repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
ScriptFileExtension = IsWindows ? "bat" : "sh";
}
/// <inheritdoc />
public void CheckCompatibility()
{
try
{
repositoryFactory.CreateInMemory().Dispose();
}
catch
{
logger.LogCritical("Unable to initialize libgit2! This is a common problem on POSIX installations. Try using Docker.");
throw;
}
using var systemIdentity = systemIdentityFactory.GetCurrent();
if (!systemIdentity.CanCreateSymlinks)
throw new InvalidOperationException("The user running tgstation-server cannot create symlinks! Please try running as an administrative user!");
}
}
}
@@ -0,0 +1,91 @@
using LibGit2Sharp;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Tgstation.Server.Host.Components.Repository.Tests
{
/// <summary>
/// Tests for <see cref="RepositoryFactory"/>.
/// </summary>
[TestClass]
public sealed class TestRepositoryFactory
{
static IRepositoryFactory CreateFactory() => new RepositoryFactory(Mock.Of<ILogger<RepositoryFactory>>());
static Task<LibGit2Sharp.IRepository> TestRepoLoading(
string path,
IRepositoryFactory repositoryFactory = null) =>
(repositoryFactory ?? CreateFactory())
.CreateFromPath(path, default);
[TestMethod]
public void TestConstructionThrows() => Assert.ThrowsException<ArgumentNullException>(() => new RepositoryFactory(null));
[TestMethod]
public void TestInMemoryRepoCreation()
{
using var repo = new RepositoryFactory(Mock.Of<ILogger<RepositoryFactory>>()).CreateInMemory();
}
[TestMethod]
public async Task TestLoadedRepoCreation()
{
using var repo = await TestRepoLoading(Path.GetFullPath("../../../../.."));
// Checking the commit previous to the one that creates this function exists
var gitObject = repo.Lookup("4802806bdccee27cb3d5fa8c2d0dfbdc117fdb4d");
Assert.IsNotNull(gitObject);
var commit = gitObject.Peel<Commit>();
Assert.AreEqual("Cleanup repository management code", commit.Message.Trim());
}
[TestMethod]
public async Task TestCloning()
{
var tempDir = Path.GetTempFileName();
File.Delete(tempDir);
try
{
var factory = CreateFactory();
await factory.Clone(
new Uri("https://github.com/Cyberboss/Test"),
new CloneOptions
{
CredentialsProvider = factory.GenerateCredentialsHandler(null, null)
},
tempDir,
default);
using (var repo = await TestRepoLoading(tempDir))
{
var gitObject = repo.Lookup("f636418bf47d238d33b0e4a34f0072b23a8aad0e");
Assert.IsNotNull(gitObject);
var commit = gitObject.Peel<Commit>();
Assert.AreEqual("Update Test.md", commit.Message);
}
}
finally
{
// Takes a while to release the repo handle sometimes...
for (var i = 0; i < 5; ++i)
{
try
{
Directory.Delete(tempDir, true);
break;
}
catch (UnauthorizedAccessException)
{
await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
}
}
}
}
}
}