From ecc25d5babdd1849e1eaf9e536471ad6e6b3be56 Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Tue, 21 Oct 2025 10:13:22 -0700 Subject: [PATCH 1/3] Address compiler warnings, upgrade test and samples to net8 --- .vscode/tasks.json | 2 +- Directory.Packages.props | 2 +- .../AzureFunctionsApp.csproj | 2 +- samples/ScheduleWebApp/ScheduleWebApp.csproj | 2 +- samples/WebAPI/WebAPI.csproj | 2 +- .../DurableTaskClientBuilderExtensions.cs | 2 +- .../AzureManaged/DurableTaskVersionUtil.cs | 4 +- .../DurableTaskSchedulerWorkerOptions.cs | 1 + src/Worker/Core/DurableTaskWorkerOptions.cs | 3 +- src/Worker/Core/IOrchestrationFilter.cs | 2 +- .../Core/Shims/TaskOrchestrationShim.cs | 3 +- .../Grpc/GrpcDurableTaskWorker.Processor.cs | 194 ++++++----- src/Worker/Grpc/GrpcDurableTaskWorker.cs | 5 + .../Abstractions.Tests.csproj | 2 +- test/Analyzers.Tests/Analyzers.Tests.csproj | 2 +- test/Benchmarks/Benchmarks.csproj | 2 +- .../Client.AzureManaged.Tests.csproj | 10 +- ...rableTaskSchedulerClientExtensionsTests.cs | 4 +- test/Client/Core.Tests/Client.Tests.csproj | 2 +- .../DefaultDurableTaskClientProviderTests.cs | 8 +- .../Grpc.Tests/Client.Grpc.Tests.csproj | 2 +- ...rchestrationServiceClientShim.Tests.csproj | 2 +- .../ShimDurableTaskClientTests.cs | 2 +- test/Generators.Tests/AzureFunctionsTests.cs | 322 ------------------ .../Generators.Tests/ClassBasedSyntaxTests.cs | 270 --------------- test/Generators.Tests/Generators.Tests.csproj | 2 +- .../Grpc.IntegrationTests.csproj | 2 +- .../OrchestrationErrorHandling.cs | 2 + .../Client/DefaultScheduleClientTests.cs | 4 +- .../Client/DefaultScheduledTaskClientTests.cs | 6 +- .../Models/ScheduleCreationOptionsTests.cs | 4 +- .../ScheduledTasks.Tests.csproj | 10 +- .../Shared.AzureManaged.Tests.csproj | 2 +- test/TestHelpers/Logging/TestLogger.cs | 9 +- test/TestHelpers/TestHelpers.csproj | 2 +- ...rableTaskSchedulerWorkerExtensionsTests.cs | 4 +- .../Worker.AzureManaged.Tests.csproj | 3 +- test/Worker/Core.Tests/Worker.Tests.csproj | 2 +- .../GrpcOrchestrationRunnerTests.cs | 2 +- .../RunBackgroundTaskLoggingTests.cs | 17 +- .../Grpc.Tests/Worker.Grpc.Tests.csproj | 2 +- 41 files changed, 174 insertions(+), 751 deletions(-) delete mode 100644 test/Generators.Tests/AzureFunctionsTests.cs delete mode 100644 test/Generators.Tests/ClassBasedSyntaxTests.cs diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f7dbaae02..b1dbbb64a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -38,7 +38,7 @@ "type": "func", "dependsOn": "build (AzureFunctionsApp)", "options": { - "cwd": "${workspaceFolder}/out/samples/bin/Debug/AzureFunctionsApp/net6.0" + "cwd": "${workspaceFolder}/out/samples/bin/Debug/AzureFunctionsApp/net8.0" }, "command": "host start", "isBackground": true, diff --git a/Directory.Packages.props b/Directory.Packages.props index a0a48e71d..2b42e9373 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -46,9 +46,9 @@ + - diff --git a/samples/AzureFunctionsApp/AzureFunctionsApp.csproj b/samples/AzureFunctionsApp/AzureFunctionsApp.csproj index 1e56f9fd7..100aa1c71 100644 --- a/samples/AzureFunctionsApp/AzureFunctionsApp.csproj +++ b/samples/AzureFunctionsApp/AzureFunctionsApp.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 v4 Exe enable diff --git a/samples/ScheduleWebApp/ScheduleWebApp.csproj b/samples/ScheduleWebApp/ScheduleWebApp.csproj index 8206fa42e..b92b74e93 100644 --- a/samples/ScheduleWebApp/ScheduleWebApp.csproj +++ b/samples/ScheduleWebApp/ScheduleWebApp.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 enable enable true diff --git a/samples/WebAPI/WebAPI.csproj b/samples/WebAPI/WebAPI.csproj index 2ee98470a..67cb59248 100644 --- a/samples/WebAPI/WebAPI.csproj +++ b/samples/WebAPI/WebAPI.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 enable enable true diff --git a/src/Client/Core/DependencyInjection/DurableTaskClientBuilderExtensions.cs b/src/Client/Core/DependencyInjection/DurableTaskClientBuilderExtensions.cs index 5c8547592..48d1a51ca 100644 --- a/src/Client/Core/DependencyInjection/DurableTaskClientBuilderExtensions.cs +++ b/src/Client/Core/DependencyInjection/DurableTaskClientBuilderExtensions.cs @@ -80,7 +80,7 @@ public static IDurableTaskClientBuilder UseBuildTarget(this I where TTarget : DurableTaskClient where TOptions : DurableTaskClientOptions { - builder.UseBuildTarget(typeof(TTarget)); + builder.UseBuildTarget(); builder.Services.AddOptions(builder.Name) .PostConfigure>((options, baseOptions) => { diff --git a/src/Shared/AzureManaged/DurableTaskVersionUtil.cs b/src/Shared/AzureManaged/DurableTaskVersionUtil.cs index 7ad3bc47c..c2ea1b171 100644 --- a/src/Shared/AzureManaged/DurableTaskVersionUtil.cs +++ b/src/Shared/AzureManaged/DurableTaskVersionUtil.cs @@ -18,7 +18,7 @@ public static class DurableTaskUserAgentUtil /// /// The version of the SDK used in the user agent string. /// - static readonly string PackageVersion = FileVersionInfo.GetVersionInfo(typeof(DurableTaskUserAgentUtil).Assembly.Location).FileVersion; + static readonly string? PackageVersion = FileVersionInfo.GetVersionInfo(typeof(DurableTaskUserAgentUtil).Assembly.Location).FileVersion; /// /// Generates the user agent string for the Durable Task SDK based on a fixed name, the package version, and the caller type. @@ -29,4 +29,4 @@ public static string GetUserAgent(string callerType) { return $"{SdkName}/{PackageVersion?.ToString() ?? "unknown"} ({callerType})"; } -} \ No newline at end of file +} diff --git a/src/Worker/AzureManaged/DurableTaskSchedulerWorkerOptions.cs b/src/Worker/AzureManaged/DurableTaskSchedulerWorkerOptions.cs index de2b75d4b..8f360174d 100644 --- a/src/Worker/AzureManaged/DurableTaskSchedulerWorkerOptions.cs +++ b/src/Worker/AzureManaged/DurableTaskSchedulerWorkerOptions.cs @@ -103,6 +103,7 @@ this.Credential is not null async (context, metadata) => { metadata.Add("taskhub", taskHubName); + // Add user agent header with durabletask-dotnet and DLL version from util metadata.Add("x-user-agent", $"{DurableTaskUserAgentUtil.GetUserAgent(nameof(DurableTaskWorker))}"); metadata.Add("workerid", this.WorkerId); diff --git a/src/Worker/Core/DurableTaskWorkerOptions.cs b/src/Worker/Core/DurableTaskWorkerOptions.cs index 703bbbd4d..47ccfab5d 100644 --- a/src/Worker/Core/DurableTaskWorkerOptions.cs +++ b/src/Worker/Core/DurableTaskWorkerOptions.cs @@ -162,7 +162,6 @@ public DataConverter DataConverter /// internal bool DataConverterExplicitlySet { get; private set; } - /// /// Applies these option values to another. /// @@ -176,7 +175,9 @@ internal void ApplyTo(DurableTaskWorkerOptions other) other.MaximumTimerInterval = this.MaximumTimerInterval; other.EnableEntitySupport = this.EnableEntitySupport; other.Versioning = this.Versioning; +#pragma warning disable CS0618 // Type or member is obsolete other.OrchestrationFilter = this.OrchestrationFilter; +#pragma warning restore CS0618 // Type or member is obsolete } } diff --git a/src/Worker/Core/IOrchestrationFilter.cs b/src/Worker/Core/IOrchestrationFilter.cs index 99520d24e..3e3cffd8d 100644 --- a/src/Worker/Core/IOrchestrationFilter.cs +++ b/src/Worker/Core/IOrchestrationFilter.cs @@ -14,7 +14,7 @@ public interface IOrchestrationFilter /// /// The information on the orchestration to validate. /// The cancellation token for the request to timeout. - /// true if the orchestration is valid false otherwise. + /// true if the orchestration is valid; false otherwise. ValueTask IsOrchestrationValidAsync(OrchestrationFilterParameters info, CancellationToken cancellationToken = default); } diff --git a/src/Worker/Core/Shims/TaskOrchestrationShim.cs b/src/Worker/Core/Shims/TaskOrchestrationShim.cs index eb7a179be..610bc705e 100644 --- a/src/Worker/Core/Shims/TaskOrchestrationShim.cs +++ b/src/Worker/Core/Shims/TaskOrchestrationShim.cs @@ -95,7 +95,8 @@ public TaskOrchestrationShim( // failure details are correctly propagated. throw new CoreTaskFailedException(e.Message, e.InnerException) { - FailureDetails = new FailureDetails(e, + FailureDetails = new FailureDetails( + e, e.FailureDetails.ToCoreFailureDetails(), properties: e.FailureDetails.Properties), }; diff --git a/src/Worker/Grpc/GrpcDurableTaskWorker.Processor.cs b/src/Worker/Grpc/GrpcDurableTaskWorker.Processor.cs index 4dfa70f7f..8a8808322 100644 --- a/src/Worker/Grpc/GrpcDurableTaskWorker.Processor.cs +++ b/src/Worker/Grpc/GrpcDurableTaskWorker.Processor.cs @@ -34,9 +34,11 @@ class Processor readonly DurableTaskShimFactory shimFactory; readonly GrpcDurableTaskWorkerOptions.InternalOptions internalOptions; readonly DTCore.IExceptionPropertiesProvider? exceptionPropertiesProvider; + [Obsolete("Experimental")] readonly IOrchestrationFilter? orchestrationFilter; +#pragma warning disable CS0618 // Type or member is obsolete public Processor(GrpcDurableTaskWorker worker, TaskHubSidecarServiceClient client, IOrchestrationFilter? orchestrationFilter = null, IExceptionPropertiesProvider? exceptionPropertiesProvider = null) { this.worker = worker; @@ -48,6 +50,7 @@ public Processor(GrpcDurableTaskWorker worker, TaskHubSidecarServiceClient clien ? new ExceptionPropertiesProviderAdapter(exceptionPropertiesProvider) : null; } +#pragma warning restore CS0618 // Type or member is obsolete ILogger Logger => this.worker.logger; @@ -346,115 +349,116 @@ void RunBackgroundTask(P.WorkItem? workItem, Func handler, CancellationTok // TODO: is Task.Run appropriate here? Should we have finer control over the tasks and their threads? _ = Task.Run( async () => - { - try - { - await handler(); - } - catch (OperationCanceledException) - { - // Shutting down - ignore - } - catch (Exception ex) { - string instanceId = - workItem?.OrchestratorRequest?.InstanceId ?? - workItem?.ActivityRequest?.OrchestrationInstance?.InstanceId ?? - workItem?.EntityRequest?.InstanceId ?? - workItem?.EntityRequestV2?.InstanceId ?? - string.Empty; - this.Logger.UnexpectedError(ex, instanceId); - - if (workItem?.OrchestratorRequest != null) + try { - try - { - this.Logger.AbandoningOrchestratorWorkItem(instanceId, workItem?.CompletionToken ?? string.Empty); - await this.client.AbandonTaskOrchestratorWorkItemAsync( - new P.AbandonOrchestrationTaskRequest - { - CompletionToken = workItem?.CompletionToken, - }, - cancellationToken: cancellation); - this.Logger.AbandonedOrchestratorWorkItem(instanceId, workItem?.CompletionToken ?? string.Empty); - } - catch (Exception abandonException) - { - this.Logger.UnexpectedError(abandonException, instanceId); - } + await handler(); } - else if (workItem?.ActivityRequest != null) + catch (OperationCanceledException) { - try - { - this.Logger.AbandoningActivityWorkItem( - instanceId, - workItem.ActivityRequest.Name, - workItem.ActivityRequest.TaskId, - workItem?.CompletionToken ?? string.Empty); - await this.client.AbandonTaskActivityWorkItemAsync( - new P.AbandonActivityTaskRequest - { - CompletionToken = workItem?.CompletionToken, - }, - cancellationToken: cancellation); - this.Logger.AbandonedActivityWorkItem( - instanceId, - workItem.ActivityRequest.Name, - workItem.ActivityRequest.TaskId, - workItem?.CompletionToken ?? string.Empty); - } - catch (Exception abandonException) - { - this.Logger.UnexpectedError(abandonException, instanceId); - } + // Shutting down - ignore } - else if (workItem?.EntityRequest != null) + catch (Exception ex) { - try + string instanceId = + workItem?.OrchestratorRequest?.InstanceId ?? + workItem?.ActivityRequest?.OrchestrationInstance?.InstanceId ?? + workItem?.EntityRequest?.InstanceId ?? + workItem?.EntityRequestV2?.InstanceId ?? + string.Empty; + this.Logger.UnexpectedError(ex, instanceId); + + if (workItem?.OrchestratorRequest != null) { - this.Logger.AbandoningEntityWorkItem( - workItem.EntityRequest.InstanceId, - workItem?.CompletionToken ?? string.Empty); - await this.client.AbandonTaskEntityWorkItemAsync( - new P.AbandonEntityTaskRequest - { - CompletionToken = workItem?.CompletionToken, - }, - cancellationToken: cancellation); - this.Logger.AbandonedEntityWorkItem( - workItem.EntityRequest.InstanceId, - workItem?.CompletionToken ?? string.Empty); + try + { + this.Logger.AbandoningOrchestratorWorkItem(instanceId, workItem?.CompletionToken ?? string.Empty); + await this.client.AbandonTaskOrchestratorWorkItemAsync( + new P.AbandonOrchestrationTaskRequest + { + CompletionToken = workItem?.CompletionToken, + }, + cancellationToken: cancellation); + this.Logger.AbandonedOrchestratorWorkItem(instanceId, workItem?.CompletionToken ?? string.Empty); + } + catch (Exception abandonException) + { + this.Logger.UnexpectedError(abandonException, instanceId); + } } - catch (Exception abandonException) + else if (workItem?.ActivityRequest != null) { - this.Logger.UnexpectedError(abandonException, workItem.EntityRequest.InstanceId); + try + { + this.Logger.AbandoningActivityWorkItem( + instanceId, + workItem.ActivityRequest.Name, + workItem.ActivityRequest.TaskId, + workItem.CompletionToken ?? string.Empty); + await this.client.AbandonTaskActivityWorkItemAsync( + new P.AbandonActivityTaskRequest + { + CompletionToken = workItem.CompletionToken, + }, + cancellationToken: cancellation); + this.Logger.AbandonedActivityWorkItem( + instanceId, + workItem.ActivityRequest.Name, + workItem.ActivityRequest.TaskId, + workItem.CompletionToken ?? string.Empty); + } + catch (Exception abandonException) + { + this.Logger.UnexpectedError(abandonException, instanceId); + } } - } - else if (workItem?.EntityRequestV2 != null) - { - try + else if (workItem?.EntityRequest != null) { - this.Logger.AbandoningEntityWorkItem( - workItem.EntityRequestV2.InstanceId, - workItem?.CompletionToken ?? string.Empty); - await this.client.AbandonTaskEntityWorkItemAsync( - new P.AbandonEntityTaskRequest - { - CompletionToken = workItem?.CompletionToken, - }, - cancellationToken: cancellation); - this.Logger.AbandonedEntityWorkItem( - workItem.EntityRequestV2.InstanceId, - workItem?.CompletionToken ?? string.Empty); + try + { + this.Logger.AbandoningEntityWorkItem( + workItem.EntityRequest.InstanceId, + workItem.CompletionToken ?? string.Empty); + await this.client.AbandonTaskEntityWorkItemAsync( + new P.AbandonEntityTaskRequest + { + CompletionToken = workItem.CompletionToken, + }, + cancellationToken: cancellation); + this.Logger.AbandonedEntityWorkItem( + workItem.EntityRequest.InstanceId, + workItem.CompletionToken ?? string.Empty); + } + catch (Exception abandonException) + { + this.Logger.UnexpectedError(abandonException, workItem.EntityRequest.InstanceId); + } } - catch (Exception abandonException) + else if (workItem?.EntityRequestV2 != null) { - this.Logger.UnexpectedError(abandonException, workItem.EntityRequestV2.InstanceId); + try + { + this.Logger.AbandoningEntityWorkItem( + workItem.EntityRequestV2.InstanceId, + workItem.CompletionToken ?? string.Empty); + await this.client.AbandonTaskEntityWorkItemAsync( + new P.AbandonEntityTaskRequest + { + CompletionToken = workItem.CompletionToken, + }, + cancellationToken: cancellation); + this.Logger.AbandonedEntityWorkItem( + workItem.EntityRequestV2.InstanceId, + workItem.CompletionToken ?? string.Empty); + } + catch (Exception abandonException) + { + this.Logger.UnexpectedError(abandonException, workItem.EntityRequestV2.InstanceId); + } } } - } - }); + }, + cancellation); } async Task OnRunOrchestratorAsync( @@ -584,6 +588,7 @@ async Task OnRunOrchestratorAsync( cancellationToken); bool filterPassed = true; +#pragma warning disable CS0618 // Type or member is obsolete if (this.orchestrationFilter != null) { filterPassed = await this.orchestrationFilter.IsOrchestrationValidAsync( @@ -594,6 +599,7 @@ async Task OnRunOrchestratorAsync( }, cancellationToken); } +#pragma warning restore CS0618 // Type or member is obsolete if (!filterPassed) { diff --git a/src/Worker/Grpc/GrpcDurableTaskWorker.cs b/src/Worker/Grpc/GrpcDurableTaskWorker.cs index da61d8849..f3a4c4653 100644 --- a/src/Worker/Grpc/GrpcDurableTaskWorker.cs +++ b/src/Worker/Grpc/GrpcDurableTaskWorker.cs @@ -17,7 +17,10 @@ sealed partial class GrpcDurableTaskWorker : DurableTaskWorker readonly IServiceProvider services; readonly ILoggerFactory loggerFactory; readonly ILogger logger; + +#pragma warning disable CS0618 // Type or member is obsolete readonly IOrchestrationFilter? orchestrationFilter; +#pragma warning restore CS0618 // Type or member is obsolete /// /// Initializes a new instance of the class. @@ -37,7 +40,9 @@ public GrpcDurableTaskWorker( IOptionsMonitor workerOptions, IServiceProvider services, ILoggerFactory loggerFactory, +#pragma warning disable CS0618 // Type or member is obsolete IOrchestrationFilter? orchestrationFilter = null, +#pragma warning restore CS0618 // Type or member is obsolete IExceptionPropertiesProvider? exceptionPropertiesProvider = null) : base(name, factory) { diff --git a/test/Abstractions.Tests/Abstractions.Tests.csproj b/test/Abstractions.Tests/Abstractions.Tests.csproj index e4cf7da90..2d01e54d2 100644 --- a/test/Abstractions.Tests/Abstractions.Tests.csproj +++ b/test/Abstractions.Tests/Abstractions.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 diff --git a/test/Analyzers.Tests/Analyzers.Tests.csproj b/test/Analyzers.Tests/Analyzers.Tests.csproj index a43fbdd08..b1117575c 100644 --- a/test/Analyzers.Tests/Analyzers.Tests.csproj +++ b/test/Analyzers.Tests/Analyzers.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 diff --git a/test/Benchmarks/Benchmarks.csproj b/test/Benchmarks/Benchmarks.csproj index 58504ddf0..8647ccc22 100644 --- a/test/Benchmarks/Benchmarks.csproj +++ b/test/Benchmarks/Benchmarks.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 Exe Benchmarks diff --git a/test/Client/AzureManaged.Tests/Client.AzureManaged.Tests.csproj b/test/Client/AzureManaged.Tests/Client.AzureManaged.Tests.csproj index 4d43922f1..64203930d 100644 --- a/test/Client/AzureManaged.Tests/Client.AzureManaged.Tests.csproj +++ b/test/Client/AzureManaged.Tests/Client.AzureManaged.Tests.csproj @@ -1,13 +1,9 @@ - net6.0 + net8.0 - - - - @@ -18,4 +14,8 @@ + + + + diff --git a/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs b/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs index 7aad801c3..cad17bd9d 100644 --- a/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs +++ b/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs @@ -95,7 +95,7 @@ public void UseDurableTaskScheduler_WithLocalhostConnectionString_ShouldConfigur [Theory] [InlineData(null, "testhub")] [InlineData("myaccount.westus3.durabletask.io", null)] - public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidationException(string endpoint, string taskHub) + public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidationException(string? endpoint, string? taskHub) { // Arrange ServiceCollection services = new ServiceCollection(); @@ -104,7 +104,7 @@ public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidat DefaultAzureCredential credential = new DefaultAzureCredential(); // Act - mockBuilder.Object.UseDurableTaskScheduler(endpoint, taskHub, credential); + mockBuilder.Object.UseDurableTaskScheduler(endpoint!, taskHub!, credential); ServiceProvider provider = services.BuildServiceProvider(); // Assert diff --git a/test/Client/Core.Tests/Client.Tests.csproj b/test/Client/Core.Tests/Client.Tests.csproj index 29966adc7..413c1244b 100644 --- a/test/Client/Core.Tests/Client.Tests.csproj +++ b/test/Client/Core.Tests/Client.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 diff --git a/test/Client/Core.Tests/DependencyInjection/DefaultDurableTaskClientProviderTests.cs b/test/Client/Core.Tests/DependencyInjection/DefaultDurableTaskClientProviderTests.cs index f6e2de6a0..9d1e0b6b8 100644 --- a/test/Client/Core.Tests/DependencyInjection/DefaultDurableTaskClientProviderTests.cs +++ b/test/Client/Core.Tests/DependencyInjection/DefaultDurableTaskClientProviderTests.cs @@ -10,10 +10,10 @@ public class DefaultDurableTaskClientProviderTests [InlineData("client1")] [InlineData("Not-found")] // case sensitive [InlineData("client1", "client2")] - public void GetClient_NotFound_Throws(params string[] clients) + public void GetClient_NotFound_Throws(params string?[] clients) { - clients ??= Array.Empty(); - DefaultDurableTaskClientProvider provider = new(CreateClients(clients)); + clients ??= []; + DefaultDurableTaskClientProvider provider = new(CreateClients(clients!)); string allNames = string.Join(", ", clients.Select(x => $"\"{x}\"")); string message = $"The value of this argument must be in the set of available clients: [{allNames}]." @@ -32,7 +32,7 @@ public void GetClient_NotFound_Throws(params string[] clients) [InlineData("Client1", "client1", "client2")] public void GetClient_Found_Returns(params string[] clients) { - clients ??= Array.Empty(); + clients ??= []; DefaultDurableTaskClientProvider provider = new(CreateClients(clients)); DurableTaskClient client = provider.GetClient("client1"); diff --git a/test/Client/Grpc.Tests/Client.Grpc.Tests.csproj b/test/Client/Grpc.Tests/Client.Grpc.Tests.csproj index 6d3dba798..ab59f7f4e 100644 --- a/test/Client/Grpc.Tests/Client.Grpc.Tests.csproj +++ b/test/Client/Grpc.Tests/Client.Grpc.Tests.csproj @@ -1,7 +1,7 @@  - net6.0;net48 + net8.0;net48 diff --git a/test/Client/OrchestrationServiceClientShim.Tests/Client.OrchestrationServiceClientShim.Tests.csproj b/test/Client/OrchestrationServiceClientShim.Tests/Client.OrchestrationServiceClientShim.Tests.csproj index f24130cbb..ec84beee7 100644 --- a/test/Client/OrchestrationServiceClientShim.Tests/Client.OrchestrationServiceClientShim.Tests.csproj +++ b/test/Client/OrchestrationServiceClientShim.Tests/Client.OrchestrationServiceClientShim.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 diff --git a/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs b/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs index 588f59ac3..4b3ed9386 100644 --- a/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs +++ b/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs @@ -94,7 +94,7 @@ public void Ctor_EntitiesConfigured_GetClientSuccess() [Theory] [InlineData(false)] [InlineData(true)] - public async void GetInstanceMetadata_EmptyList_Null(bool isNull) + public async Task GetInstanceMetadata_EmptyList_Null(bool isNull) { // arrange List? states = isNull ? null : new(); diff --git a/test/Generators.Tests/AzureFunctionsTests.cs b/test/Generators.Tests/AzureFunctionsTests.cs deleted file mode 100644 index 5cfa9d8a9..000000000 --- a/test/Generators.Tests/AzureFunctionsTests.cs +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -//using Microsoft.Azure.Functions.Worker; -using Microsoft.DurableTask.Generators.Tests.Utils; - -namespace Microsoft.DurableTask.Generators.Tests; - -public class AzureFunctionsTests -{ - const string GeneratedClassName = "GeneratedDurableTaskExtensions"; - const string GeneratedFileName = $"{GeneratedClassName}.cs"; - - [Fact(Skip = "Durable Functions Extension out of date")] - public async Task Activities_SimpleFunctionTrigger() - { - string code = @" -using Microsoft.Azure.Functions.Worker; -using Microsoft.DurableTask; - -public class Calculator -{ - [Function(nameof(Identity))] - public int Identity([ActivityTrigger] int input) => input; -}"; - - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: @" -public static Task CallIdentityAsync(this TaskOrchestrationContext ctx, int input, TaskOptions? options = null) -{ - return ctx.CallActivityAsync(""Identity"", input, options); -}", - isDurableFunctions: true); - - await TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: true); - } - - [Fact(Skip = "Durable Functions Extension out of date")] - public async Task Activities_SimpleFunctionTrigger_TaskReturning() - { - string code = @" -using System.Threading.Tasks; -using Microsoft.Azure.Functions.Worker; -using Microsoft.DurableTask; - -public class Calculator -{ - [Function(""Identity"")] - public Task IdentityAsync([ActivityTrigger] int input) => Task.FromResult(input); -}"; - - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: @" -public static Task CallIdentityAsync(this TaskOrchestrationContext ctx, int input, TaskOptions? options = null) -{ - return ctx.CallActivityAsync(""Identity"", input, options); -}", - isDurableFunctions: true); - - await TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: true); - } - - [Fact(Skip = "Durable Functions Extension out of date")] - public async Task Activities_SimpleFunctionTrigger_CustomType() - { - string code = @" -using System.Threading.Tasks; -using Microsoft.Azure.Functions.Worker; -using Microsoft.DurableTask; - -namespace AzureFunctionsTests -{ - public record Input(int Value); - - public class Calculator - { - [Function(""Identity"")] - public Task Identity([ActivityTrigger] Input input) => Task.FromResult(input); - } -}"; - - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: @" -public static Task CallIdentityAsync(this TaskOrchestrationContext ctx, AzureFunctionsTests.Input input, TaskOptions? options = null) -{ - return ctx.CallActivityAsync(""Identity"", input, options); -}", - isDurableFunctions: true); - - await TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: true); - } - - /// - /// Verifies that using the class-based activity syntax generates a - /// extension method as well as an function definition. - /// - /// The activity input type. - /// The activity output type. - [Theory(Skip = "Durable Functions Extension out of date")] - [InlineData("int", "string")] - [InlineData("string", "int")] - [InlineData("Guid", "TimeSpan")] - public async Task Activities_ClassBasedSyntax(string inputType, string outputType) - { - // Nullable reference types need to be used for input expressions - string defaultInputType = TestHelpers.GetDefaultInputType(inputType); - - string code = $@" -using System; -using System.Threading.Tasks; -using Microsoft.DurableTask; - -[DurableTask(nameof(MyActivity))] -public class MyActivity : TaskActivityBase<{inputType}, {outputType}> -{{ - protected override {outputType} OnRun(TaskActivityContext context, {inputType} input) => default!; -}}"; - - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: $@" -public static Task<{outputType}> CallMyActivityAsync(this TaskOrchestrationContext ctx, {inputType} input, TaskOptions? options = null) -{{ - return ctx.CallActivityAsync<{outputType}>(""MyActivity"", input, options); -}} - -[Function(nameof(MyActivity))] -public static async Task<{outputType}> MyActivity([ActivityTrigger] {defaultInputType} input, string instanceId, FunctionContext executionContext) -{{ - ITaskActivity activity = ActivatorUtilities.CreateInstance(executionContext.InstanceServices); - TaskActivityContext context = new GeneratedActivityContext(""MyActivity"", instanceId); - object? result = await activity.RunAsync(context, input); - return ({outputType})result!; -}} -{TestHelpers.DeIndent(DurableTaskSourceGenerator.GetGeneratedActivityContextCode(), spacesToRemove: 8)}", - isDurableFunctions: true); - - await TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: true); - } - - /// - /// Verifies that using the class-based syntax for authoring orchestrations generates - /// type-safe and - /// extension methods as well as function triggers. - /// - /// The activity input type. - /// The activity output type. - [Theory(Skip = "Durable Functions Extension out of date")] - [InlineData("int", "string?")] - [InlineData("string", "int")] - [InlineData("(int, int)", "(double, double)")] - [InlineData("DateTime?", "DateTimeOffset?")] - public async Task Orchestrators_ClassBasedSyntax(string inputType, string outputType) - { - // Nullable reference types need to be used for input expressions - string defaultInputType = TestHelpers.GetDefaultInputType(inputType); - - string code = $@" -#nullable enable -using System; -using System.Threading.Tasks; -using Microsoft.DurableTask; - -namespace MyNS -{{ - [DurableTask(nameof(MyOrchestrator))] - public class MyOrchestrator : TaskOrchestratorBase<{inputType}, {outputType}> - {{ - protected override Task<{outputType}> OnRunAsync(TaskOrchestrationContext ctx, {defaultInputType} input) => throw new NotImplementedException(); - }} -}}"; - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: $@" -static readonly ITaskOrchestrator singletonMyOrchestrator = new MyNS.MyOrchestrator(); - -[Function(nameof(MyOrchestrator))] -public static Task<{outputType}> MyOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context) -{{ - return singletonMyOrchestrator.RunAsync(context, context.GetInput<{inputType}>()) - .ContinueWith(t => ({outputType})(t.Result ?? default({outputType})!), TaskContinuationOptions.ExecuteSynchronously); -}} - -/// -public static Task ScheduleNewMyOrchestratorInstanceAsync( - this DurableTaskClient client, - string? instanceId = null, - {defaultInputType} input = default, - DateTimeOffset? startTime = null) -{{ - return client.ScheduleNewOrchestrationInstanceAsync( - ""MyOrchestrator"", - instanceId, - input, - startTime); -}} - -/// -public static Task<{outputType}> CallMyOrchestratorAsync( - this TaskOrchestrationContext context, - string? instanceId = null, - {defaultInputType} input = default, - TaskOptions? options = null) -{{ - return context.CallSubOrchestratorAsync<{outputType}>( - ""MyOrchestrator"", - instanceId, - input, - options); -}}", - isDurableFunctions: true); - - await TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: true); - } - - /// - /// Verifies that using the class-based syntax for authoring orchestrations generates - /// type-safe and - /// extension methods as well as function triggers. - /// - /// The activity input type. - /// The activity output type. - [Theory(Skip = "Durable Functions Extension out of date")] - [InlineData("int", "string?")] - [InlineData("string", "int")] - [InlineData("(int, int)", "(double, double)")] - [InlineData("DateTime?", "DateTimeOffset?")] - public async Task Orchestrators_ClassBasedSyntax_Inheritance(string inputType, string outputType) - { - // Nullable reference types need to be used for input expressions - string defaultInputType = TestHelpers.GetDefaultInputType(inputType); - - string code = $@" -#nullable enable -using System; -using System.Threading.Tasks; -using Microsoft.DurableTask; - -namespace MyNS -{{ - [DurableTask] - public class MyOrchestrator : MyOrchestratorBase - {{ - protected override Task<{outputType}> OnRunAsync(TaskOrchestrationContext ctx, {defaultInputType} input) => throw new NotImplementedException(); - }} - - public abstract class MyOrchestratorBase : TaskOrchestratorBase<{inputType}, {outputType}> - {{ - }} -}}"; - // Same output as Orchestrators_ClassBasedSyntax - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: $@" -static readonly ITaskOrchestrator singletonMyOrchestrator = new MyNS.MyOrchestrator(); - -[Function(nameof(MyOrchestrator))] -public static Task<{outputType}> MyOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context) -{{ - return singletonMyOrchestrator.RunAsync(context, context.GetInput<{inputType}>()) - .ContinueWith(t => ({outputType})(t.Result ?? default({outputType})!), TaskContinuationOptions.ExecuteSynchronously); -}} - -/// -public static Task ScheduleNewMyOrchestratorInstanceAsync( - this DurableTaskClient client, - string? instanceId = null, - {defaultInputType} input = default, - DateTimeOffset? startTime = null) -{{ - return client.ScheduleNewOrchestrationInstanceAsync( - ""MyOrchestrator"", - instanceId, - input, - startTime); -}} - -/// -public static Task<{outputType}> CallMyOrchestratorAsync( - this TaskOrchestrationContext context, - string? instanceId = null, - {defaultInputType} input = default, - TaskOptions? options = null) -{{ - return context.CallSubOrchestratorAsync<{outputType}>( - ""MyOrchestrator"", - instanceId, - input, - options); -}}", - isDurableFunctions: true); - - await TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: true); - } -} diff --git a/test/Generators.Tests/ClassBasedSyntaxTests.cs b/test/Generators.Tests/ClassBasedSyntaxTests.cs deleted file mode 100644 index 18bd9d320..000000000 --- a/test/Generators.Tests/ClassBasedSyntaxTests.cs +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Microsoft.DurableTask.Generators.Tests.Utils; - -namespace Microsoft.DurableTask.Generators.Tests; - -public class ClassBasedSyntaxTests -{ - const string GeneratedClassName = "GeneratedDurableTaskExtensions"; - const string GeneratedFileName = $"{GeneratedClassName}.cs"; - - [Theory] - [InlineData("int", "int input")] - [InlineData("int?", "int? input = default")] - [InlineData("string", "string input")] - [InlineData("string?", "string? input = default")] - public Task Orchestrators_PrimitiveTypes(string type, string input) - { - string code = $@" -#nullable enable -using System.Threading.Tasks; -using Microsoft.DurableTask; - -[DurableTask(nameof(MyOrchestrator))] -class MyOrchestrator : TaskOrchestrator<{type}, string> -{{ - public override Task RunAsync(TaskOrchestrationContext ctx, {type} input) => Task.FromResult(string.Empty); -}}"; - - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: $@" -/// -public static Task ScheduleNewMyOrchestratorInstanceAsync( - this IOrchestrationSubmitter client, {input}, StartOrchestrationOptions? options = null) -{{ - return client.ScheduleNewOrchestrationInstanceAsync(""MyOrchestrator"", input, options); -}} - -/// -public static Task CallMyOrchestratorAsync( - this TaskOrchestrationContext context, {input}, TaskOptions? options = null) -{{ - return context.CallSubOrchestratorAsync(""MyOrchestrator"", input, options); -}} - -internal static DurableTaskRegistry AddAllGeneratedTasks(this DurableTaskRegistry builder) -{{ - builder.AddOrchestrator(); - return builder; -}}"); - - return TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: false); - } - - [Fact] - public Task Orchestrators_Inheritance() - { - string code = @" -using System.Threading.Tasks; -using Microsoft.DurableTask; - -[DurableTask(nameof(MyOrchestrator))] -sealed class MyOrchestrator : MyOrchestratorBase -{ - public override Task RunAsync(TaskOrchestrationContext ctx, int input) => Task.FromResult(this.X); -} - -abstract class MyOrchestratorBase : TaskOrchestrator -{ - public virtual string X => ""Foo""; -}"; - - // NOTE: Same output as Orchestrators_PrimitiveTypes - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: @" -/// -public static Task ScheduleNewMyOrchestratorInstanceAsync( - this IOrchestrationSubmitter client, int input, StartOrchestrationOptions? options = null) -{ - return client.ScheduleNewOrchestrationInstanceAsync(""MyOrchestrator"", input, options); -} - -/// -public static Task CallMyOrchestratorAsync( - this TaskOrchestrationContext context, int input, TaskOptions? options = null) -{ - return context.CallSubOrchestratorAsync(""MyOrchestrator"", input, options); -} - -internal static DurableTaskRegistry AddAllGeneratedTasks(this DurableTaskRegistry builder) -{ - builder.AddOrchestrator(); - return builder; -}"); - - return TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: false); - - } - - [Theory] - [InlineData("int", "int input")] - [InlineData("int?", "int? input = default")] - [InlineData("string", "string input")] - [InlineData("string?", "string? input = default")] - public Task Activities_PrimitiveTypes(string type, string input) - { - string code = $@" -#nullable enable -using System.Threading.Tasks; -using Microsoft.DurableTask; - -[DurableTask(nameof(MyActivity))] -class MyActivity : TaskActivity<{type}, string> -{{ - public override Task RunAsync(TaskActivityContext context, {type} input) => Task.FromResult(string.Empty); -}}"; - - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: $@" -public static Task CallMyActivityAsync(this TaskOrchestrationContext ctx, {input}, TaskOptions? options = null) -{{ - return ctx.CallActivityAsync(""MyActivity"", input, options); -}} - -internal static DurableTaskRegistry AddAllGeneratedTasks(this DurableTaskRegistry builder) -{{ - builder.AddActivity(); - return builder; -}}"); - - return TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: false); - } - - [Fact] - public Task Activities_CustomTypes() - { - string code = @" -using System.Threading.Tasks; -using MyNS; -using Microsoft.DurableTask; - -[DurableTask(nameof(MyActivity))] -class MyActivity : TaskActivity -{ - public override Task RunAsync(TaskActivityContext context, MyClass input) => Task.FromResult(input); -} - -namespace MyNS -{ - public class MyClass { } -}"; - - string expectedOutput = TestHelpers.WrapAndFormat( - generatedClassName: "GeneratedDurableTaskExtensions", - methodList: @" -public static Task CallMyActivityAsync(this TaskOrchestrationContext ctx, MyNS.MyClass input, TaskOptions? options = null) -{ - return ctx.CallActivityAsync(""MyActivity"", input, options); -} - -internal static DurableTaskRegistry AddAllGeneratedTasks(this DurableTaskRegistry builder) -{ - builder.AddActivity(); - return builder; -}"); - - return TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: false); - } - - - [Fact] - public Task Activities_ExplicitNaming() - { - // The [DurableTask] attribute is expected to override the activity class name - string code = @" -using System.Threading.Tasks; -using MyNS; -using Microsoft.DurableTask; - -namespace MyNS -{ - [DurableTask(""MyActivity"")] - class MyActivityImpl : TaskActivity - { - public override Task RunAsync(TaskActivityContext context, MyClass input) => Task.FromResult(input); - } - - public class MyClass { } -}"; - - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: @" -public static Task CallMyActivityAsync(this TaskOrchestrationContext ctx, MyNS.MyClass input, TaskOptions? options = null) -{ - return ctx.CallActivityAsync(""MyActivity"", input, options); -} - -internal static DurableTaskRegistry AddAllGeneratedTasks(this DurableTaskRegistry builder) -{ - builder.AddActivity(); - return builder; -}"); - - return TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: false); - } - - [Fact] - public Task Activities_Inheritance() - { - string code = @" -using System.Threading.Tasks; -using Microsoft.DurableTask; - -[DurableTask(nameof(MyActivity))] -class MyActivity : MyActivityBase -{ - public override Task RunAsync(TaskActivityContext context, int input) => Task.FromResult(string.Empty); -} - -abstract class MyActivityBase : TaskActivity -{ -}"; - - // NOTE: Same output as Activities_PrimitiveTypes - string expectedOutput = TestHelpers.WrapAndFormat( - GeneratedClassName, - methodList: @" -public static Task CallMyActivityAsync(this TaskOrchestrationContext ctx, int input, TaskOptions? options = null) -{ - return ctx.CallActivityAsync(""MyActivity"", input, options); -} - -internal static DurableTaskRegistry AddAllGeneratedTasks(this DurableTaskRegistry builder) -{ - builder.AddActivity(); - return builder; -}"); - - return TestHelpers.RunTestAsync( - GeneratedFileName, - code, - expectedOutput, - isDurableFunctions: false); - } -} diff --git a/test/Generators.Tests/Generators.Tests.csproj b/test/Generators.Tests/Generators.Tests.csproj index f805fecb6..243824179 100644 --- a/test/Generators.Tests/Generators.Tests.csproj +++ b/test/Generators.Tests/Generators.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 diff --git a/test/Grpc.IntegrationTests/Grpc.IntegrationTests.csproj b/test/Grpc.IntegrationTests/Grpc.IntegrationTests.csproj index e6b0aee76..3c9f765b7 100644 --- a/test/Grpc.IntegrationTests/Grpc.IntegrationTests.csproj +++ b/test/Grpc.IntegrationTests/Grpc.IntegrationTests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 diff --git a/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs b/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs index 2235efd65..58dda8a81 100644 --- a/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs +++ b/test/Grpc.IntegrationTests/OrchestrationErrorHandling.cs @@ -746,6 +746,7 @@ public CustomException(string message, Exception innerException) { } + [Obsolete] protected CustomException(SerializationInfo info, StreamingContext context) : base(info, context) { @@ -784,6 +785,7 @@ public BusinessValidationException(string message, public IList? ListProperty { get; } public object? NullProperty { get; } + [Obsolete] protected BusinessValidationException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/test/ScheduledTasks.Tests/Client/DefaultScheduleClientTests.cs b/test/ScheduledTasks.Tests/Client/DefaultScheduleClientTests.cs index d5c89fa0e..f3c55fa6c 100644 --- a/test/ScheduledTasks.Tests/Client/DefaultScheduleClientTests.cs +++ b/test/ScheduledTasks.Tests/Client/DefaultScheduleClientTests.cs @@ -39,11 +39,11 @@ public void Constructor_WithNullClient_ThrowsArgumentNullException() [Theory] [InlineData(null, typeof(ArgumentNullException), "Value cannot be null")] [InlineData("", typeof(ArgumentException), "Parameter cannot be an empty string")] - public void Constructor_WithInvalidScheduleId_ThrowsCorrectException(string invalidScheduleId, Type expectedExceptionType, string expectedMessage) + public void Constructor_WithInvalidScheduleId_ThrowsCorrectException(string? invalidScheduleId, Type expectedExceptionType, string expectedMessage) { // Act & Assert var ex = Assert.Throws(expectedExceptionType, () => - new DefaultScheduleClient(this.durableTaskClient.Object, invalidScheduleId, this.logger)); + new DefaultScheduleClient(this.durableTaskClient.Object, invalidScheduleId!, this.logger)); Assert.Contains(expectedMessage, ex.Message, StringComparison.OrdinalIgnoreCase); } diff --git a/test/ScheduledTasks.Tests/Client/DefaultScheduledTaskClientTests.cs b/test/ScheduledTasks.Tests/Client/DefaultScheduledTaskClientTests.cs index 4eeada246..287299723 100644 --- a/test/ScheduledTasks.Tests/Client/DefaultScheduledTaskClientTests.cs +++ b/test/ScheduledTasks.Tests/Client/DefaultScheduledTaskClientTests.cs @@ -59,10 +59,10 @@ public void GetScheduleClient_ReturnsValidClient() [Theory] [InlineData(null, typeof(ArgumentNullException), "Value cannot be null")] [InlineData("", typeof(ArgumentException), "Parameter cannot be an empty string")] - public void GetScheduleClient_WithInvalidId_ThrowsCorrectException(string scheduleId, Type expectedExceptionType, string expectedMessage) + public void GetScheduleClient_WithInvalidId_ThrowsCorrectException(string? scheduleId, Type expectedExceptionType, string expectedMessage) { // Act & Assert - var ex = Assert.Throws(expectedExceptionType, () => this.client.GetScheduleClient(scheduleId)); + var ex = Assert.Throws(expectedExceptionType, () => this.client.GetScheduleClient(scheduleId!)); Assert.Contains(expectedMessage, ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -104,7 +104,7 @@ public async Task CreateScheduleAsync_WithValidOptions_CreatesSchedule() r.EntityId.Name == entityInstanceId.Name && r.EntityId.Key == entityInstanceId.Key && r.OperationName == nameof(Schedule.CreateSchedule) && - ((ScheduleCreationOptions)r.Input).ScheduleId == options.ScheduleId && + ((ScheduleCreationOptions)r.Input!).ScheduleId == options.ScheduleId && ((ScheduleCreationOptions)r.Input).OrchestrationName == options.OrchestrationName && ((ScheduleCreationOptions)r.Input).Interval == options.Interval), default), diff --git a/test/ScheduledTasks.Tests/Models/ScheduleCreationOptionsTests.cs b/test/ScheduledTasks.Tests/Models/ScheduleCreationOptionsTests.cs index 10d21a6b4..b08245ecd 100644 --- a/test/ScheduledTasks.Tests/Models/ScheduleCreationOptionsTests.cs +++ b/test/ScheduledTasks.Tests/Models/ScheduleCreationOptionsTests.cs @@ -36,7 +36,7 @@ public void Constructor_WithValidParameters_CreatesInstance() [InlineData("schedule", "", typeof(ArgumentException), "Parameter cannot be an empty string or start with the null character")] public void Constructor_WithInvalidParameters_ThrowsArgumentException( string scheduleId, - string orchestrationName, + string? orchestrationName, Type expectedExceptionType, string expectedMessage) { @@ -44,7 +44,7 @@ public void Constructor_WithInvalidParameters_ThrowsArgumentException( TimeSpan interval = TimeSpan.FromMinutes(5); // Act & Assert - var exception = Assert.Throws(expectedExceptionType, () => new ScheduleCreationOptions(scheduleId, orchestrationName, interval)); + var exception = Assert.Throws(expectedExceptionType, () => new ScheduleCreationOptions(scheduleId, orchestrationName!, interval)); Assert.Contains(expectedMessage, exception.Message); } diff --git a/test/ScheduledTasks.Tests/ScheduledTasks.Tests.csproj b/test/ScheduledTasks.Tests/ScheduledTasks.Tests.csproj index 33726a624..20b47cf83 100644 --- a/test/ScheduledTasks.Tests/ScheduledTasks.Tests.csproj +++ b/test/ScheduledTasks.Tests/ScheduledTasks.Tests.csproj @@ -1,18 +1,10 @@ - - net6.0 - enable - enable - false + net8.0 true - - - - diff --git a/test/Shared/AzureManaged.Tests/Shared.AzureManaged.Tests.csproj b/test/Shared/AzureManaged.Tests/Shared.AzureManaged.Tests.csproj index f9822995b..424359f9a 100644 --- a/test/Shared/AzureManaged.Tests/Shared.AzureManaged.Tests.csproj +++ b/test/Shared/AzureManaged.Tests/Shared.AzureManaged.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 diff --git a/test/TestHelpers/Logging/TestLogger.cs b/test/TestHelpers/Logging/TestLogger.cs index adbd31414..9602f0662 100644 --- a/test/TestHelpers/Logging/TestLogger.cs +++ b/test/TestHelpers/Logging/TestLogger.cs @@ -2,12 +2,14 @@ // Licensed under the MIT License. using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; public class TestLogger : ILogger { public List<(LogLevel Level, string Message)> Logs { get; } = new(); - public IDisposable? BeginScope(TState state) where TState : notnull => null; + public IDisposable BeginScope(TState state) + => NullLogger.Instance.BeginScope(state); public bool IsEnabled(LogLevel logLevel) => true; @@ -22,7 +24,8 @@ public class TestLogger : ILogger { public List<(LogLevel Level, string Message)> Logs { get; } = new(); - public IDisposable? BeginScope(TState state) where TState : notnull => null; + public IDisposable BeginScope(TState state) + => NullLogger.Instance.BeginScope(state); public bool IsEnabled(LogLevel logLevel) => true; @@ -31,4 +34,4 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except string message = formatter(state, exception); this.Logs.Add((logLevel, message)); } -} \ No newline at end of file +} diff --git a/test/TestHelpers/TestHelpers.csproj b/test/TestHelpers/TestHelpers.csproj index 555140828..51cc3d8f1 100644 --- a/test/TestHelpers/TestHelpers.csproj +++ b/test/TestHelpers/TestHelpers.csproj @@ -1,7 +1,7 @@  - net6.0;netstandard2.0 + net8.0;netstandard2.0 diff --git a/test/Worker/AzureManaged.Tests/DurableTaskSchedulerWorkerExtensionsTests.cs b/test/Worker/AzureManaged.Tests/DurableTaskSchedulerWorkerExtensionsTests.cs index 49e8df4e3..268ce46cd 100644 --- a/test/Worker/AzureManaged.Tests/DurableTaskSchedulerWorkerExtensionsTests.cs +++ b/test/Worker/AzureManaged.Tests/DurableTaskSchedulerWorkerExtensionsTests.cs @@ -98,7 +98,7 @@ public void UseDurableTaskScheduler_WithLocalhostConnectionString_ShouldConfigur [Theory] [InlineData(null, "testhub")] [InlineData("myaccount.westus3.durabletask.io", null)] - public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidationException(string endpoint, string taskHub) + public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidationException(string? endpoint, string? taskHub) { // Arrange ServiceCollection services = new ServiceCollection(); @@ -107,7 +107,7 @@ public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidat DefaultAzureCredential credential = new DefaultAzureCredential(); // Act - mockBuilder.Object.UseDurableTaskScheduler(endpoint, taskHub, credential); + mockBuilder.Object.UseDurableTaskScheduler(endpoint!, taskHub!, credential); ServiceProvider provider = services.BuildServiceProvider(); // Assert diff --git a/test/Worker/AzureManaged.Tests/Worker.AzureManaged.Tests.csproj b/test/Worker/AzureManaged.Tests/Worker.AzureManaged.Tests.csproj index 4a5a7cc15..daafb032a 100644 --- a/test/Worker/AzureManaged.Tests/Worker.AzureManaged.Tests.csproj +++ b/test/Worker/AzureManaged.Tests/Worker.AzureManaged.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 @@ -16,4 +16,5 @@ + diff --git a/test/Worker/Core.Tests/Worker.Tests.csproj b/test/Worker/Core.Tests/Worker.Tests.csproj index 736986d4d..c97b649e0 100644 --- a/test/Worker/Core.Tests/Worker.Tests.csproj +++ b/test/Worker/Core.Tests/Worker.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 diff --git a/test/Worker/Grpc.Tests/GrpcOrchestrationRunnerTests.cs b/test/Worker/Grpc.Tests/GrpcOrchestrationRunnerTests.cs index 6c3179211..abeb0b2b9 100644 --- a/test/Worker/Grpc.Tests/GrpcOrchestrationRunnerTests.cs +++ b/test/Worker/Grpc.Tests/GrpcOrchestrationRunnerTests.cs @@ -327,7 +327,7 @@ public void ExternallyEndedExtendedSession_Evicted() } [Fact] - public async void Stale_ExtendedSessions_Evicted_Async() + public async Task Stale_ExtendedSessions_Evicted_Async() { using var extendedSessions = new ExtendedSessionsCache(); int extendedSessionIdleTimeout = 5; diff --git a/test/Worker/Grpc.Tests/RunBackgroundTaskLoggingTests.cs b/test/Worker/Grpc.Tests/RunBackgroundTaskLoggingTests.cs index 56ace8e77..23ad7d1ab 100644 --- a/test/Worker/Grpc.Tests/RunBackgroundTaskLoggingTests.cs +++ b/test/Worker/Grpc.Tests/RunBackgroundTaskLoggingTests.cs @@ -343,7 +343,8 @@ static async Task AssertEventually(Func condition, int timeoutMs = 2000) } await Task.Delay(50); } - Assert.True(false, "Condition not met within timeout"); + + Assert.Fail("Condition not met within timeout"); } sealed class TestFixture : IAsyncDisposable @@ -366,10 +367,11 @@ sealed class TestFixture : IAsyncDisposable this.RunBackgroundTaskMethod = runBackgroundTaskMethod; } - public static async Task CreateAsync() + public static Task CreateAsync() { // Logging var logProvider = new TestLogProvider(new NullOutput()); + // DI var services = new ServiceCollection().BuildServiceProvider(); var loggerFactory = new SimpleLoggerFactory(logProvider); @@ -393,8 +395,8 @@ public static async Task CreateAsync() exceptionPropertiesProvider: null); // Client mock - var callInvoker = Mock.Of(); - var clientMock = new Mock(MockBehavior.Strict, new object[] { callInvoker }); + CallInvoker callInvoker = Mock.Of(); + var clientMock = new Mock(MockBehavior.Strict, [callInvoker]); // Build Processor via reflection Type processorType = typeof(GrpcDurableTaskWorker).GetNestedType("Processor", BindingFlags.NonPublic)!; @@ -402,17 +404,18 @@ public static async Task CreateAsync() processorType, BindingFlags.Public | BindingFlags.Instance, binder: null, - args: new object?[] { worker, clientMock.Object, null, null }, + args: [worker, clientMock.Object, null, null], culture: null)!; MethodInfo runBackgroundTask = processorType.GetMethod("RunBackgroundTask", BindingFlags.Instance | BindingFlags.NonPublic)!; - return new TestFixture((ServiceProvider)services, logProvider, clientMock, worker, processorInstance, runBackgroundTask); + TestFixture fixture = new(services, logProvider, clientMock, worker, processorInstance, runBackgroundTask); + return Task.FromResult(fixture); } public void InvokeRunBackgroundTask(P.WorkItem workItem, Func handler, CancellationToken cancellationToken = default) { - this.RunBackgroundTaskMethod.Invoke(this.ProcessorInstance, new object?[] { workItem, handler, cancellationToken }); + this.RunBackgroundTaskMethod.Invoke(this.ProcessorInstance, [workItem, handler, cancellationToken]); } public IReadOnlyCollection GetLogs() diff --git a/test/Worker/Grpc.Tests/Worker.Grpc.Tests.csproj b/test/Worker/Grpc.Tests/Worker.Grpc.Tests.csproj index cda2aa55a..6dd71a29c 100644 --- a/test/Worker/Grpc.Tests/Worker.Grpc.Tests.csproj +++ b/test/Worker/Grpc.Tests/Worker.Grpc.Tests.csproj @@ -1,7 +1,7 @@ - net6.0;net48 + net8.0;net48 From 419d5e1640a6f01af8aa485ff3ccb3201345f419 Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Tue, 21 Oct 2025 10:46:28 -0700 Subject: [PATCH 2/3] Update SDK, address more warnings --- global.json | 6 ++-- src/Client/Grpc/GrpcDurableTaskClient.cs | 2 +- src/Generators/DurableTaskSourceGenerator.cs | 2 ++ .../DurableTaskWorkerBuilderExtensions.cs | 2 +- .../Grpc/GrpcDurableTaskWorker.Processor.cs | 3 +- .../OrchestrationPatterns.cs | 32 ++++++++++++++++--- 6 files changed, 36 insertions(+), 11 deletions(-) diff --git a/global.json b/global.json index 4ac08fdaf..41ba8755c 100644 --- a/global.json +++ b/global.json @@ -1,10 +1,10 @@ { "sdk": { - "version": "8.0.100", + "version": "9.0.306", "rollForward": "latestFeature" }, "msbuild-sdks": { - "Microsoft.Build.NoTargets": "3.7.0", - "Microsoft.Build.Traversal": "4.1.0" + "Microsoft.Build.NoTargets": "3.7.134", + "Microsoft.Build.Traversal": "4.1.82" } } diff --git a/src/Client/Grpc/GrpcDurableTaskClient.cs b/src/Client/Grpc/GrpcDurableTaskClient.cs index c57b22f96..b6998e2af 100644 --- a/src/Client/Grpc/GrpcDurableTaskClient.cs +++ b/src/Client/Grpc/GrpcDurableTaskClient.cs @@ -100,7 +100,7 @@ public override async Task ScheduleNewOrchestrationInstanceAsync( }; // Add tags to the collection - if (request?.Tags != null && options?.Tags != null) + if (request.Tags != null && options?.Tags != null) { foreach (KeyValuePair tag in options.Tags) { diff --git a/src/Generators/DurableTaskSourceGenerator.cs b/src/Generators/DurableTaskSourceGenerator.cs index 4ad0eb2d2..24bcb7810 100644 --- a/src/Generators/DurableTaskSourceGenerator.cs +++ b/src/Generators/DurableTaskSourceGenerator.cs @@ -279,9 +279,11 @@ class DurableTaskSyntaxReceiver : ISyntaxContextReceiver readonly List activities = new(); readonly List durableFunctions = new(); +#pragma warning disable CA1859 // Use concrete types when possible for performance -- not important here public IReadOnlyList Orchestrators => this.orchestrators; public IReadOnlyList Activities => this.activities; public IReadOnlyList DurableFunctions => this.durableFunctions; +#pragma warning restore CA1859 // Use concrete types when possible for performance -- not important here public void OnVisitSyntaxNode(GeneratorSyntaxContext context) { diff --git a/src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs b/src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs index 3f349b710..801986538 100644 --- a/src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs +++ b/src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs @@ -78,7 +78,7 @@ public static IDurableTaskWorkerBuilder UseBuildTarget(this I where TTarget : DurableTaskWorker where TOptions : DurableTaskWorkerOptions { - builder.UseBuildTarget(typeof(TTarget)); + builder.UseBuildTarget(); builder.Services.AddOptions(builder.Name) .PostConfigure>((options, baseOptions) => { diff --git a/src/Worker/Grpc/GrpcDurableTaskWorker.Processor.cs b/src/Worker/Grpc/GrpcDurableTaskWorker.Processor.cs index 8a8808322..e65788d33 100644 --- a/src/Worker/Grpc/GrpcDurableTaskWorker.Processor.cs +++ b/src/Worker/Grpc/GrpcDurableTaskWorker.Processor.cs @@ -7,6 +7,7 @@ using DurableTask.Core.Entities; using DurableTask.Core.Entities.OperationFormat; using DurableTask.Core.History; +using Google.Protobuf.Collections; using Microsoft.DurableTask.Abstractions; using Microsoft.DurableTask.Entities; using Microsoft.DurableTask.Tracing; @@ -112,7 +113,7 @@ public async Task ExecuteAsync(CancellationToken cancellation) } } - static string GetActionsListForLogging(IReadOnlyList actions) + static string GetActionsListForLogging(RepeatedField actions) { if (actions.Count == 0) { diff --git a/test/Grpc.IntegrationTests/OrchestrationPatterns.cs b/test/Grpc.IntegrationTests/OrchestrationPatterns.cs index b03ff6797..4a48b3999 100644 --- a/test/Grpc.IntegrationTests/OrchestrationPatterns.cs +++ b/test/Grpc.IntegrationTests/OrchestrationPatterns.cs @@ -3,6 +3,7 @@ using System.Text.Json; using System.Text.Json.Nodes; +using Castle.Components.DictionaryAdapter; using Microsoft.DurableTask.Client; using Microsoft.DurableTask.Tests.Logging; using Microsoft.DurableTask.Worker; @@ -1134,14 +1135,35 @@ public async Task FilterOrchestrationsByTagPassesWithNoMatch() [Obsolete("Experimental")] class OrchestrationFilter : IOrchestrationFilter { - public ISet NameDenySet { get; set; } = new HashSet(); - public IDictionary TagDenyDict = new Dictionary(); + public ISet NameDenySet { get; } = new HashSet(); + public IDictionary TagDenyDict { get; } = new Dictionary(); public ValueTask IsOrchestrationValidAsync(OrchestrationFilterParameters info, CancellationToken cancellationToken = default) { - return ValueTask.FromResult( - !this.NameDenySet.Contains(info.Name) - && !this.TagDenyDict.Any(kvp => info.Tags != null && info.Tags.ContainsKey(kvp.Key) && info.Tags[kvp.Key] == kvp.Value)); + bool NameAllowed(string? name) + { + return name == null || !this.NameDenySet.Contains(name); + } + + bool TagsAllowed(IReadOnlyDictionary? tags) + { + if (tags == null) + { + return true; + } + + foreach ((string key, string value) in this.TagDenyDict) + { + if (tags.TryGetValue(key, out string? tagValue) && tagValue == value) + { + return false; + } + } + + return true; + } + + return ValueTask.FromResult(NameAllowed(info.Name) && TagsAllowed(info.Tags)); } } From e6a01f76d1780b7140f3b0768247fc45932dd9c8 Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Wed, 22 Oct 2025 09:46:49 -0700 Subject: [PATCH 3/3] Add dependabot.yml for sdk updates --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..5e8b1b8fa --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "dotnet-sdk" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + ignore: + - dependency-name: "*" + update-types: + - "version-update:semver-major" + - "version-update:semver-minor"