-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(repeater): implement a repeater factory (#79)
closes #78
- Loading branch information
Showing
13 changed files
with
411 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Logging; | ||
using SecTester.Core; | ||
using SecTester.Core.Utils; | ||
using SecTester.Repeater.Api; | ||
using SecTester.Repeater.Bus; | ||
|
||
namespace SecTester.Repeater; | ||
|
||
public class DefaultRepeaterFactory : RepeaterFactory | ||
{ | ||
private readonly Configuration _configuration; | ||
private readonly EventBusFactory _eventBusFactory; | ||
private readonly ILogger _logger; | ||
private readonly Repeaters _repeaters; | ||
private readonly IServiceScopeFactory _serviceScopeFactory; | ||
|
||
public DefaultRepeaterFactory(IServiceScopeFactory serviceScopeFactory, Repeaters repeaters, EventBusFactory eventBusFactory, Configuration configuration, ILogger logger) | ||
{ | ||
_serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory)); | ||
_repeaters = repeaters ?? throw new ArgumentNullException(nameof(repeaters)); | ||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||
_eventBusFactory = eventBusFactory ?? throw new ArgumentNullException(nameof(eventBusFactory)); | ||
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); | ||
} | ||
|
||
public Task<Repeater> CreateRepeater() | ||
{ | ||
return CreateRepeater(new RepeaterOptions()); | ||
} | ||
|
||
public async Task<Repeater> CreateRepeater(RepeaterOptions options) | ||
{ | ||
Version version = new(_configuration.Version); | ||
|
||
string repeaterId = await _repeaters.CreateRepeater($"{options.NamePrefix}-{Guid.NewGuid()}", options.Description).ConfigureAwait(false); | ||
var eventBus = await _eventBusFactory.Create(repeaterId).ConfigureAwait(false); | ||
|
||
var scope = _serviceScopeFactory.CreateAsyncScope(); | ||
await using var _ = scope.ConfigureAwait(false); | ||
var timerProvider = scope.ServiceProvider.GetRequiredService<TimerProvider>(); | ||
|
||
return new Repeater(repeaterId, eventBus, version, _logger, timerProvider); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/SecTester.Repeater/Extensions/ServiceCollectionExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using SecTester.Core.Utils; | ||
using SecTester.Repeater.Api; | ||
|
||
namespace SecTester.Repeater.Extensions; | ||
|
||
public static class ServiceCollectionExtensions | ||
{ | ||
public static IServiceCollection AddSecTesterRepeater(this IServiceCollection collection) | ||
{ | ||
return AddSecTesterRepeater(collection, () => new RepeaterOptions()); | ||
} | ||
|
||
public static IServiceCollection AddSecTesterRepeater(this IServiceCollection collection, Func<RepeaterOptions> configure) | ||
{ | ||
collection | ||
.AddScoped<RepeaterFactory, DefaultRepeaterFactory>() | ||
.AddScoped(_ => configure()) | ||
.AddScoped<Repeaters, DefaultRepeaters>() | ||
.AddScoped<TimerProvider, SystemTimerProvider>(); | ||
|
||
return collection; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System.Threading.Tasks; | ||
|
||
namespace SecTester.Repeater; | ||
|
||
public interface RepeaterFactory | ||
{ | ||
public Task<Repeater> CreateRepeater(RepeaterOptions options); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,24 @@ | ||
using SecTester.Repeater.Runners; | ||
using System; | ||
|
||
namespace SecTester.Repeater; | ||
|
||
public record RepeaterOptions | ||
{ | ||
public string NamePrefix { get; init; } = "sectester"; | ||
private const int MaxPrefixLength = 44; | ||
private readonly string _namePrefix = "sectester"; | ||
|
||
public string NamePrefix | ||
{ | ||
get => _namePrefix; | ||
init | ||
{ | ||
if (string.IsNullOrEmpty(value) || value.Length > MaxPrefixLength) | ||
{ | ||
throw new ArgumentOutOfRangeException($"Name prefix must be less than {MaxPrefixLength} characters."); | ||
} | ||
_namePrefix = value; | ||
} | ||
} | ||
|
||
public string? Description { get; init; } | ||
public RequestRunnerOptions? RequestRunnerOptions { get; init; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
test/SecTester.Repeater.Tests/DefaultRepeaterFactoryTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
using SecTester.Repeater.Tests.Mocks; | ||
|
||
namespace SecTester.Repeater.Tests; | ||
|
||
public class DefaultRepeaterFactoryTests : IDisposable | ||
{ | ||
private const string Id = "99138d92-69db-44cb-952a-1cd9ec031e20"; | ||
private const string DefaultNamePrefix = "sectester"; | ||
private const string Hostname = "app.neuralegion.com"; | ||
|
||
private readonly IServiceScopeFactory _serviceScopeFactory = Substitute.For<IServiceScopeFactory>(); | ||
private readonly EventBusFactory _eventBusFactory = Substitute.For<EventBusFactory>(); | ||
private readonly Configuration _configuration = new(Hostname); | ||
|
||
private readonly Repeaters _repeaters = Substitute.For<Repeaters>(); | ||
private readonly MockLogger _logger = Substitute.For<MockLogger>(); | ||
private readonly TimerProvider _timerProvider = Substitute.For<TimerProvider>(); | ||
private readonly DefaultRepeaterFactory _sut; | ||
|
||
public DefaultRepeaterFactoryTests() | ||
{ | ||
// ADHOC: since GetRequiredService is part of extension we should explicitly mock an instance method | ||
_serviceScopeFactory.CreateAsyncScope().ServiceProvider.GetService(typeof(TimerProvider)).Returns(_timerProvider); | ||
_sut = new DefaultRepeaterFactory(_serviceScopeFactory, _repeaters, _eventBusFactory, _configuration, _logger); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_timerProvider.ClearSubstitute(); | ||
_serviceScopeFactory.ClearSubstitute(); | ||
_eventBusFactory.ClearSubstitute(); | ||
_repeaters.ClearSubstitute(); | ||
_logger.ClearSubstitute(); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
[Fact] | ||
public async Task CreateRepeater_CreatesRepeater() | ||
{ | ||
// arrange | ||
_repeaters.CreateRepeater(Arg.Is<string>(s => s.Contains(DefaultNamePrefix))) | ||
.Returns(Id); | ||
|
||
// act | ||
await using var repeater = await _sut.CreateRepeater(); | ||
|
||
// assert | ||
repeater.Should().BeOfType<Repeater>(); | ||
repeater.Should().BeEquivalentTo( | ||
new | ||
{ | ||
RepeaterId = Id | ||
}); | ||
} | ||
|
||
[Fact] | ||
public async Task CreateRepeater_GivenOptions_CreatesRepeater() | ||
{ | ||
// arrange | ||
var options = new RepeaterOptions | ||
{ | ||
NamePrefix = "foo", | ||
Description = "bar" | ||
}; | ||
_repeaters.CreateRepeater(Arg.Is<string>(s => s.Contains(options.NamePrefix)), options.Description) | ||
.Returns(Id); | ||
|
||
// act | ||
await using var repeater = await _sut.CreateRepeater(options); | ||
|
||
// assert | ||
repeater.Should().BeOfType<Repeater>(); | ||
repeater.Should().BeEquivalentTo( | ||
new | ||
{ | ||
RepeaterId = Id | ||
}); | ||
} | ||
} |
2 changes: 0 additions & 2 deletions
2
test/SecTester.Repeater.Tests/Extensions/SemaphoreSlimExtensionsTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
test/SecTester.Repeater.Tests/Extensions/ServiceCollectionExtensionsTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
namespace SecTester.Repeater.Tests.Extensions; | ||
|
||
public class ServiceCollectionExtensionsTests | ||
{ | ||
private readonly IServiceCollection _sut = Substitute.ForPartsOf<ServiceCollection>(); | ||
|
||
[Fact] | ||
public void AddSecTesterRepeater_RegistersRepeaterFactory() | ||
{ | ||
// act | ||
_sut.AddSecTesterRepeater(); | ||
|
||
// assert | ||
_sut.Received().AddScoped<RepeaterFactory, DefaultRepeaterFactory>(); | ||
} | ||
|
||
[Fact] | ||
public void AddSecTesterRepeater_RegistersRepeaters() | ||
{ | ||
// act | ||
_sut.AddSecTesterRepeater(); | ||
|
||
// assert | ||
_sut.Received().AddScoped<Repeaters, DefaultRepeaters>(); | ||
} | ||
|
||
[Fact] | ||
public void AddSecTesterRepeater_RegistersTimerProvider() | ||
{ | ||
// act | ||
_sut.AddSecTesterRepeater(); | ||
|
||
// assert | ||
_sut.Received().AddScoped<TimerProvider, SystemTimerProvider>(); | ||
} | ||
} |
Oops, something went wrong.