diff --git a/Directory.Packages.props b/Directory.Packages.props
index 532287a7..40909ed4 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -48,7 +48,8 @@
-
+
+
@@ -92,7 +93,7 @@
-
+
@@ -126,7 +127,7 @@
-
+
@@ -154,7 +155,6 @@
-
diff --git a/sandbox/OpenIddict.Sandbox.AspNet.Client/OpenIddict.Sandbox.AspNet.Client.csproj b/sandbox/OpenIddict.Sandbox.AspNet.Client/OpenIddict.Sandbox.AspNet.Client.csproj
index bf3c88ad..fd450a23 100644
--- a/sandbox/OpenIddict.Sandbox.AspNet.Client/OpenIddict.Sandbox.AspNet.Client.csproj
+++ b/sandbox/OpenIddict.Sandbox.AspNet.Client/OpenIddict.Sandbox.AspNet.Client.csproj
@@ -16,7 +16,6 @@
-
diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj
index 27545421..011b2a3f 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj
@@ -13,7 +13,6 @@
-
diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj
index 5ca4a091..057c0336 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj
@@ -16,7 +16,6 @@
-
diff --git a/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj b/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
index 550900d5..8cd60427 100644
--- a/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
+++ b/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
@@ -14,6 +14,10 @@
+
+
+
+
diff --git a/src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs b/src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs
index e71b7fc7..e6d87cd2 100644
--- a/src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs
+++ b/src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs
@@ -14,7 +14,7 @@ namespace OpenIddict.Quartz;
/// Contains the methods required to ensure that the OpenIddict Quartz.NET configuration is valid.
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
-public sealed class OpenIddictQuartzConfiguration : IConfigureOptions, IPostConfigureOptions
+public sealed class OpenIddictQuartzConfiguration : IPostConfigureOptions
{
private readonly IServiceProvider _provider;
@@ -25,31 +25,6 @@ public sealed class OpenIddictQuartzConfiguration : IConfigureOptions _provider = provider ?? throw new ArgumentNullException(nameof(provider));
- ///
- public void Configure(QuartzOptions options)
- {
- ArgumentNullException.ThrowIfNull(options);
-
- options.AddJob(builder =>
- {
- builder.StoreDurably()
- .WithIdentity(OpenIddictQuartzJob.Identity)
- .WithDescription(SR.GetResourceString(SR.ID8001));
- });
-
- options.AddTrigger(builder =>
- {
- // Note: this trigger uses a quite long interval (1 hour), which means it may be potentially never
- // reached if the application is shut down or recycled. As such, this trigger is set up to fire
- // between 1 and 10 minutes after the application starts to ensure the job is executed at least once.
- builder.ForJob(OpenIddictQuartzJob.Identity)
- .WithIdentity(SR.GetResourceString(SR.ID8004), SR.GetResourceString(SR.ID8005))
- .WithSimpleSchedule(options => options.WithIntervalInHours(1).RepeatForever())
- .WithDescription(SR.GetResourceString(SR.ID8002))
- .StartAt(DateBuilder.FutureDate(new Random().Next(1, 10), IntervalUnit.Minute));
- });
- }
-
///
public void PostConfigure(string? name, OpenIddictQuartzOptions options)
{
diff --git a/src/OpenIddict.Quartz/OpenIddictQuartzExtensions.cs b/src/OpenIddict.Quartz/OpenIddictQuartzExtensions.cs
index 628cd50b..8a35970d 100644
--- a/src/OpenIddict.Quartz/OpenIddictQuartzExtensions.cs
+++ b/src/OpenIddict.Quartz/OpenIddictQuartzExtensions.cs
@@ -25,16 +25,38 @@ public static class OpenIddictQuartzExtensions
{
ArgumentNullException.ThrowIfNull(builder);
- builder.Services.AddQuartz();
+ // Note: the AddQuartz() method MUST only be called once to avoid adding multiple jobs and triggers.
+ if (!builder.Services.Any(static descriptor => descriptor.ServiceType == typeof(OpenIddictQuartzJob)))
+ {
+ builder.Services.AddQuartz(options =>
+ {
+ options.AddJob(static builder =>
+ {
+ builder.StoreDurably()
+ .WithIdentity(OpenIddictQuartzJob.Identity)
+ .WithDescription(SR.GetResourceString(SR.ID8001));
+ });
- // The OpenIddict job is registered as a service to allow
- // Quartz.NET's DI integration to resolve it from the DI.
- builder.Services.TryAddTransient();
+ options.AddTrigger(static builder =>
+ {
+ // Note: this trigger uses a quite long interval (1 hour), which means it may be potentially never
+ // reached if the application is shut down or recycled. As such, this trigger is set up to fire
+ // between 1 and 10 minutes after the application starts to ensure the job is executed at least once.
+ builder.ForJob(OpenIddictQuartzJob.Identity)
+ .WithIdentity(SR.GetResourceString(SR.ID8004), SR.GetResourceString(SR.ID8005))
+ .WithSimpleSchedule(options => options.WithInterval(TimeSpan.FromHours(1)).RepeatForever())
+ .WithDescription(SR.GetResourceString(SR.ID8002))
+ .StartAt(TimeProvider.System.GetUtcNow() + TimeSpan.FromMinutes(new Random().Next(1, 10)));
+ });
+ });
+ }
- // Note: TryAddEnumerable() is used here to ensure the initializers are registered only once.
- builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
- IConfigureOptions, OpenIddictQuartzConfiguration>());
+#if !NET
+ // Note: unlike Quartz.NET 4.0+, Quartz.NET 3.x doesn't automatically register the job as a service.
+ builder.Services.TryAddTransient();
+#endif
+ // Note: TryAddEnumerable() is used here to ensure the initializer is registered only once.
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
IPostConfigureOptions, OpenIddictQuartzConfiguration>());
diff --git a/src/OpenIddict.Quartz/OpenIddictQuartzJob.cs b/src/OpenIddict.Quartz/OpenIddictQuartzJob.cs
index 4b4277fb..c9e305ac 100644
--- a/src/OpenIddict.Quartz/OpenIddictQuartzJob.cs
+++ b/src/OpenIddict.Quartz/OpenIddictQuartzJob.cs
@@ -16,24 +16,21 @@ namespace OpenIddict.Quartz;
[DisallowConcurrentExecution, EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictQuartzJob : IJob
{
- private readonly IOptionsMonitor _options;
private readonly IServiceProvider _provider;
+#if !NET
///
/// Creates a new instance of the class.
///
public OpenIddictQuartzJob() => throw new InvalidOperationException(SR.GetResourceString(SR.ID0082));
+#endif
///
/// Creates a new instance of the class.
///
- /// The OpenIddict Quartz.NET options.
/// The service provider.
- public OpenIddictQuartzJob(IOptionsMonitor options, IServiceProvider provider)
- {
- _options = options ?? throw new ArgumentNullException(nameof(options));
- _provider = provider ?? throw new ArgumentNullException(nameof(provider));
- }
+ public OpenIddictQuartzJob(IServiceProvider provider)
+ => _provider = provider ?? throw new ArgumentNullException(nameof(provider));
///
/// Gets the default identity assigned to this job.
@@ -43,20 +40,24 @@ public sealed class OpenIddictQuartzJob : IJob
group: SR.GetResourceString(SR.ID8005));
///
+#if NET
+ public async ValueTask Execute(IJobExecutionContext context, CancellationToken cancellationToken = default)
+#else
public async Task Execute(IJobExecutionContext context)
+#endif
{
ArgumentNullException.ThrowIfNull(context);
List? exceptions = null;
- // Note: this job is registered as a transient service. As such, it cannot directly depend on scoped services
- // like the core managers. To work around this limitation, a scope is manually created for each invocation.
await using var scope = _provider.CreateAsyncScope();
+ var options = scope.ServiceProvider.GetRequiredService>().CurrentValue;
+
// Important: since authorizations that still have tokens attached are never
// pruned, the tokens MUST be deleted before deleting the authorizations.
- if (!_options.CurrentValue.DisableTokenPruning)
+ if (!options.DisableTokenPruning)
{
var manager = scope.ServiceProvider.GetService()
?? throw new JobExecutionException(new InvalidOperationException(SR.GetResourceString(SR.ID0278)))
@@ -66,7 +67,7 @@ public sealed class OpenIddictQuartzJob : IJob
UnscheduleFiringTrigger = true
};
- var threshold = _options.CurrentValue.TimeProvider.GetUtcNow() - _options.CurrentValue.MinimumTokenLifespan;
+ var threshold = options.TimeProvider.GetUtcNow() - options.MinimumTokenLifespan;
try
{
@@ -101,7 +102,7 @@ public sealed class OpenIddictQuartzJob : IJob
}
}
- if (!_options.CurrentValue.DisableAuthorizationPruning)
+ if (!options.DisableAuthorizationPruning)
{
var manager = scope.ServiceProvider.GetService()
?? throw new JobExecutionException(new InvalidOperationException(SR.GetResourceString(SR.ID0278)))
@@ -111,7 +112,7 @@ public sealed class OpenIddictQuartzJob : IJob
UnscheduleFiringTrigger = true
};
- var threshold = _options.CurrentValue.TimeProvider.GetUtcNow() - _options.CurrentValue.MinimumAuthorizationLifespan;
+ var threshold = options.TimeProvider.GetUtcNow() - options.MinimumAuthorizationLifespan;
try
{
@@ -149,7 +150,7 @@ public sealed class OpenIddictQuartzJob : IJob
// Important: since sessions that still have tokens attached are never
// pruned, the tokens MUST be deleted before deleting the sessions.
- if (!_options.CurrentValue.DisableSessionPruning)
+ if (!options.DisableSessionPruning)
{
var manager = scope.ServiceProvider.GetService()
?? throw new JobExecutionException(new InvalidOperationException(SR.GetResourceString(SR.ID0278)))
@@ -159,7 +160,7 @@ public sealed class OpenIddictQuartzJob : IJob
UnscheduleFiringTrigger = true
};
- var threshold = _options.CurrentValue.TimeProvider.GetUtcNow() - _options.CurrentValue.MinimumSessionLifespan;
+ var threshold = options.TimeProvider.GetUtcNow() - options.MinimumSessionLifespan;
try
{
@@ -199,7 +200,7 @@ public sealed class OpenIddictQuartzJob : IJob
throw new JobExecutionException(new AggregateException(exceptions))
{
// Only refire the job if the maximum refire count set in the options wasn't reached.
- RefireImmediately = context.RefireCount < _options.CurrentValue.MaximumRefireCount
+ RefireImmediately = context.RefireCount < options.MaximumRefireCount
};
}
}
diff --git a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzConfigurationTests.cs b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzConfigurationTests.cs
deleted file mode 100644
index 9f654c4c..00000000
--- a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzConfigurationTests.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-using Quartz;
-using Xunit;
-
-namespace OpenIddict.Quartz.Tests;
-
-public class OpenIddictQuartzConfigurationTests
-{
- [Fact]
- public void UseQuartz_RegistersJobDetails()
- {
- // Arrange
- var options = new QuartzOptions();
- var configuration = new OpenIddictQuartzConfiguration(new ServiceCollection().BuildServiceProvider());
-
- // Act
- configuration.Configure(options);
-
- // Assert
- Assert.Single(options.JobDetails);
- Assert.Equal(OpenIddictQuartzJob.Identity, options.JobDetails[0].Key);
- Assert.Equal(SR.GetResourceString(SR.ID8003), options.JobDetails[0].Key.Name);
- Assert.Equal(SR.GetResourceString(SR.ID8005), options.JobDetails[0].Key.Group);
- Assert.Equal(SR.GetResourceString(SR.ID8001), options.JobDetails[0].Description);
- }
-
- [Fact]
- public void UseQuartz_RegistersTriggerDetails()
- {
- // Arrange
- var options = new QuartzOptions();
- var configuration = new OpenIddictQuartzConfiguration(new ServiceCollection().BuildServiceProvider());
-
- // Act
- configuration.Configure(options);
-
- // Assert
- Assert.Single(options.Triggers);
- Assert.Equal(OpenIddictQuartzJob.Identity, options.Triggers[0].JobKey);
- Assert.Equal(SR.GetResourceString(SR.ID8004), options.Triggers[0].Key.Name);
- Assert.Equal(SR.GetResourceString(SR.ID8005), options.Triggers[0].Key.Group);
- Assert.Equal(SR.GetResourceString(SR.ID8002), options.Triggers[0].Description);
- }
-}
diff --git a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzExtensionsTests.cs b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzExtensionsTests.cs
index 41e0b540..cbf5b173 100644
--- a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzExtensionsTests.cs
+++ b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzExtensionsTests.cs
@@ -1,6 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
-using Quartz;
using Xunit;
namespace OpenIddict.Quartz.Tests;
@@ -43,9 +42,15 @@ public class OpenIddictQuartzExtensionsTests
builder.UseQuartz();
// Assert
+#if NET
+ Assert.Contains(services, service => service.ServiceType == typeof(OpenIddictQuartzJob) &&
+ service.ImplementationType == typeof(OpenIddictQuartzJob) &&
+ service.Lifetime is ServiceLifetime.Scoped);
+#else
Assert.Contains(services, service => service.ServiceType == typeof(OpenIddictQuartzJob) &&
service.ImplementationType == typeof(OpenIddictQuartzJob) &&
service.Lifetime is ServiceLifetime.Transient);
+#endif
}
[Fact]
@@ -62,11 +67,9 @@ public class OpenIddictQuartzExtensionsTests
// Assert
Assert.Single(services, service => service.ServiceType == typeof(OpenIddictQuartzJob) &&
- service.ImplementationType == typeof(OpenIddictQuartzJob) &&
- service.Lifetime is ServiceLifetime.Transient);
+ service.ImplementationType == typeof(OpenIddictQuartzJob));
- Assert.Single(services, service => service.ServiceType == typeof(IConfigureOptions) &&
- service.ImplementationType == typeof(OpenIddictQuartzConfiguration) &&
- service.Lifetime is ServiceLifetime.Singleton);
+ Assert.Single(services, service => service.ServiceType == typeof(IPostConfigureOptions) &&
+ service.ImplementationType == typeof(OpenIddictQuartzConfiguration));
}
}
diff --git a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzJobTests.cs b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzJobTests.cs
index da5bbae2..7c93830b 100644
--- a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzJobTests.cs
+++ b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzJobTests.cs
@@ -8,34 +8,37 @@ namespace OpenIddict.Quartz.Tests;
public class OpenIddictQuartzJobTests
{
+#if !NET
[Fact]
- public void Constructor_ThrowsAnException()
+ public void Constructor_ThrowsAnExceptionWhenServiceProviderCannotBeResolved()
{
// Arrange, act and assert
var exception = Assert.Throws(() => new OpenIddictQuartzJob());
Assert.Equal(SR.GetResourceString(SR.ID0082), exception.Message);
}
+#endif
[Fact]
public async Task Execute_UsesServiceScope()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == Mock.Of() &&
provider.GetService(typeof(IOpenIddictSessionManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of());
+ provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of() &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var scope = Mock.Of(scope => scope.ServiceProvider == provider);
var factory = Mock.Of(factory => factory.CreateScope() == scope);
- var monitor = Mock.Of>(
- monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
- {
- TimeProvider = TimeProvider.System
- });
- var job = new OpenIddictQuartzJob(monitor,
- Mock.Of(provider => provider.GetService(typeof(IServiceScopeFactory)) == factory));
+ var job = new OpenIddictQuartzJob(Mock.Of(provider => provider.GetService(typeof(IServiceScopeFactory)) == factory));
// Act
await job.Execute(Mock.Of());
@@ -48,15 +51,22 @@ public class OpenIddictQuartzJobTests
public async Task Execute_IgnoresPruningWhenTokenPruningIsDisabled()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ DisableTokenPruning = true,
+ TimeProvider = TimeProvider.System
+ });
var manager = new Mock();
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == Mock.Of() &&
provider.GetService(typeof(IOpenIddictSessionManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == manager.Object);
+ provider.GetService(typeof(IOpenIddictTokenManager)) == manager.Object &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
- var job = CreateJob(provider, options => options.DisableTokenPruning = true);
+ var job = CreateJob(provider);
// Act
await job.Execute(Mock.Of());
@@ -69,15 +79,22 @@ public class OpenIddictQuartzJobTests
public async Task Execute_IgnoresPruningWhenAuthorizationPruningIsDisabled()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ DisableAuthorizationPruning = true,
+ TimeProvider = TimeProvider.System
+ });
var manager = new Mock();
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == manager.Object &&
provider.GetService(typeof(IOpenIddictSessionManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of());
+ provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of() &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
- var job = CreateJob(provider, options => options.DisableAuthorizationPruning = true);
+ var job = CreateJob(provider);
// Act
await job.Execute(Mock.Of());
@@ -90,15 +107,22 @@ public class OpenIddictQuartzJobTests
public async Task Execute_IgnoresPruningWhenSessionPruningIsDisabled()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ DisableSessionPruning = true,
+ TimeProvider = TimeProvider.System
+ });
var manager = new Mock();
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == Mock.Of() &&
provider.GetService(typeof(IOpenIddictSessionManager)) == manager.Object &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of());
+ provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of() &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
- var job = CreateJob(provider, options => options.DisableSessionPruning = true);
+ var job = CreateJob(provider);
// Act
await job.Execute(Mock.Of());
@@ -111,15 +135,23 @@ public class OpenIddictQuartzJobTests
public async Task Execute_UnschedulesTriggersWhenTokenManagerIsMissing()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == Mock.Of() &&
provider.GetService(typeof(IOpenIddictSessionManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == null);
+ provider.GetService(typeof(IOpenIddictTokenManager)) == null &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var job = CreateJob(provider);
// Act and assert
- var exception = await Assert.ThrowsAsync(() => job.Execute(Mock.Of()));
+ var exception = await Assert.ThrowsAsync(async () =>
+ await job.Execute(Mock.Of()));
Assert.False(exception.RefireImmediately);
Assert.True(exception.UnscheduleAllTriggers);
@@ -133,13 +165,21 @@ public class OpenIddictQuartzJobTests
public async Task Execute_UnschedulesTriggersWhenAuthorizationManagerIsMissing()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var provider = Mock.Of(provider =>
- provider.GetService(typeof(IOpenIddictAuthorizationManager)) == null);
+ provider.GetService(typeof(IOpenIddictAuthorizationManager)) == null &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var job = CreateJob(provider);
// Act and assert
- var exception = await Assert.ThrowsAsync(() => job.Execute(Mock.Of()));
+ var exception = await Assert.ThrowsAsync(async () =>
+ await job.Execute(Mock.Of()));
Assert.False(exception.RefireImmediately);
Assert.True(exception.UnscheduleAllTriggers);
@@ -153,13 +193,21 @@ public class OpenIddictQuartzJobTests
public async Task Execute_UnschedulesTriggersWhenSessionManagerIsMissing()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var provider = Mock.Of(provider =>
- provider.GetService(typeof(IOpenIddictSessionManager)) == null);
+ provider.GetService(typeof(IOpenIddictSessionManager)) == null &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var job = CreateJob(provider);
// Act and assert
- var exception = await Assert.ThrowsAsync(() => job.Execute(Mock.Of()));
+ var exception = await Assert.ThrowsAsync(async () =>
+ await job.Execute(Mock.Of()));
Assert.False(exception.RefireImmediately);
Assert.True(exception.UnscheduleAllTriggers);
@@ -173,42 +221,62 @@ public class OpenIddictQuartzJobTests
public async Task Execute_RethrowsOutOfMemoryExceptionsThrownDuringTokenPruning()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var manager = new Mock();
manager.Setup(manager => manager.PruneAsync(It.IsAny(), It.IsAny()))
.Throws(new OutOfMemoryException());
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == manager.Object);
+ provider.GetService(typeof(IOpenIddictTokenManager)) == manager.Object &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var job = CreateJob(provider);
// Act and assert
- await Assert.ThrowsAsync(() => job.Execute(Mock.Of()));
+ await Assert.ThrowsAsync(async () => await job.Execute(Mock.Of()));
}
[Fact]
public async Task Execute_RethrowsOutOfMemoryExceptionsThrownDuringAuthorizationPruning()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var manager = new Mock();
manager.Setup(manager => manager.PruneAsync(It.IsAny(), It.IsAny()))
.Throws(new OutOfMemoryException());
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == manager.Object &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of());
+ provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of() &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var job = CreateJob(provider);
// Act and assert
- await Assert.ThrowsAsync(() => job.Execute(Mock.Of()));
+ await Assert.ThrowsAsync(async () => await job.Execute(Mock.Of()));
}
[Fact]
public async Task Execute_RethrowsOutOfMemoryExceptionsThrownDuringSessionPruning()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var manager = new Mock();
manager.Setup(manager => manager.PruneAsync(It.IsAny(), It.IsAny()))
.Throws(new OutOfMemoryException());
@@ -216,12 +284,13 @@ public class OpenIddictQuartzJobTests
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == Mock.Of() &&
provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictSessionManager)) == manager.Object);
+ provider.GetService(typeof(IOpenIddictSessionManager)) == manager.Object &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var job = CreateJob(provider);
// Act and assert
- await Assert.ThrowsAsync(() => job.Execute(Mock.Of()));
+ await Assert.ThrowsAsync(async () => await job.Execute(Mock.Of()));
}
[Fact]
@@ -230,20 +299,27 @@ public class OpenIddictQuartzJobTests
// Arrange
var token = new CancellationToken(canceled: true);
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var manager = new Mock();
manager.Setup(manager => manager.PruneAsync(It.IsAny(), It.IsAny()))
.Throws(new OperationCanceledException(token));
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == manager.Object);
+ provider.GetService(typeof(IOpenIddictTokenManager)) == manager.Object &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var context = Mock.Of(context => context.CancellationToken == token);
var job = CreateJob(provider);
// Act and assert
- var exception = await Assert.ThrowsAsync(() => job.Execute(context));
+ var exception = await Assert.ThrowsAsync(async () => await job.Execute(context));
Assert.False(exception.RefireImmediately);
@@ -256,20 +332,27 @@ public class OpenIddictQuartzJobTests
// Arrange
var token = new CancellationToken(canceled: true);
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var manager = new Mock();
manager.Setup(manager => manager.PruneAsync(It.IsAny(), It.IsAny()))
.Throws(new OperationCanceledException(token));
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == manager.Object &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of());
+ provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of() &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var context = Mock.Of(context => context.CancellationToken == token);
var job = CreateJob(provider);
// Act and assert
- var exception = await Assert.ThrowsAsync(() => job.Execute(context));
+ var exception = await Assert.ThrowsAsync(async () => await job.Execute(context));
Assert.False(exception.RefireImmediately);
@@ -282,6 +365,12 @@ public class OpenIddictQuartzJobTests
// Arrange
var token = new CancellationToken(canceled: true);
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var manager = new Mock();
manager.Setup(manager => manager.PruneAsync(It.IsAny(), It.IsAny()))
.Throws(new OperationCanceledException(token));
@@ -289,14 +378,15 @@ public class OpenIddictQuartzJobTests
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == Mock.Of() &&
provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictSessionManager)) == manager.Object);
+ provider.GetService(typeof(IOpenIddictSessionManager)) == manager.Object &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var context = Mock.Of(context => context.CancellationToken == token);
var job = CreateJob(provider);
// Act and assert
- var exception = await Assert.ThrowsAsync(() => job.Execute(context));
+ var exception = await Assert.ThrowsAsync(async () => await job.Execute(context));
Assert.False(exception.RefireImmediately);
@@ -307,6 +397,12 @@ public class OpenIddictQuartzJobTests
public async Task Execute_AllowsRefiringWhenExceptionsAreThrown()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var provider = new Mock();
provider.Setup(provider => provider.GetService(typeof(IOpenIddictAuthorizationManager)))
.Returns(CreateAuthorizationManager(new ApplicationException()));
@@ -317,12 +413,15 @@ public class OpenIddictQuartzJobTests
provider.Setup(provider => provider.GetService(typeof(IOpenIddictTokenManager)))
.Returns(CreateTokenManager(new ApplicationException()));
+ provider.Setup(provider => provider.GetService(typeof(IOptionsMonitor)))
+ .Returns(monitor);
+
var context = Mock.Of(context => context.RefireCount == 0);
var job = CreateJob(provider.Object);
// Act and assert
- var exception = await Assert.ThrowsAsync(() => job.Execute(context));
+ var exception = await Assert.ThrowsAsync(async () => await job.Execute(context));
Assert.True(exception.RefireImmediately);
Assert.IsType(exception.InnerException);
@@ -363,6 +462,12 @@ public class OpenIddictQuartzJobTests
public async Task Execute_AllowsRefiringWhenAggregateExceptionsAreThrown()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ TimeProvider = TimeProvider.System
+ });
+
var provider = new Mock();
provider.Setup(provider => provider.GetService(typeof(IOpenIddictAuthorizationManager)))
.Returns(CreateAuthorizationManager(new AggregateException(
@@ -376,12 +481,15 @@ public class OpenIddictQuartzJobTests
.Returns(CreateTokenManager(new AggregateException(
new InvalidOperationException(), new ApplicationException())));
+ provider.Setup(provider => provider.GetService(typeof(IOptionsMonitor)))
+ .Returns(monitor);
+
var context = Mock.Of(context => context.RefireCount == 0);
var job = CreateJob(provider.Object);
// Act and assert
- var exception = await Assert.ThrowsAsync(() => job.Execute(context));
+ var exception = await Assert.ThrowsAsync(async () => await job.Execute(context));
Assert.True(exception.RefireImmediately);
Assert.IsType(exception.InnerException);
@@ -425,6 +533,13 @@ public class OpenIddictQuartzJobTests
public async Task Execute_DisallowsRefiringWhenMaximumRefireCountIsReached()
{
// Arrange
+ var monitor = Mock.Of>(
+ monitor => monitor.CurrentValue == new OpenIddictQuartzOptions
+ {
+ MaximumRefireCount = 5,
+ TimeProvider = TimeProvider.System
+ });
+
var manager = new Mock();
manager.Setup(manager => manager.PruneAsync(It.IsAny(), It.IsAny()))
.Throws(new ApplicationException());
@@ -432,32 +547,25 @@ public class OpenIddictQuartzJobTests
var provider = Mock.Of(provider =>
provider.GetService(typeof(IOpenIddictAuthorizationManager)) == manager.Object &&
provider.GetService(typeof(IOpenIddictSessionManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of());
+ provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of() &&
+ provider.GetService(typeof(IOptionsMonitor)) == monitor);
var context = Mock.Of(context => context.RefireCount == 5);
- var job = CreateJob(provider, options => options.MaximumRefireCount = 5);
+ var job = CreateJob(provider);
// Act and assert
- var exception = await Assert.ThrowsAsync(() => job.Execute(context));
+ var exception = await Assert.ThrowsAsync(async () => await job.Execute(context));
Assert.False(exception.RefireImmediately);
}
- private static OpenIddictQuartzJob CreateJob(IServiceProvider provider, Action? configuration = null)
+ private static OpenIddictQuartzJob CreateJob(IServiceProvider provider)
{
var scope = Mock.Of(scope => scope.ServiceProvider == provider);
var factory = Mock.Of(factory => factory.CreateScope() == scope);
- var options = new OpenIddictQuartzOptions
- {
- TimeProvider = TimeProvider.System
- };
-
- configuration?.Invoke(options);
-
- var monitor = Mock.Of>(monitor => monitor.CurrentValue == options);
- return new OpenIddictQuartzJob(monitor,
- Mock.Of(provider => provider.GetService(typeof(IServiceScopeFactory)) == factory));
+ return new OpenIddictQuartzJob(Mock.Of(provider =>
+ provider.GetService(typeof(IServiceScopeFactory)) == factory));
}
}