Skip to content

Commit

Permalink
Fix seqcli user create (datalust#168); add multi-user testing support…
Browse files Browse the repository at this point in the history
… to the end-to-end tests
  • Loading branch information
nblumhardt committed Feb 5, 2021
1 parent 5dc5991 commit 0fcc345
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 64 deletions.
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 2020.5.{build}
version: 2021.1.{build}
skip_tags: true
image:
- Visual Studio 2019
Expand Down
2 changes: 1 addition & 1 deletion src/SeqCli/Cli/Commands/User/CreateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ protected override async Task<int> Run()
return 1;
}

user.RoleIds.Add(role.Title);
user.RoleIds.Add(role.Id);
}

if (_filter != null)
Expand Down
6 changes: 5 additions & 1 deletion test/SeqCli.EndToEnd/Args.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace SeqCli.EndToEnd
{
class Args
public class Args
{
readonly string[] _args;

Expand All @@ -19,5 +19,9 @@ public Regex[] TestCases() => _args

// Simple replacement so `Events.*` becomes `Events\..*`
static Regex ToArgRegex(string arg) => new Regex(arg.Replace(".", "\\.").Replace("*", ".*"));

public bool Multiuser() => _args.Any(a => a == "--license-certificate-stdin");

public bool UseDockerSeq() => _args.Any(a => a == "--docker-server");
}
}
2 changes: 1 addition & 1 deletion test/SeqCli.EndToEnd/Support/CaptiveProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace SeqCli.EndToEnd.Support
{
public sealed class CaptiveProcess : ITestProcess, IDisposable
public class CaptiveProcess : ITestProcess, IDisposable
{
readonly bool _captureOutput;
readonly string _stopCommandFullExePath;
Expand Down
11 changes: 11 additions & 0 deletions test/SeqCli.EndToEnd/Support/CliTestCaseAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace SeqCli.EndToEnd.Support
{
[AttributeUsage(AttributeTargets.Class)]
public class CliTestCaseAttribute : Attribute
{
public bool IsSetup { get; set; }
public bool Multiuser { get; set; }
}
}
6 changes: 5 additions & 1 deletion test/SeqCli.EndToEnd/Support/IsolatedTestCase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class IsolatedTestCase
readonly Lazy<SeqConnection> _connection;
readonly Lazy<ILogger> _logger;
readonly CliCommandRunner _commandRunner;
readonly Lazy<LicenseSetup> _licenseSetup;
readonly ICliTestCase _testCase;

ITestProcess _lastRunProcess;
Expand All @@ -20,12 +21,14 @@ public IsolatedTestCase(
Lazy<SeqConnection> connection,
Lazy<ILogger> logger,
CliCommandRunner commandRunner,
Lazy<LicenseSetup> licenseSetup,
ICliTestCase testCase)
{
_serverProcess = serverProcess;
_connection = connection;
_logger = logger;
_commandRunner = commandRunner;
_licenseSetup = licenseSetup;
_testCase = testCase ?? throw new ArgumentNullException(nameof(testCase));
}

Expand All @@ -35,7 +38,8 @@ public IsolatedTestCase(
public async Task ExecuteTestCaseAsync()
{
_lastRunProcess = _serverProcess.Value;
await _connection.Value.EnsureConnected();
await _connection.Value.EnsureConnected();
await _licenseSetup.Value.SetupAsync(_connection.Value, _logger.Value);
await _testCase.ExecuteAsync(_connection.Value, _logger.Value, _commandRunner);
}
}
Expand Down
47 changes: 47 additions & 0 deletions test/SeqCli.EndToEnd/Support/IsolatedTestCaseRegistrationSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using Autofac;
using Autofac.Core;
using Autofac.Core.Activators.Delegate;
using Autofac.Core.Lifetime;
using Autofac.Core.Registration;
using Seq.Api;
using Serilog;

namespace SeqCli.EndToEnd.Support
{
// Built-in decorator support didn't transfer metadata.
class IsolatedTestCaseRegistrationSource : IRegistrationSource
{
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
if (!(service is TypedService ts && ts.ServiceType == typeof(IsolatedTestCase)))
yield break;

var innerService = ts.ChangeType(typeof(ICliTestCase));
foreach (var inner in registrationAccessor(innerService))
{
yield return new ComponentRegistration(
Guid.NewGuid(),
new DelegateActivator(typeof(IsolatedTestCase), (ctx, p) =>
{
var tc = (ICliTestCase) ctx.ResolveComponent(new ResolveRequest(innerService, inner, p));
return new IsolatedTestCase(
ctx.Resolve<Lazy<ITestProcess>>(),
ctx.Resolve<Lazy<SeqConnection>>(),
ctx.Resolve<Lazy<ILogger>>(),
ctx.Resolve<CliCommandRunner>(),
ctx.Resolve<Lazy<LicenseSetup>>(),
tc);
}),
new CurrentScopeLifetime(),
InstanceSharing.None,
InstanceOwnership.OwnedByLifetimeScope,
new[] {service},
inner.Metadata);
}
}

public bool IsAdapterForIndividualComponents { get; } = true;
}
}
40 changes: 40 additions & 0 deletions test/SeqCli.EndToEnd/Support/LicenseCliSetupTestCase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Threading.Tasks;
using Seq.Api;
using SeqCli.EndToEnd.Support;
using Serilog;

namespace SeqCli.EndToEnd.Support
{
public class LicenseSetup
{
readonly bool _enabled;

bool _attempted;
string _certificate;

public LicenseSetup(Args args)
{
_enabled = args.Multiuser();
}

public async Task SetupAsync(
SeqConnection connection,
ILogger logger)
{
if (!_enabled)
return;

if (!_attempted)
{
_attempted = true;
logger.Information("Reading license certificate from STDIN....");
_certificate = await Console.In.ReadToEndAsync();
}

var license = await connection.Licenses.FindCurrentAsync();
license.LicenseText = _certificate;
await connection.Licenses.UpdateAsync(license);
}
}
}
11 changes: 10 additions & 1 deletion test/SeqCli.EndToEnd/Support/TestConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ namespace SeqCli.EndToEnd.Support
{
public class TestConfiguration
{
readonly Args _args;

public TestConfiguration(Args args)
{
_args = args;
}

public int ServerListenPort { get; } = 9989;

public string ServerListenUrl => $"http://localhost:{ServerListenPort}";
Expand All @@ -15,6 +22,8 @@ public class TestConfiguration

public string TestedBinary => Path.Combine(EquivalentBaseDirectory, "seqcli.dll");

public bool IsMultiuser => _args.Multiuser();

public CaptiveProcess SpawnCliProcess(string command, string additionalArgs = null, Dictionary<string, string> environment = null, bool skipServerArg = false)
{
if (command == null) throw new ArgumentNullException(nameof(command));
Expand All @@ -32,7 +41,7 @@ public CaptiveProcess SpawnServerProcess(string storagePath)
if (storagePath == null) throw new ArgumentNullException(nameof(storagePath));

var commandWithArgs = $"run --listen=\"{ServerListenUrl}\" --storage=\"{storagePath}\"";
if (Environment.GetEnvironmentVariable("ENDTOEND_USE_DOCKER_SEQ") == "Y")
if (_args.UseDockerSeq())
{
return new CaptiveProcess("docker", $"run --name seq -it --rm -e ACCEPT_EULA=Y -p {ServerListenPort}:80 datalust/seq:latest", stopCommandFullExePath: "docker", stopCommandArgs: "stop seq");
}
Expand Down
53 changes: 29 additions & 24 deletions test/SeqCli.EndToEnd/Support/TestDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Autofac.Features.Metadata;
using Autofac.Features.OwnedInstances;

namespace SeqCli.EndToEnd.Support
{
class TestDriver
{
readonly TestConfiguration _configuration;
readonly IEnumerable<Func<Owned<IsolatedTestCase>>> _cases;
readonly IEnumerable<Meta<Func<Owned<IsolatedTestCase>>>> _cases;

public TestDriver(
TestConfiguration configuration,
IEnumerable<Func<Owned<IsolatedTestCase>>> cases)
IEnumerable<Meta<Func<Owned<IsolatedTestCase>>>> cases)
{
_configuration = configuration;
_cases = cases;
Expand All @@ -31,33 +32,36 @@ public async Task<int> Run()

foreach (var testCaseFactory in _cases.OrderBy(c => Guid.NewGuid()))
{
if (testCaseFactory.Metadata.TryGetValue("Multiuser", out var multiuser) && true.Equals(multiuser) && !_configuration.IsMultiuser)
continue;

count++;
using (var testCase = testCaseFactory())
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine($"RUNNING {testCase.Value.Description.PadRight(50)}");
Console.ResetColor();

try
{
await testCase.Value.ExecuteTestCaseAsync();
await using var testCase = testCaseFactory.Value();

Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine($"RUNNING {testCase.Value.Description.PadRight(50)}");
Console.ResetColor();

try
{
await testCase.Value.ExecuteTestCaseAsync();

passed.Add(testCase.Value.Description);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("PASS");
Console.ResetColor();
}
catch (Exception ex)
{
failed.Add(testCase.Value.Description);
passed.Add(testCase.Value.Description);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("PASS");
Console.ResetColor();
}
catch (Exception ex)
{
failed.Add(testCase.Value.Description);

Console.Write(testCase.Value.Output);
Console.Write(testCase.Value.Output);

Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("FAIL");
Console.WriteLine(ex);
Console.ResetColor();
}
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("FAIL");
Console.WriteLine(ex);
Console.ResetColor();
}
}

Expand All @@ -75,3 +79,4 @@ public async Task<int> Run()
}
}
}

32 changes: 22 additions & 10 deletions test/SeqCli.EndToEnd/TestDriverModule.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac;
using Seq.Api;
using SeqCli.EndToEnd.Support;
using Serilog;
using Module = Autofac.Module;

namespace SeqCli.EndToEnd
{
Expand All @@ -18,13 +20,29 @@ public TestDriverModule(Args args)

protected override void Load(ContainerBuilder builder)
{
builder.RegisterInstance(_args);

// This enables running the program with an argument like `*Ingest*` to match all test cases
// with `Ingest` in their names.
var testCases = _args.TestCases();
builder.RegisterAssemblyTypes(ThisAssembly)
// ReSharper disable once AssignNullToNotNullAttribute
.Where(t => testCases == null || testCases.Length == 0 || testCases.Any(c => c.IsMatch(t.FullName)))
.As<ICliTestCase>();
.As<ICliTestCase>()
.WithMetadata(t =>
{
// Autofac doesn't appear to allow optional metadata using the short-cut method.
var a = t.GetCustomAttribute<CliTestCaseAttribute>();
var m = new Dictionary<string, object>();
if (a != null)
{
m["Multiuser"] = a.Multiuser;
}

return m;
});

builder.RegisterType<LicenseSetup>().SingleInstance();

builder.RegisterType<TestConfiguration>().SingleInstance();
builder.RegisterType<TestDataFolder>().InstancePerOwned<IsolatedTestCase>();
Expand All @@ -47,14 +65,8 @@ protected override void Load(ContainerBuilder builder)
.CreateLogger())
.As<ILogger>()
.InstancePerOwned<IsolatedTestCase>();

builder.RegisterAdapter<ICliTestCase, IsolatedTestCase>((ctx, tc) =>
new IsolatedTestCase(
ctx.Resolve<Lazy<ITestProcess>>(),
ctx.Resolve<Lazy<SeqConnection>>(),
ctx.Resolve<Lazy<ILogger>>(),
ctx.Resolve<CliCommandRunner>(),
tc));

builder.RegisterSource(new IsolatedTestCaseRegistrationSource());
}
}
}
Loading

0 comments on commit 0fcc345

Please sign in to comment.