diff --git a/Directory.Build.props b/Directory.Build.props
index 5b684373..fc086139 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -128,25 +128,21 @@
- net9.0-android;
net10.0-android
- net9.0-ios;
net10.0-ios
- net9.0-maccatalyst;
net10.0-maccatalyst
- net9.0-macos;
net10.0-macos
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 6fa6c30b..ed985d4c 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -22,25 +22,26 @@
Condition=" '$(TargetFrameworkIdentifier)' == '.NETFramework' And $([MSBuild]::VersionEquals($(TargetFrameworkVersion), '4.6.2')) ">
-
-
-
+
+
+
-
+
-
+
-
+
+
@@ -60,19 +61,19 @@
-
-
-
+
+
+
-
+
-
+
@@ -80,7 +81,8 @@
-
+
+
@@ -92,8 +94,8 @@
-->
-
-
+
+
@@ -111,19 +113,19 @@
-
-
-
+
+
+
-
+
-
+
@@ -131,7 +133,8 @@
-
+
+
@@ -143,8 +146,8 @@
-->
-
-
+
+
@@ -166,12 +169,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
@@ -197,23 +200,24 @@
-
-
+
+
-
+
-
+
-
+
+
@@ -222,7 +226,7 @@
-->
-
+
@@ -239,23 +243,24 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
+
-
-
+
+
@@ -280,23 +285,23 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
+
@@ -380,23 +385,24 @@
-
+
-
+
-
+
-
+
+
diff --git a/WorkloadRollback.json b/WorkloadRollback.json
index 040477c7..d99071ba 100644
--- a/WorkloadRollback.json
+++ b/WorkloadRollback.json
@@ -1,18 +1,18 @@
{
- "microsoft.net.sdk.android": "36.1.43/10.0.100",
- "microsoft.net.sdk.ios": "26.5.10284/10.0.100",
- "microsoft.net.sdk.maccatalyst": "26.5.10284/10.0.100",
- "microsoft.net.sdk.macos": "26.5.10284/10.0.100",
+ "microsoft.net.sdk.android": "36.1.69/10.0.100",
+ "microsoft.net.sdk.ios": "26.5.10301/10.0.100",
+ "microsoft.net.sdk.maccatalyst": "26.5.10301/10.0.100",
+ "microsoft.net.sdk.macos": "26.5.10301/10.0.100",
"microsoft.net.sdk.maui": "10.0.20/10.0.100",
- "microsoft.net.sdk.tvos": "26.5.10284/10.0.100",
- "microsoft.net.workload.mono.toolchain.current": "10.0.110/10.0.100",
- "microsoft.net.workload.emscripten.current": "10.0.110/10.0.100",
- "microsoft.net.workload.emscripten.net6": "10.0.110/10.0.100",
- "microsoft.net.workload.emscripten.net7": "10.0.110/10.0.100",
- "microsoft.net.workload.emscripten.net8": "10.0.110/10.0.100",
- "microsoft.net.workload.emscripten.net9": "10.0.110/10.0.100",
- "microsoft.net.workload.mono.toolchain.net6": "10.0.110/10.0.100",
- "microsoft.net.workload.mono.toolchain.net7": "10.0.110/10.0.100",
- "microsoft.net.workload.mono.toolchain.net8": "10.0.110/10.0.100",
- "microsoft.net.workload.mono.toolchain.net9": "10.0.110/10.0.100"
+ "microsoft.net.sdk.tvos": "26.5.10301/10.0.100",
+ "microsoft.net.workload.mono.toolchain.current": "10.0.111/10.0.100",
+ "microsoft.net.workload.emscripten.current": "10.0.111/10.0.100",
+ "microsoft.net.workload.emscripten.net6": "10.0.111/10.0.100",
+ "microsoft.net.workload.emscripten.net7": "10.0.111/10.0.100",
+ "microsoft.net.workload.emscripten.net8": "10.0.111/10.0.100",
+ "microsoft.net.workload.emscripten.net9": "10.0.111/10.0.100",
+ "microsoft.net.workload.mono.toolchain.net6": "10.0.111/10.0.100",
+ "microsoft.net.workload.mono.toolchain.net7": "10.0.111/10.0.100",
+ "microsoft.net.workload.mono.toolchain.net8": "10.0.111/10.0.100",
+ "microsoft.net.workload.mono.toolchain.net9": "10.0.111/10.0.100"
}
diff --git a/global.json b/global.json
index 3b244ade..5c048ec0 100644
--- a/global.json
+++ b/global.json
@@ -1,17 +1,17 @@
{
"sdk": {
- "version": "10.0.302",
+ "version": "10.0.400",
"allowPrerelease": true,
"rollForward": "major"
},
"tools": {
- "dotnet": "10.0.302",
+ "dotnet": "10.0.400",
"runtimes": {
"aspnetcore": [
- "8.0.29",
- "9.0.18"
+ "8.0.30",
+ "9.0.19"
]
}
},
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 63106125..f39d2e2c 100644
--- a/sandbox/OpenIddict.Sandbox.AspNet.Client/OpenIddict.Sandbox.AspNet.Client.csproj
+++ b/sandbox/OpenIddict.Sandbox.AspNet.Client/OpenIddict.Sandbox.AspNet.Client.csproj
@@ -15,7 +15,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 f871dffe..49edf614 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj
@@ -12,7 +12,6 @@
-
@@ -26,6 +25,7 @@
+
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 b7311c4e..86138b1d 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj
@@ -15,7 +15,6 @@
-
@@ -29,6 +28,7 @@
+
diff --git a/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj b/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
index b3293c82..7e76d00c 100644
--- a/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
+++ b/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
@@ -18,6 +18,13 @@
+
+
+
+
diff --git a/src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs b/src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs
index 94966814..0cfd6fb2 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..83bb59e9 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 !NET10_0_OR_GREATER
+ // 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 98f69c6c..83ee8b6a 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 !NET10_0_OR_GREATER
///
/// 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 NET10_0_OR_GREATER
+ 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
{
@@ -88,7 +89,7 @@ public sealed class OpenIddictQuartzJob : IJob
// occurred while trying to prune the entities. In this case, add the inner exceptions to the collection.
catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception))
{
- exceptions ??= [];
+ exceptions ??= new List(capacity: exception.InnerExceptions.Count);
exceptions.AddRange(exception.InnerExceptions);
}
@@ -96,12 +97,12 @@ public sealed class OpenIddictQuartzJob : IJob
// to be re-thrown later (typically, at the very end of this job, as an AggregateException).
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
- exceptions ??= [];
+ exceptions ??= new List(capacity: 1);
exceptions.Add(exception);
}
}
- 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
{
@@ -133,7 +134,7 @@ public sealed class OpenIddictQuartzJob : IJob
// occurred while trying to prune the entities. In this case, add the inner exceptions to the collection.
catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception))
{
- exceptions ??= [];
+ exceptions ??= new List(capacity: exception.InnerExceptions.Count);
exceptions.AddRange(exception.InnerExceptions);
}
@@ -141,17 +142,17 @@ public sealed class OpenIddictQuartzJob : IJob
// to be re-thrown later (typically, at the very end of this job, as an AggregateException).
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
- exceptions ??= [];
+ exceptions ??= new List(capacity: 1);
exceptions.Add(exception);
}
}
- if (exceptions is not null)
+ if (exceptions is { Count: > 0 })
{
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 d72a54b3..41ba0681 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 NET10_0_OR_GREATER
Assert.Contains(services, service => service.ServiceType == typeof(OpenIddictQuartzJob) &&
service.ImplementationType == typeof(OpenIddictQuartzJob) &&
- service.Lifetime == ServiceLifetime.Transient);
+ 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 == ServiceLifetime.Transient);
+ service.ImplementationType == typeof(OpenIddictQuartzJob));
- Assert.Single(services, service => service.ServiceType == typeof(IConfigureOptions) &&
- service.ImplementationType == typeof(OpenIddictQuartzConfiguration) &&
- service.Lifetime == 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 05798bdf..d531d8e7 100644
--- a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzJobTests.cs
+++ b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzJobTests.cs
@@ -8,33 +8,36 @@ namespace OpenIddict.Quartz.Tests;
public class OpenIddictQuartzJobTests
{
+#if !NET10_0_OR_GREATER
[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 provider = Mock.Of(provider =>
- provider.GetService(typeof(IOpenIddictAuthorizationManager)) == Mock.Of() &&
- provider.GetService(typeof(IOpenIddictTokenManager)) == Mock.Of());
-
- 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 provider = Mock.Of(provider =>
+ provider.GetService(typeof(IOpenIddictAuthorizationManager)) == 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 job = new OpenIddictQuartzJob(Mock.Of(provider => provider.GetService(typeof(IServiceScopeFactory)) == factory));
// Act
await job.Execute(Mock.Of());
@@ -47,14 +50,21 @@ 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(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());
@@ -67,14 +77,21 @@ 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(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());
@@ -87,14 +104,22 @@ 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(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);
@@ -108,13 +133,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);
@@ -128,36 +161,50 @@ 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]
@@ -166,20 +213,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);
@@ -192,20 +246,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);
@@ -216,6 +277,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()));
@@ -223,12 +290,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);
@@ -259,6 +329,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(
@@ -268,12 +344,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);
@@ -306,38 +385,38 @@ 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());
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.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));
}
}