diff --git a/.github/workflows/E2ETest.yml b/.github/workflows/E2ETest.yml index 761c53e70..3eb18b29e 100644 --- a/.github/workflows/E2ETest.yml +++ b/.github/workflows/E2ETest.yml @@ -23,18 +23,23 @@ jobs: env: E2E_TEST_DURABLE_BACKEND: 'AzureStorage' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 6.0.x - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 8.0.x + - name: Setup .NET Core + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + - name: Set up Node.js (needed for Azurite) uses: actions/setup-node@v3 with: @@ -116,18 +121,23 @@ jobs: env: E2E_TEST_DURABLE_BACKEND: 'AzureStorage' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 6.0.x - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 8.0.x + - name: Setup .NET Core + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + - name: Set up Node.js (needed for Azurite) uses: actions/setup-node@v3 with: @@ -209,18 +219,23 @@ jobs: env: E2E_TEST_DURABLE_BACKEND: "MSSQL" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 6.0.x - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 8.0.x + - name: Setup .NET Core + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + - name: Set up Node.js (needed for Azurite) uses: actions/setup-node@v3 with: @@ -306,18 +321,23 @@ jobs: env: E2E_TEST_DURABLE_BACKEND: "azureManaged" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 6.0.x - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 8.0.x + - name: Setup .NET Core + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + - name: Set up Node.js (needed for Azurite) uses: actions/setup-node@v3 with: diff --git a/.github/workflows/codeQL.yml b/.github/workflows/codeQL.yml index 6cb68940e..bc60e6d5c 100644 --- a/.github/workflows/codeQL.yml +++ b/.github/workflows/codeQL.yml @@ -49,23 +49,38 @@ jobs: # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 - name: Set up .NET Core 2.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '2.1.x' - name: Set up .NET Core 3.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '3.1.x' + - name: Set up .NET 6.0 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '6.0.x' + + - name: Set up .NET 8.0 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + + - name: Set up .NET 10.0 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + - name: Restore dependencies run: dotnet restore $solution diff --git a/.github/workflows/smoketest-dotnet-isolated-v4.yml b/.github/workflows/smoketest-dotnet-isolated-v4.yml index 059e27d28..bac17356a 100644 --- a/.github/workflows/smoketest-dotnet-isolated-v4.yml +++ b/.github/workflows/smoketest-dotnet-isolated-v4.yml @@ -17,29 +17,34 @@ jobs: build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 # Install .NET versions - name: Set up .NET Core 3.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '3.1.x' - name: Set up .NET Core 2.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '2.1.x' - name: Set up .NET Core 6.x - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '6.x' - name: Set up .NET Core 8.x - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '8.x' + - name: Set up .NET Core 10.x + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + # Install Azurite - name: Set up Node.js (needed for Azurite) uses: actions/setup-node@v3 diff --git a/.github/workflows/smoketest-java8-v4.yml b/.github/workflows/smoketest-java8-v4.yml index 1277bdf08..f04776f10 100644 --- a/.github/workflows/smoketest-java8-v4.yml +++ b/.github/workflows/smoketest-java8-v4.yml @@ -17,7 +17,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 - name: Set up JDK 8 uses: actions/setup-java@v2 with: diff --git a/.github/workflows/smoketest-mssql-inproc-v4.yml b/.github/workflows/smoketest-mssql-inproc-v4.yml index 370fa404e..e15187049 100644 --- a/.github/workflows/smoketest-mssql-inproc-v4.yml +++ b/.github/workflows/smoketest-mssql-inproc-v4.yml @@ -24,7 +24,7 @@ jobs: FUNCTIONS_INPROC_NET8_ENABLED: "1" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Run V4 .NET in-proc w/ MSSQL Smoke Test run: test/SmokeTests/e2e-test.ps1 -DockerfilePath test/SmokeTests/BackendSmokeTests/MSSQL/Dockerfile -HttpStartPath api/DurableFunctionsHttpStart -ContainerName MSSQLApp -SetupSQLServer diff --git a/.github/workflows/smoketest-netherite-inproc-v4.yml b/.github/workflows/smoketest-netherite-inproc-v4.yml index ef24d1a19..5191bda20 100644 --- a/.github/workflows/smoketest-netherite-inproc-v4.yml +++ b/.github/workflows/smoketest-netherite-inproc-v4.yml @@ -21,7 +21,7 @@ jobs: FUNCTIONS_INPROC_NET8_ENABLED: "1" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 - name: Run V4 .NET in-proc w/ Netherite Smoke Test run: test/SmokeTests/e2e-test.ps1 -DockerfilePath test/SmokeTests/BackendSmokeTests/Netherite/Dockerfile -HttpStartPath api/DurableFunctionsHttpStart -ContainerName NetheriteApp shell: pwsh diff --git a/.github/workflows/smoketest-node20-v4.yml b/.github/workflows/smoketest-node24-v4.yml similarity index 82% rename from .github/workflows/smoketest-node20-v4.yml rename to .github/workflows/smoketest-node24-v4.yml index 9c70eaaa7..747ba93af 100644 --- a/.github/workflows/smoketest-node20-v4.yml +++ b/.github/workflows/smoketest-node24-v4.yml @@ -1,4 +1,4 @@ -name: Smoke Test - Node 20 on Functions V4 +name: Smoke Test - Node 24 on Functions V4 on: workflow_dispatch: @@ -17,7 +17,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Run V4 Node 20 Smoke Test + - uses: actions/checkout@v5 + - name: Run V4 Node 24 Smoke Test run: test/SmokeTests/e2e-test.ps1 -DockerfilePath test/SmokeTests/OOProcSmokeTests/durableJS/Dockerfile -HttpStartPath api/DurableFunctionsHttpStart -TestWithCustomInstanceId shell: pwsh diff --git a/.github/workflows/smoketest-python37-v4.yml b/.github/workflows/smoketest-python311-v4.yml similarity index 81% rename from .github/workflows/smoketest-python37-v4.yml rename to .github/workflows/smoketest-python311-v4.yml index b13d4ef6b..a51f3a772 100644 --- a/.github/workflows/smoketest-python37-v4.yml +++ b/.github/workflows/smoketest-python311-v4.yml @@ -1,4 +1,4 @@ -name: Smoke Test - Python 3.7 on Functions V4 +name: Smoke Test - Python 3.11 on Functions V4 on: workflow_dispatch: @@ -17,7 +17,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Run V4 Python 3.7 Smoke Test + - uses: actions/checkout@v5 + - name: Run V4 Python 3.11 Smoke Test run: test/SmokeTests/e2e-test.ps1 -DockerfilePath test/SmokeTests/OOProcSmokeTests/durablePy/Dockerfile -HttpStartPath api/DurableFunctionsHttpStart -ContainerName pyApp -TestWithCustomInstanceId shell: pwsh diff --git a/.github/workflows/validate-build-analyzer.yml b/.github/workflows/validate-build-analyzer.yml index aa79aae1e..3c528ae16 100644 --- a/.github/workflows/validate-build-analyzer.yml +++ b/.github/workflows/validate-build-analyzer.yml @@ -21,28 +21,38 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 - name: Set up .NET Core 3.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '3.1.x' - name: Set up .NET Core 2.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '2.1.x' - name: Set up .NET 6.0 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '6.0.x' + - name: Set up .NET 8.0 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + + - name: Set up .NET 10.0 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + - name: Restore dependencies run: dotnet restore $solution diff --git a/.github/workflows/validate-build-e2e.yml b/.github/workflows/validate-build-e2e.yml index ed8b827e1..4b09022e3 100644 --- a/.github/workflows/validate-build-e2e.yml +++ b/.github/workflows/validate-build-e2e.yml @@ -21,28 +21,38 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 - name: Set up .NET Core 3.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '3.1.x' - name: Set up .NET Core 2.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '2.1.x' - name: Set up .NET 6.0 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '6.0.x' + - name: Set up .NET 8.0 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + + - name: Set up .NET 10.0 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + - name: Restore dependencies run: dotnet restore $solution diff --git a/.github/workflows/validate-build.yml b/.github/workflows/validate-build.yml index dffb0cad4..943a74b6a 100644 --- a/.github/workflows/validate-build.yml +++ b/.github/workflows/validate-build.yml @@ -21,28 +21,38 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 - name: Set up .NET Core 3.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '3.1.x' - name: Set up .NET Core 2.1 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '2.1.x' - name: Set up .NET 6.0 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '6.0.x' + - name: Set up .NET 8.0 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + + - name: Set up .NET 10.0 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + - name: Restore dependencies run: dotnet restore $solution diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..d1018e005 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,8 @@ + + + + true + + $(NoWarn);NU1510 + + diff --git a/Directory.Packages.props b/Directory.Packages.props index bee39f722..1835ccdc9 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -62,7 +62,7 @@ - + diff --git a/azure-pipelines-analyzer-release.yml b/azure-pipelines-analyzer-release.yml index 56fb72fc6..452a8bde4 100644 --- a/azure-pipelines-analyzer-release.yml +++ b/azure-pipelines-analyzer-release.yml @@ -27,6 +27,18 @@ steps: packageType: 'sdk' version: '6.0.x' +- task: UseDotNet@2 + displayName: 'Use the .NET 8 SDK' + inputs: + packageType: 'sdk' + version: '8.0.x' + +- task: UseDotNet@2 + displayName: 'Use the .NET 10 SDK' + inputs: + packageType: 'sdk' + version: '10.0.x' + # Use NuGet - task: NuGetToolInstaller@1 displayName: 'Use NuGet ' diff --git a/azure-pipelines-release-dotnet-isolated.yml b/azure-pipelines-release-dotnet-isolated.yml index 61cd68644..3aa10813a 100644 --- a/azure-pipelines-release-dotnet-isolated.yml +++ b/azure-pipelines-release-dotnet-isolated.yml @@ -14,6 +14,18 @@ steps: packageType: 'sdk' version: '6.0.x' +- task: UseDotNet@2 + displayName: 'Use the .NET 8 SDK' + inputs: + packageType: 'sdk' + version: '8.0.x' + +- task: UseDotNet@2 + displayName: 'Use the .NET 10 SDK' + inputs: + packageType: 'sdk' + version: '10.0.x' + # Start by restoring all the .NET Isolated worker extension dependencies. This needs to be its own task. - task: DotNetCoreCLI@2 displayName: 'Restore nuget dependencies' diff --git a/azure-pipelines-release-nightly.yml b/azure-pipelines-release-nightly.yml index 81ee08c88..54df1adbc 100644 --- a/azure-pipelines-release-nightly.yml +++ b/azure-pipelines-release-nightly.yml @@ -41,6 +41,18 @@ steps: packageType: 'sdk' version: '6.0.x' +- task: UseDotNet@2 + displayName: 'Use the .NET 8 SDK' + inputs: + packageType: 'sdk' + version: '8.0.x' + +- task: UseDotNet@2 + displayName: 'Use the .NET 10 SDK' + inputs: + packageType: 'sdk' + version: '10.0.x' + # Use NuGet - task: NuGetToolInstaller@1 displayName: 'Use NuGet ' diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 6dc866632..33c7906a1 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -38,6 +38,18 @@ steps: packageType: 'sdk' version: '6.0.x' +- task: UseDotNet@2 + displayName: 'Use the .NET 8 SDK' + inputs: + packageType: 'sdk' + version: '8.0.x' + +- task: UseDotNet@2 + displayName: 'Use the .NET 10 SDK' + inputs: + packageType: 'sdk' + version: '10.0.x' + # Use NuGet - task: NuGetToolInstaller@1 displayName: 'Use NuGet ' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5ab030524..b004f8561 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -23,6 +23,18 @@ jobs: packageType: 'sdk' version: '6.0.x' + - task: UseDotNet@2 + displayName: 'Use the .NET 8 SDK' + inputs: + packageType: 'sdk' + version: '8.0.x' + + - task: UseDotNet@2 + displayName: 'Use the .NET 10 SDK' + inputs: + packageType: 'sdk' + version: '10.0.x' + - task: DotNetCoreCLI@2 inputs: command: 'restore' @@ -72,6 +84,18 @@ jobs: packageType: 'sdk' version: '6.0.x' + - task: UseDotNet@2 + displayName: 'Use the .NET 8 SDK' + inputs: + packageType: 'sdk' + version: '8.0.x' + + - task: UseDotNet@2 + displayName: 'Use the .NET 10 SDK' + inputs: + packageType: 'sdk' + version: '10.0.x' + - task: DotNetCoreCLI@2 inputs: command: 'restore' @@ -119,6 +143,18 @@ jobs: packageType: 'sdk' version: '6.0.x' + - task: UseDotNet@2 + displayName: 'Use the .NET 8 SDK' + inputs: + packageType: 'sdk' + version: '8.0.x' + + - task: UseDotNet@2 + displayName: 'Use the .NET 10 SDK' + inputs: + packageType: 'sdk' + version: '10.0.x' + - task: DotNetCoreCLI@2 inputs: command: 'restore' diff --git a/global.json b/global.json index 523ca1705..eefe68a2e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.416", + "version": "10.0.100", "rollForward": "latestFeature" }, "msbuild-sdks": { diff --git a/samples/VSSample.Tests/VSSample.Tests.csproj b/samples/VSSample.Tests/VSSample.Tests.csproj index 2f08a8f37..7eeb046d0 100644 --- a/samples/VSSample.Tests/VSSample.Tests.csproj +++ b/samples/VSSample.Tests/VSSample.Tests.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 false diff --git a/samples/distributed-tracing/v1/FunctionAppCorrelation/FunctionAppCorrelation.csproj b/samples/distributed-tracing/v1/FunctionAppCorrelation/FunctionAppCorrelation.csproj index 47b38472a..789dd1347 100644 --- a/samples/distributed-tracing/v1/FunctionAppCorrelation/FunctionAppCorrelation.csproj +++ b/samples/distributed-tracing/v1/FunctionAppCorrelation/FunctionAppCorrelation.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 true true diff --git a/samples/distributed-tracing/v2/DistributedTracingSample/DistributedTracingSample/DistributedTracingSample.csproj b/samples/distributed-tracing/v2/DistributedTracingSample/DistributedTracingSample/DistributedTracingSample.csproj index 53f20d708..79322b960 100644 --- a/samples/distributed-tracing/v2/DistributedTracingSample/DistributedTracingSample/DistributedTracingSample.csproj +++ b/samples/distributed-tracing/v2/DistributedTracingSample/DistributedTracingSample/DistributedTracingSample.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 diff --git a/samples/durable-client-managed-identity/aspnetcore-app/ToDoList.csproj b/samples/durable-client-managed-identity/aspnetcore-app/ToDoList.csproj index 5feff1383..0f69cb925 100644 --- a/samples/durable-client-managed-identity/aspnetcore-app/ToDoList.csproj +++ b/samples/durable-client-managed-identity/aspnetcore-app/ToDoList.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 diff --git a/samples/durable-client-managed-identity/functions-app/DurableClientSampleFunctionApp.csproj b/samples/durable-client-managed-identity/functions-app/DurableClientSampleFunctionApp.csproj index 3452602fb..2d54ebc4b 100644 --- a/samples/durable-client-managed-identity/functions-app/DurableClientSampleFunctionApp.csproj +++ b/samples/durable-client-managed-identity/functions-app/DurableClientSampleFunctionApp.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0 v4 diff --git a/samples/entitites-csharp/Chirper/Chirper.Service/Chirper.Service.csproj b/samples/entitites-csharp/Chirper/Chirper.Service/Chirper.Service.csproj index b26f306e5..e2aa39414 100644 --- a/samples/entitites-csharp/Chirper/Chirper.Service/Chirper.Service.csproj +++ b/samples/entitites-csharp/Chirper/Chirper.Service/Chirper.Service.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 diff --git a/samples/entitites-csharp/RideSharing/RideSharing/RideSharing.csproj b/samples/entitites-csharp/RideSharing/RideSharing/RideSharing.csproj index 2eec7a91d..da6c30546 100644 --- a/samples/entitites-csharp/RideSharing/RideSharing/RideSharing.csproj +++ b/samples/entitites-csharp/RideSharing/RideSharing/RideSharing.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 diff --git a/samples/functionapp-csharp/DurableClientSampleFunctionApp.csproj b/samples/functionapp-csharp/DurableClientSampleFunctionApp.csproj index 3452602fb..2d54ebc4b 100644 --- a/samples/functionapp-csharp/DurableClientSampleFunctionApp.csproj +++ b/samples/functionapp-csharp/DurableClientSampleFunctionApp.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0 v4 diff --git a/samples/isolated-unit-tests/IsolatedUnitTest.csproj b/samples/isolated-unit-tests/IsolatedUnitTest.csproj index 121a4ce58..b5cffb8b7 100644 --- a/samples/isolated-unit-tests/IsolatedUnitTest.csproj +++ b/samples/isolated-unit-tests/IsolatedUnitTest.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 Exe enable diff --git a/samples/precompiled/VSSample.csproj b/samples/precompiled/VSSample.csproj index 8fc211d60..b4b6e78c8 100644 --- a/samples/precompiled/VSSample.csproj +++ b/samples/precompiled/VSSample.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 diff --git a/samples/todolist-aspnetcore/ToDoList.csproj b/samples/todolist-aspnetcore/ToDoList.csproj index a320b15e8..9ad0c3791 100644 --- a/samples/todolist-aspnetcore/ToDoList.csproj +++ b/samples/todolist-aspnetcore/ToDoList.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 diff --git a/src/DurableFunctions.TypedInterfaces/Example/Calculator.cs b/src/DurableFunctions.TypedInterfaces/Example/Calculator.cs index eb4efd470..f3617c38b 100644 --- a/src/DurableFunctions.TypedInterfaces/Example/Calculator.cs +++ b/src/DurableFunctions.TypedInterfaces/Example/Calculator.cs @@ -85,7 +85,7 @@ [ActivityTrigger] IDurableActivityContext context // Don't add trigger attribute [FunctionName("Divide")] public Task Divide( - [ActivityTrigger] IDurableActivityContext context + IDurableActivityContext context ) { return Task.FromResult(0); diff --git a/src/DurableFunctions.TypedInterfaces/Example/DurableFunctions.TypedInterfaces.Example.csproj b/src/DurableFunctions.TypedInterfaces/Example/DurableFunctions.TypedInterfaces.Example.csproj index f16261d7a..ab5110c28 100644 --- a/src/DurableFunctions.TypedInterfaces/Example/DurableFunctions.TypedInterfaces.Example.csproj +++ b/src/DurableFunctions.TypedInterfaces/Example/DurableFunctions.TypedInterfaces.Example.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 v4 true $(BaseIntermediateOutputPath)Generated diff --git a/src/WebJobs.Extensions.DurableTask/LocalHttpListener.cs b/src/WebJobs.Extensions.DurableTask/LocalHttpListener.cs index 2d0c4662f..bca2bb437 100644 --- a/src/WebJobs.Extensions.DurableTask/LocalHttpListener.cs +++ b/src/WebJobs.Extensions.DurableTask/LocalHttpListener.cs @@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.WebApiCompatShim; +using Microsoft.Extensions.Hosting; namespace Microsoft.Azure.WebJobs.Extensions.DurableTask { @@ -34,7 +35,13 @@ internal class LocalHttpListener : IDisposable private readonly Random portGenerator; private readonly HashSet attemptedPorts; +#if NET6_0 +#pragma warning disable ASPDEPR004 // Type 'IWebHost' is obsolete private IWebHost localWebHost; +#pragma warning restore ASPDEPR004 +#else + private IHost localWebHost; +#endif public LocalHttpListener( EndToEndTraceHelper traceHelper, @@ -47,7 +54,13 @@ public LocalHttpListener( // Set to a non null value this.InternalRpcUri = new Uri($"http://uninitialized"); +#if NET6_0 +#pragma warning disable ASPDEPR004 // Type 'IWebHost' is obsolete this.localWebHost = new NoOpWebHost(); +#pragma warning restore ASPDEPR004 +#else + this.localWebHost = new NoOpHost(); +#endif this.portGenerator = new Random(); this.attemptedPorts = new HashSet(); } @@ -76,6 +89,10 @@ public async Task StartAsync() { this.InternalRpcUri = new Uri($"http://127.0.0.1:{listeningPort}/durabletask/"); var listenUri = new Uri(this.InternalRpcUri.GetLeftPart(UriPartial.Authority)); + +#if NET6_0 + // Use legacy WebHostBuilder for .NET 6 (IWebHost is obsolete in .NET 10+) +#pragma warning disable ASPDEPR008 // Type 'WebHostBuilder' is obsolete this.localWebHost = new WebHostBuilder() .UseKestrel() .ConfigureKestrel(o => @@ -86,7 +103,22 @@ public async Task StartAsync() .UseUrls(listenUri.OriginalString) .Configure(a => a.Run(this.HandleRequestAsync)) .Build(); - +#pragma warning restore ASPDEPR008 +#else + // Use modern WebApplication for .NET 8+ + var builder = WebApplication.CreateSlimBuilder(); + builder.WebHost.UseKestrel(o => + { + // remove request's Content size limits + o.Limits.MaxRequestBodySize = null; + }); + builder.WebHost.UseUrls(listenUri.OriginalString); + + var app = builder.Build(); + app.Run(this.HandleRequestAsync); + + this.localWebHost = app; +#endif await this.localWebHost.StartAsync(); this.IsListening = true; break; @@ -180,6 +212,8 @@ private static async Task SetResponseAsync(HttpContext context, HttpResponseMess } } +#if NET6_0 +#pragma warning disable ASPDEPR004 // Type 'IWebHost' is obsolete private class NoOpWebHost : IWebHost { public IFeatureCollection ServerFeatures => throw new NotImplementedException(); @@ -194,5 +228,18 @@ public void Start() { } public Task StopAsync(CancellationToken cancellationToken = default(CancellationToken)) => Task.CompletedTask; } +#pragma warning restore ASPDEPR004 +#else + private class NoOpHost : IHost + { + public IServiceProvider Services => throw new NotImplementedException(); + + public void Dispose() { } + + public Task StartAsync(CancellationToken cancellationToken = default(CancellationToken)) => Task.CompletedTask; + + public Task StopAsync(CancellationToken cancellationToken = default(CancellationToken)) => Task.CompletedTask; + } +#endif } } \ No newline at end of file diff --git a/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj b/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj index a954508ba..deb4e0f86 100644 --- a/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj +++ b/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj @@ -1,7 +1,7 @@  - net8.0 + net6.0;net8.0;net10.0 Microsoft.Azure.WebJobs.Extensions.DurableTask Microsoft.Azure.WebJobs.Extensions.DurableTask 3 @@ -18,7 +18,8 @@ true embedded - NU5125;SA0001 + + NU5125;SA0001;NU1510 diff --git a/src/Worker.Extensions.DurableTask/Worker.Extensions.DurableTask.csproj b/src/Worker.Extensions.DurableTask/Worker.Extensions.DurableTask.csproj index 58756f9bf..79a8f2a2d 100644 --- a/src/Worker.Extensions.DurableTask/Worker.Extensions.DurableTask.csproj +++ b/src/Worker.Extensions.DurableTask/Worker.Extensions.DurableTask.csproj @@ -2,7 +2,7 @@ - netstandard2.0;net8.0 + netstandard2.0;net6.0;net8.0;net10.0 latest enable embedded diff --git a/test/CodeGen.Example.Test/DurableFunctions.TypedInterfaces.Examples.Test.csproj b/test/CodeGen.Example.Test/DurableFunctions.TypedInterfaces.Examples.Test.csproj index 25863ad1f..1382b9e44 100644 --- a/test/CodeGen.Example.Test/DurableFunctions.TypedInterfaces.Examples.Test.csproj +++ b/test/CodeGen.Example.Test/DurableFunctions.TypedInterfaces.Examples.Test.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 Microsoft Corporation SA0001;SA1600;SA1615 true diff --git a/test/CodeGen.SourceGenerator.Test/DurableFunctions.TypedInterfaces.SourceGenerator.Test.csproj b/test/CodeGen.SourceGenerator.Test/DurableFunctions.TypedInterfaces.SourceGenerator.Test.csproj index 8ec718f4b..5a2f1e24d 100644 --- a/test/CodeGen.SourceGenerator.Test/DurableFunctions.TypedInterfaces.SourceGenerator.Test.csproj +++ b/test/CodeGen.SourceGenerator.Test/DurableFunctions.TypedInterfaces.SourceGenerator.Test.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 Microsoft Corporation SA0001;SA1600;SA1615 true diff --git a/test/CodeGen.SourceGenerator.Test/Utils/ProjectUtility.cs b/test/CodeGen.SourceGenerator.Test/Utils/ProjectUtility.cs index aaa141001..d8a63e1e0 100644 --- a/test/CodeGen.SourceGenerator.Test/Utils/ProjectUtility.cs +++ b/test/CodeGen.SourceGenerator.Test/Utils/ProjectUtility.cs @@ -1,16 +1,26 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. +using System.IO; +using System.Reflection; using DurableFunctions.TypedInterfaces.SourceGenerator.Tests.Models; namespace WebJobs.Extensions.DurableTask.CodeGen.SourceGenerator.Test.Utils { internal class ProjectUtility { - private const string ProjectFilePath = @"..\..\..\..\..\src\DurableFunctions.TypedInterfaces\WebJobs.Extensions.DurableTask.CodeGen.Example\WebJobs.Extensions.DurableTask.CodeGen.Example.csproj"; + private const string RelativeProjectFilePath = @"../../../../../src/DurableFunctions.TypedInterfaces/Example/DurableFunctions.TypedInterfaces.Example.csproj"; private static CompiledProject instance; - public static CompiledProject CompiledProject => instance ??= new CompiledProject(ProjectFilePath); + public static CompiledProject CompiledProject => instance ??= new CompiledProject(GetProjectFilePath()); + + private static string GetProjectFilePath() + { + // Get the directory where the test assembly is located + var assemblyLocation = Assembly.GetExecutingAssembly().Location; + var assemblyDirectory = Path.GetDirectoryName(assemblyLocation); + return Path.GetFullPath(Path.Combine(assemblyDirectory!, RelativeProjectFilePath)); + } } } diff --git a/test/Common/DurableTaskEndToEndTests.cs b/test/Common/DurableTaskEndToEndTests.cs index 0b283869e..26602d65d 100644 --- a/test/Common/DurableTaskEndToEndTests.cs +++ b/test/Common/DurableTaskEndToEndTests.cs @@ -29,6 +29,10 @@ using Xunit.Abstractions; using Xunit.Sdk; +#if NET10_0_OR_GREATER +using AsyncLinq = System.Linq.AsyncEnumerable; +#endif + namespace Microsoft.Azure.WebJobs.Extensions.DurableTask.Tests { public class DurableTaskEndToEndTests : IDisposable @@ -5231,13 +5235,13 @@ public async Task MaxOrchestrationAction_MaxReached_OrchestrationFails() [MemberData(nameof(TestDataGenerator.GetBooleanAndFullFeaturedStorageProviderOptions), MemberType = typeof(TestDataGenerator))] public async Task Dedupe_Default_NotRunning_ThrowsException(bool extendedSessions, string storageProvider) { - var instanceId = "OverridableStatesDefaultTest_" + Guid.NewGuid().ToString("N"); + var instanceId = "OverridableStatesDefaultTest_" + Guid.NewGuid().ToString("N"); - using (ITestHost host = TestHelpers.GetJobHost( - this.loggerProvider, - nameof(this.Dedupe_Default_NotRunning_ThrowsException), - extendedSessions, - storageProviderType: storageProvider)) + using (ITestHost host = TestHelpers.GetJobHost( + this.loggerProvider, + nameof(this.Dedupe_Default_NotRunning_ThrowsException), + extendedSessions, + storageProviderType: storageProvider)) { await host.StartAsync(); @@ -5940,7 +5944,11 @@ private static async Task GetBlobCount(string containerName, string directo BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName); await containerClient.CreateIfNotExistsAsync(); +#if NET10_0_OR_GREATER + return await AsyncLinq.CountAsync(containerClient.GetBlobsAsync()); +#else return await containerClient.GetBlobsAsync().CountAsync(); +#endif } private static async Task EnsureBlobContainerExists(string containerName) diff --git a/test/DFPerfScenarios/DFPerfScenariosV4.csproj b/test/DFPerfScenarios/DFPerfScenariosV4.csproj index 58843db29..bce83e9ce 100644 --- a/test/DFPerfScenarios/DFPerfScenariosV4.csproj +++ b/test/DFPerfScenarios/DFPerfScenariosV4.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 diff --git a/test/Directory.Packages.props b/test/Directory.Packages.props index e6d293bd2..d7b39ad0a 100644 --- a/test/Directory.Packages.props +++ b/test/Directory.Packages.props @@ -22,9 +22,10 @@ - + + diff --git a/test/FunctionsV2/TestCleanup.cs b/test/FunctionsV2/TestCleanup.cs index b7072d590..8ffc7c09c 100644 --- a/test/FunctionsV2/TestCleanup.cs +++ b/test/FunctionsV2/TestCleanup.cs @@ -14,6 +14,10 @@ using Xunit; using Xunit.Abstractions; +#if NET10_0_OR_GREATER +using AsyncLinq = System.Linq.AsyncEnumerable; +#endif + namespace WebJobs.Extensions.DurableTask.Tests.V2 { public class TestCleanup @@ -46,6 +50,18 @@ public async Task CleanupOldAzureStorageTaskHubs() this.output.WriteLine($"Using storage account: {blobServiceClient.AccountName}"); +#if NET10_0_OR_GREATER + List taskHubsToDelete = await AsyncLinq.ToListAsync( + AsyncLinq.Take( + AsyncLinq.Select( + AsyncLinq.Where( + AsyncLinq.Where( + blobServiceClient.GetBlobContainersAsync(), + c => c.Name.Contains("-leases", StringComparison.Ordinal)), + c => DateTimeOffset.UtcNow.Subtract(c.Properties.LastModified) > oldTaskHubDeletionThreshold), + c => c.Name[..c.Name.IndexOf("-leases")]), + maxDeletedTaskHubs)); +#else List taskHubsToDelete = await blobServiceClient .GetBlobContainersAsync() .Where(c => c.Name.Contains("-leases", StringComparison.Ordinal)) @@ -53,6 +69,7 @@ public async Task CleanupOldAzureStorageTaskHubs() .Select(c => c.Name[..c.Name.IndexOf("-leases")]) .Take(maxDeletedTaskHubs) .ToListAsync(); +#endif await Task.WhenAll(taskHubsToDelete.Select(taskHub => this.DeleteTaskHub(taskHub, connectionString))); } diff --git a/test/FunctionsV2/WebJobs.Extensions.DurableTask.Tests.V2.csproj b/test/FunctionsV2/WebJobs.Extensions.DurableTask.Tests.V2.csproj index 6da4632cc..43449dbac 100644 --- a/test/FunctionsV2/WebJobs.Extensions.DurableTask.Tests.V2.csproj +++ b/test/FunctionsV2/WebJobs.Extensions.DurableTask.Tests.V2.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 Microsoft Corporation SA0001;SA1600;SA1615 true @@ -30,6 +30,11 @@ + + + + + diff --git a/test/PerfTests/DFPerfTests/perf.csproj b/test/PerfTests/DFPerfTests/perf.csproj index 8f5f2648d..fdacce4a7 100644 --- a/test/PerfTests/DFPerfTests/perf.csproj +++ b/test/PerfTests/DFPerfTests/perf.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0 v4 diff --git a/test/PerfTests/JavaScript/extensions.csproj b/test/PerfTests/JavaScript/extensions.csproj index 94bdf4478..c0f5e1f74 100644 --- a/test/PerfTests/JavaScript/extensions.csproj +++ b/test/PerfTests/JavaScript/extensions.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 ** diff --git a/test/PerfTests/Python/extensions.csproj b/test/PerfTests/Python/extensions.csproj index 94bdf4478..c0f5e1f74 100644 --- a/test/PerfTests/Python/extensions.csproj +++ b/test/PerfTests/Python/extensions.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 ** diff --git a/test/SmokeTests/BackendSmokeTests/MSSQL/Dockerfile b/test/SmokeTests/BackendSmokeTests/MSSQL/Dockerfile index 977a65094..8af95c287 100644 --- a/test/SmokeTests/BackendSmokeTests/MSSQL/Dockerfile +++ b/test/SmokeTests/BackendSmokeTests/MSSQL/Dockerfile @@ -1,16 +1,17 @@ # Copyright (c) .NET Foundation. All rights reserved. # Licensed under the MIT License. See LICENSE in the project root for license information. -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build-env # Build the DF MSSQL app COPY . /root RUN cd /root/test/SmokeTests/BackendSmokeTests/MSSQL && \ mkdir -p /home/site/wwwroot && \ - dotnet publish -c Release --output /home/site/wwwroot + dotnet publish -c Release -f net10.0 --output /home/site/wwwroot # Deploy the app -FROM mcr.microsoft.com/azure-functions/dotnet:4-dotnet8 +FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated10.0 ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ - AzureFunctionsJobHost__Logging__Console__IsEnabled=true + AzureFunctionsJobHost__Logging__Console__IsEnabled=true \ + FUNCTIONS_WORKER_RUNTIME=dotnet-isolated COPY --from=build-env ["/home/site/wwwroot", "/home/site/wwwroot"] diff --git a/test/SmokeTests/BackendSmokeTests/MSSQL/DurableFunctionsOrchestrationCSharp..cs b/test/SmokeTests/BackendSmokeTests/MSSQL/DurableFunctionsOrchestrationCSharp..cs deleted file mode 100644 index 3caf1d11b..000000000 --- a/test/SmokeTests/BackendSmokeTests/MSSQL/DurableFunctionsOrchestrationCSharp..cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.DurableTask; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.Azure.WebJobs.Host; -using Microsoft.Extensions.Logging; - -namespace MSSQL -{ - public static class DurableFunctionsOrchestrationCSharp - { - [FunctionName("DurableFunctionsOrchestrationCSharp")] - public static async Task> RunOrchestrator( - [OrchestrationTrigger] IDurableOrchestrationContext context) - { - var outputs = new List(); - - // Replace "hello" with the name of your Durable Activity Function. - outputs.Add(await context.CallActivityAsync(nameof(SayHello), "Tokyo")); - outputs.Add(await context.CallActivityAsync(nameof(SayHello), "Seattle")); - outputs.Add(await context.CallActivityAsync(nameof(SayHello), "London")); - - // returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"] - return outputs; - } - - [FunctionName(nameof(SayHello))] - public static string SayHello([ActivityTrigger] string name, ILogger log) - { - log.LogInformation("Saying hello to {name}.", name); - return $"Hello {name}!"; - } - - [FunctionName("DurableFunctionsHttpStart")] - public static async Task HttpStart( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req, - [DurableClient] IDurableOrchestrationClient starter, - ILogger log) - { - // Function input comes from the request content. - string instanceId = await starter.StartNewAsync("DurableFunctionsOrchestrationCSharp", null); - - log.LogInformation("Started orchestration with ID = '{instanceId}'.", instanceId); - - return starter.CreateCheckStatusResponse(req, instanceId); - } - } -} diff --git a/test/SmokeTests/BackendSmokeTests/MSSQL/DurableFunctionsOrchestrationCSharp.cs b/test/SmokeTests/BackendSmokeTests/MSSQL/DurableFunctionsOrchestrationCSharp.cs new file mode 100644 index 000000000..fc8e69d3f --- /dev/null +++ b/test/SmokeTests/BackendSmokeTests/MSSQL/DurableFunctionsOrchestrationCSharp.cs @@ -0,0 +1,58 @@ +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.DurableTask; +using Microsoft.DurableTask.Client; +using Microsoft.Extensions.Logging; + +namespace MSSQL; + +public static class DurableFunctionsOrchestrationCSharp +{ + /// + /// Orchestrates a simple fan-out using the SQL Server provider. + /// + [Function(nameof(DurableFunctionsOrchestrationCSharp))] + public static async Task> RunOrchestrator( + [OrchestrationTrigger] TaskOrchestrationContext context) + { + ILogger logger = context.CreateReplaySafeLogger(nameof(DurableFunctionsOrchestrationCSharp)); + logger.LogInformation("Running SQL Server orchestration sample."); + + var outputs = new List + { + await context.CallActivityAsync(nameof(SayHello), "Tokyo"), + await context.CallActivityAsync(nameof(SayHello), "Seattle"), + await context.CallActivityAsync(nameof(SayHello), "London"), + }; + + return outputs; + } + + /// + /// Activity that returns a greeting for the requested city. + /// + [Function(nameof(SayHello))] + public static string SayHello([ActivityTrigger] string name, FunctionContext context) + { + ILogger logger = context.GetLogger(nameof(SayHello)); + logger.LogInformation("Saying hello to {name}.", name); + return $"Hello {name}!"; + } + + /// + /// HTTP starter that schedules the orchestration and returns management URLs. + /// + [Function("DurableFunctionsHttpStart")] + public static async Task HttpStart( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req, + [DurableClient] DurableTaskClient client, + FunctionContext context) + { + ILogger logger = context.GetLogger(nameof(HttpStart)); + + string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(nameof(DurableFunctionsOrchestrationCSharp)); + logger.LogInformation("Started orchestration with ID = '{instanceId}'.", instanceId); + + return await client.CreateCheckStatusResponseAsync(req, instanceId); + } +} diff --git a/test/SmokeTests/BackendSmokeTests/MSSQL/MSSQL.csproj b/test/SmokeTests/BackendSmokeTests/MSSQL/MSSQL.csproj index 1c48ffee8..a27275df1 100644 --- a/test/SmokeTests/BackendSmokeTests/MSSQL/MSSQL.csproj +++ b/test/SmokeTests/BackendSmokeTests/MSSQL/MSSQL.csproj @@ -1,18 +1,21 @@ - net8.0 + net10.0 v4 - - - - false + Exe + enable + enable + latest - + - - + + + + + diff --git a/test/SmokeTests/BackendSmokeTests/MSSQL/Program.cs b/test/SmokeTests/BackendSmokeTests/MSSQL/Program.cs new file mode 100644 index 000000000..a9f3b9bc5 --- /dev/null +++ b/test/SmokeTests/BackendSmokeTests/MSSQL/Program.cs @@ -0,0 +1,8 @@ +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Hosting; + +var host = new HostBuilder() + .ConfigureFunctionsWebApplication() + .Build(); + +host.Run(); diff --git a/test/SmokeTests/BackendSmokeTests/Netherite/Dockerfile b/test/SmokeTests/BackendSmokeTests/Netherite/Dockerfile index d0f44a7d4..80144d887 100644 --- a/test/SmokeTests/BackendSmokeTests/Netherite/Dockerfile +++ b/test/SmokeTests/BackendSmokeTests/Netherite/Dockerfile @@ -1,16 +1,17 @@ # Copyright (c) .NET Foundation. All rights reserved. # Licensed under the MIT License. See LICENSE in the project root for license information. -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build-env # Build the app COPY . /root RUN cd /root/test/SmokeTests/BackendSmokeTests/Netherite && \ mkdir -p /home/site/wwwroot && \ - dotnet publish -c Release --output /home/site/wwwroot + dotnet publish -c Release -f net10.0 --output /home/site/wwwroot # Deploy the app -FROM mcr.microsoft.com/azure-functions/dotnet:4-dotnet8.0 +FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated10.0 ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ - AzureFunctionsJobHost__Logging__Console__IsEnabled=true + AzureFunctionsJobHost__Logging__Console__IsEnabled=true \ + FUNCTIONS_WORKER_RUNTIME=dotnet-isolated COPY --from=build-env ["/home/site/wwwroot", "/home/site/wwwroot"] diff --git a/test/SmokeTests/BackendSmokeTests/Netherite/DurableFunctionsOrchestrationCSharp.cs b/test/SmokeTests/BackendSmokeTests/Netherite/DurableFunctionsOrchestrationCSharp.cs index 5dc6d7c3e..8e44e9ed2 100644 --- a/test/SmokeTests/BackendSmokeTests/Netherite/DurableFunctionsOrchestrationCSharp.cs +++ b/test/SmokeTests/BackendSmokeTests/Netherite/DurableFunctionsOrchestrationCSharp.cs @@ -1,50 +1,58 @@ -using System.Collections.Generic; -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.DurableTask; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.Azure.WebJobs.Host; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.DurableTask; +using Microsoft.DurableTask.Client; using Microsoft.Extensions.Logging; -namespace Company.Function +namespace Netherite; + +public static class DurableFunctionsOrchestrationCSharp { - public static class DurableFunctionsOrchestrationCSharp + /// + /// Orchestrates a simple fan-out using Netherite storage provider. + /// + [Function(nameof(DurableFunctionsOrchestrationCSharp))] + public static async Task> RunOrchestrator( + [OrchestrationTrigger] TaskOrchestrationContext context) { - [FunctionName("DurableFunctionsOrchestrationCSharp")] - public static async Task> RunOrchestrator( - [OrchestrationTrigger] IDurableOrchestrationContext context) + ILogger logger = context.CreateReplaySafeLogger(nameof(DurableFunctionsOrchestrationCSharp)); + logger.LogInformation("Running Netherite orchestration sample."); + + var outputs = new List { - var outputs = new List(); + await context.CallActivityAsync(nameof(SayHello), "Tokyo"), + await context.CallActivityAsync(nameof(SayHello), "Seattle"), + await context.CallActivityAsync(nameof(SayHello), "London"), + }; - // Replace "hello" with the name of your Durable Activity Function. - outputs.Add(await context.CallActivityAsync(nameof(SayHello), "Tokyo")); - outputs.Add(await context.CallActivityAsync(nameof(SayHello), "Seattle")); - outputs.Add(await context.CallActivityAsync(nameof(SayHello), "London")); + return outputs; + } - // returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"] - return outputs; - } + /// + /// Activity that returns a greeting for the requested city. + /// + [Function(nameof(SayHello))] + public static string SayHello([ActivityTrigger] string name, FunctionContext context) + { + ILogger logger = context.GetLogger(nameof(SayHello)); + logger.LogInformation("Saying hello to {name}.", name); + return $"Hello {name}!"; + } - [FunctionName(nameof(SayHello))] - public static string SayHello([ActivityTrigger] string name, ILogger log) - { - log.LogInformation("Saying hello to {name}.", name); - return $"Hello {name}!"; - } - - [FunctionName("DurableFunctionsHttpStart")] - public static async Task HttpStart( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req, - [DurableClient] IDurableOrchestrationClient starter, - ILogger log) - { - // Function input comes from the request content. - string instanceId = await starter.StartNewAsync("DurableFunctionsOrchestrationCSharp", null); + /// + /// HTTP starter that schedules the orchestration and returns management URLs. + /// + [Function("DurableFunctionsHttpStart")] + public static async Task HttpStart( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req, + [DurableClient] DurableTaskClient client, + FunctionContext context) + { + ILogger logger = context.GetLogger(nameof(HttpStart)); - log.LogInformation("Started orchestration with ID = '{instanceId}'.", instanceId); + string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(nameof(DurableFunctionsOrchestrationCSharp)); + logger.LogInformation("Started orchestration with ID = '{instanceId}'.", instanceId); - return starter.CreateCheckStatusResponse(req, instanceId); - } + return await client.CreateCheckStatusResponseAsync(req, instanceId); } } \ No newline at end of file diff --git a/test/SmokeTests/BackendSmokeTests/Netherite/Netherite.csproj b/test/SmokeTests/BackendSmokeTests/Netherite/Netherite.csproj index 219a0e193..70b38b1a1 100644 --- a/test/SmokeTests/BackendSmokeTests/Netherite/Netherite.csproj +++ b/test/SmokeTests/BackendSmokeTests/Netherite/Netherite.csproj @@ -1,16 +1,21 @@ - net8.0 + net10.0 v4 - - - - false + Exe + enable + enable + latest - - - + + + + + + + + diff --git a/test/SmokeTests/BackendSmokeTests/Netherite/Program.cs b/test/SmokeTests/BackendSmokeTests/Netherite/Program.cs new file mode 100644 index 000000000..a9f3b9bc5 --- /dev/null +++ b/test/SmokeTests/BackendSmokeTests/Netherite/Program.cs @@ -0,0 +1,8 @@ +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Hosting; + +var host = new HostBuilder() + .ConfigureFunctionsWebApplication() + .Build(); + +host.Run(); diff --git a/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/Dockerfile b/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/Dockerfile index b06d1727c..abc00a2db 100644 --- a/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/Dockerfile +++ b/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/Dockerfile @@ -1,7 +1,7 @@ # Copyright (c) .NET Foundation. All rights reserved. # Licensed under the MIT License. See LICENSE in the project root for license information. -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build-env # Step 1: Build the WebJobs extension and publish it as a local NuGet package COPY . /root @@ -20,13 +20,13 @@ RUN cd /root/src/WebJobs.Extensions.DurableTask && \ RUN cd /root/test/SmokeTests/OOProcSmokeTests/DotNetIsolated && \ mkdir -p /home/site/wwwroot && \ dotnet restore --verbosity normal && \ - dotnet build -c Release && \ - dotnet publish -c Release --no-build --output /home/site/wwwroot && \ + dotnet build -c Release -f net10.0 && \ + dotnet publish -c Release -f net10.0 --no-build --output /home/site/wwwroot && \ ls -aR /home/site/wwwroot && \ cat /home/site/wwwroot/extensions.json # debugging # Step 3: Generate the final app image to run -FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0 +FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated10.0 # This is the standard setup for Azure Functions running in Docker containers ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ diff --git a/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/DotNetIsolated.csproj b/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/DotNetIsolated.csproj index 09fa60fed..e31a46064 100644 --- a/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/DotNetIsolated.csproj +++ b/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/DotNetIsolated.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 exe false diff --git a/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/run-smoke-tests.ps1 b/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/run-smoke-tests.ps1 index 408e0eace..a1673321f 100644 --- a/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/run-smoke-tests.ps1 +++ b/test/SmokeTests/OOProcSmokeTests/DotNetIsolated/run-smoke-tests.ps1 @@ -110,7 +110,7 @@ Do { # We stop the host process and wait for a bit before checking if it is running again. Write-Host "Restarting the Functions host..." -ForegroundColor Yellow - Stop-Process -Name "func" -Force + Stop-Process -Name "func" -Force -ErrorAction SilentlyContinue Start-Sleep -Seconds 5 # Log whether the process kill succeeded diff --git a/test/SmokeTests/OOProcSmokeTests/durableJS/Dockerfile b/test/SmokeTests/OOProcSmokeTests/durableJS/Dockerfile index cde3ad7b5..6f178ae47 100644 --- a/test/SmokeTests/OOProcSmokeTests/durableJS/Dockerfile +++ b/test/SmokeTests/OOProcSmokeTests/durableJS/Dockerfile @@ -3,13 +3,13 @@ # Step 1: Add the durable extension by building it locally. # This is an alternative to "func extensions install" -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build-env COPY . /root RUN cd /root/test/SmokeTests/OOProcSmokeTests/durableJS && \ dotnet build -o bin # Step 2: Deploy and run npm install to get the Durable Functions SDK -FROM mcr.microsoft.com/azure-functions/node:4-node20 +FROM mcr.microsoft.com/azure-functions/node:4-node24 COPY --from=build-env /root/test/SmokeTests/OOProcSmokeTests/durableJS /home/site/wwwroot ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ AzureFunctionsJobHost__Logging__Console__IsEnabled=true diff --git a/test/SmokeTests/OOProcSmokeTests/durableJS/extensions.csproj b/test/SmokeTests/OOProcSmokeTests/durableJS/extensions.csproj index 9ef7d086c..43ae20a6c 100644 --- a/test/SmokeTests/OOProcSmokeTests/durableJS/extensions.csproj +++ b/test/SmokeTests/OOProcSmokeTests/durableJS/extensions.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 ** diff --git a/test/SmokeTests/OOProcSmokeTests/durableJava/Dockerfile b/test/SmokeTests/OOProcSmokeTests/durableJava/Dockerfile index 36c1e8eff..b7479923a 100644 --- a/test/SmokeTests/OOProcSmokeTests/durableJava/Dockerfile +++ b/test/SmokeTests/OOProcSmokeTests/durableJava/Dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build-env COPY . /root RUN cd /root/test/SmokeTests/OOProcSmokeTests/durableJava && \ dotnet build -o bin -FROM mcr.microsoft.com/azure-functions/java:4-java8 +FROM mcr.microsoft.com/azure-functions/java:4-java17 # Copy the bin folder generated at /root/test/SmokeTests/OOProcSmokeTests/durableJava COPY --from=build-env /root/test/SmokeTests/OOProcSmokeTests/durableJava /home/site/wwwroot diff --git a/test/SmokeTests/OOProcSmokeTests/durableJava/Nuget.config b/test/SmokeTests/OOProcSmokeTests/durableJava/Nuget.config index f137fb6a1..f46190d31 100644 --- a/test/SmokeTests/OOProcSmokeTests/durableJava/Nuget.config +++ b/test/SmokeTests/OOProcSmokeTests/durableJava/Nuget.config @@ -6,4 +6,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/SmokeTests/OOProcSmokeTests/durableJava/extensions.csproj b/test/SmokeTests/OOProcSmokeTests/durableJava/extensions.csproj index e77a6f488..f845c88a9 100644 --- a/test/SmokeTests/OOProcSmokeTests/durableJava/extensions.csproj +++ b/test/SmokeTests/OOProcSmokeTests/durableJava/extensions.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 ** diff --git a/test/SmokeTests/OOProcSmokeTests/durablePy/Dockerfile b/test/SmokeTests/OOProcSmokeTests/durablePy/Dockerfile index 253ea274c..98a3e8f55 100644 --- a/test/SmokeTests/OOProcSmokeTests/durablePy/Dockerfile +++ b/test/SmokeTests/OOProcSmokeTests/durablePy/Dockerfile @@ -3,13 +3,13 @@ # Step 1: Add the durable extension by building it locally. # This is an alternative to "func extensions install" -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build-env COPY . /root RUN cd /root/test/SmokeTests/OOProcSmokeTests/durablePy && \ dotnet build -o bin # Step 2: Deploy and run pip install to get the Durable Functions SDK -FROM mcr.microsoft.com/azure-functions/python:4-python3.7 +FROM mcr.microsoft.com/azure-functions/python:4-python3.11 COPY --from=build-env /root/test/SmokeTests/OOProcSmokeTests/durablePy /home/site/wwwroot ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ AzureFunctionsJobHost__Logging__Console__IsEnabled=true diff --git a/test/SmokeTests/OOProcSmokeTests/durablePy/Nuget.config b/test/SmokeTests/OOProcSmokeTests/durablePy/Nuget.config index f137fb6a1..f46190d31 100644 --- a/test/SmokeTests/OOProcSmokeTests/durablePy/Nuget.config +++ b/test/SmokeTests/OOProcSmokeTests/durablePy/Nuget.config @@ -6,4 +6,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/SmokeTests/OOProcSmokeTests/durablePy/extensions.csproj b/test/SmokeTests/OOProcSmokeTests/durablePy/extensions.csproj index 5355a99ef..271266d62 100644 --- a/test/SmokeTests/OOProcSmokeTests/durablePy/extensions.csproj +++ b/test/SmokeTests/OOProcSmokeTests/durablePy/extensions.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 ** diff --git a/test/SmokeTests/e2e-test.ps1 b/test/SmokeTests/e2e-test.ps1 index aa7759fff..feb029f37 100644 --- a/test/SmokeTests/e2e-test.ps1 +++ b/test/SmokeTests/e2e-test.ps1 @@ -16,7 +16,10 @@ param( [string]$tag="2019-latest", [int]$port=1433, [string]$dbname="DurableDB", - [string]$collation="Latin1_General_100_BIN2_UTF8" + [string]$collation="Latin1_General_100_BIN2_UTF8", + [string]$ContainerEngine="docker", + [string]$Platform="", + [string]$NetheriteEventHubsConnection="UseDevelopmentStorage=true" ) function Exit-OnError() { @@ -69,32 +72,84 @@ function Start-And-Wait-Orchestration { return $false } +function Wait-ForHostPing { + param( + [string]$Uri, + [int]$MaxRetries = 20, + [int]$SleepSeconds = 3 + ) + + $attempt = 0 + while ($attempt -lt $MaxRetries) { + try { + Invoke-RestMethod -Method Post -Uri $Uri | Out-Null + Write-Host "Host responded to ping after attempt $($attempt + 1)." -ForegroundColor Yellow + return $true + } catch { + $attempt++ + Write-Host "Host not ready (attempt $attempt/$MaxRetries): $($_.Exception.Message)" -ForegroundColor Yellow + Start-Sleep -Seconds $SleepSeconds + } + } + + return $false +} + $ErrorActionPreference = "Stop" $AzuriteVersion = "3.34.0" +$engine = $ContainerEngine +$platformArgs = @() +if (-not [string]::IsNullOrWhiteSpace($Platform)) { + $platformArgs = @("--platform", $Platform) +} + if ($NoSetup -eq $false) { # Build the docker image first, since that's the most critical step Write-Host "Building sample app Docker container from '$DockerfilePath'..." -ForegroundColor Yellow - docker build --pull -f $DockerfilePath -t $ImageName --progress plain $PSScriptRoot/../../ + $buildArgs = @("build", "--pull", "-f", $DockerfilePath, "-t", $ImageName) + if ($platformArgs.Count -gt 0) { + $buildArgs += $platformArgs + } + $buildArgs += "$PSScriptRoot/../../" + & $engine @buildArgs Exit-OnError # Next, download and start the Azurite emulator Docker image Write-Host "Pulling down the mcr.microsoft.com/azure-storage/azurite:$AzuriteVersion image..." -ForegroundColor Yellow - docker pull "mcr.microsoft.com/azure-storage/azurite:${AzuriteVersion}" + $azuritePull = @("pull", "mcr.microsoft.com/azure-storage/azurite:${AzuriteVersion}") + if ($platformArgs.Count -gt 0) { + $azuritePull += $platformArgs + } + & $engine @azuritePull Exit-OnError Write-Host "Starting Azurite storage emulator using default ports..." -ForegroundColor Yellow - docker run --name 'azurite' -p 10000:10000 -p 10001:10001 -p 10002:10002 -d "mcr.microsoft.com/azure-storage/azurite:${AzuriteVersion}" + $azuriteRun = @("run", "--name", "azurite", "-p", "10000:10000", "-p", "10001:10001", "-p", "10002:10002", "-d") + if ($platformArgs.Count -gt 0) { + $azuriteRun = @("run") + $platformArgs + $azuriteRun[1..($azuriteRun.Count - 1)] + } + $azuriteRun += "mcr.microsoft.com/azure-storage/azurite:${AzuriteVersion}" + & $engine @azuriteRun Exit-OnError if ($SetupSQLServer -eq $true) { Write-Host "Pulling down the mcr.microsoft.com/mssql/server:$tag image..." - docker pull mcr.microsoft.com/mssql/server:$tag + $mssqlPull = @("pull", "mcr.microsoft.com/mssql/server:$tag") + if ($platformArgs.Count -gt 0) { + $mssqlPull += $platformArgs + } + & $engine @mssqlPull Exit-OnError # Start the SQL Server docker container with the specified edition Write-Host "Starting SQL Server $tag $sqlpid docker container on port $port" -ForegroundColor DarkYellow - docker run --name mssql-server -e 'ACCEPT_EULA=Y' -e "MSSQL_SA_PASSWORD=$pw" -e "MSSQL_PID=$sqlpid" -p ${port}:1433 -d mcr.microsoft.com/mssql/server:$tag + $mssqlRun = @("run", "--name", "mssql-server", "-e", "ACCEPT_EULA=Y", "-e", "MSSQL_SA_PASSWORD=$pw", "-e", "MSSQL_PID=$sqlpid", "-p", "${port}:1433", "-d") + if ($platformArgs.Count -gt 0) { + $mssqlRun = @("run") + $platformArgs + $mssqlRun[1..($mssqlRun.Count - 1)] + } + $mssqlRun += "mcr.microsoft.com/mssql/server:$tag" + & $engine @mssqlRun Exit-OnError # Wait for SQL Server to be ready @@ -103,23 +158,23 @@ if ($NoSetup -eq $false) { Exit-OnError Write-Host "Checking if SQL Server is still running..." -ForegroundColor Yellow - $sqlServerStatus = docker inspect -f '{{.State.Status}}' mssql-server + $sqlServerStatus = & $engine inspect -f '{{.State.Status}}' mssql-server Exit-OnError if ($sqlServerStatus -ne "running") { Write-Host "Unexpected SQL Server status: $sqlServerStatus" -ForegroundColor Yellow - docker logs mssql-server + & $engine logs mssql-server exit 1; } # Get SQL Server IP Address - used to create SQLDB_Connection Write-Host "Getting IP Address..." -ForegroundColor Yellow - $serverIpAddress = docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mssql-server + $serverIpAddress = & $engine inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mssql-server Exit-OnError # Create the database with strict binary collation Write-Host "Creating '$dbname' database with '$collation' collation" -ForegroundColor DarkYellow - docker exec -d mssql-server /opt/mssql-tools18/bin/sqlcmd -S . -U sa -P "$pw" -Q "CREATE DATABASE [$dbname] COLLATE $collation" + & $engine exec -d mssql-server /opt/mssql-tools18/bin/sqlcmd -S . -U sa -P "$pw" -Q "CREATE DATABASE [$dbname] COLLATE $collation" Exit-OnError # Wait for database to be ready @@ -129,19 +184,37 @@ if ($NoSetup -eq $false) { # Finally, start up the application container, connecting to the SQL Server container Write-Host "Starting the $ContainerName application container" -ForegroundColor Yellow - docker run --name $ContainerName -p 8080:80 -it --add-host=host.docker.internal:host-gateway -d ` - --env "SQLDB_Connection=Server=$serverIpAddress,1433;Database=$dbname;User=sa;Password=$pw;" ` - --env 'AzureWebJobsStorage=UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://host.docker.internal' ` - --env 'WEBSITE_HOSTNAME=localhost:8080' ` - $ImageName + $appRunArgs = @("run") + if ($platformArgs.Count -gt 0) { + $appRunArgs += $platformArgs + } + $appRunArgs += @("--name", $ContainerName, "-p", "8080:80", "-it", "--add-host=host.docker.internal:host-gateway", "-d", + "--env", "SQLDB_Connection=Server=$serverIpAddress,1433;Database=$dbname;User=sa;Password=$pw;", + "--env", "AzureWebJobsStorage=UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://host.docker.internal", + "--env", "WEBSITE_HOSTNAME=localhost:8080", + "--env", "FUNCTIONS_WORKER_RUNTIME=dotnet-isolated") + if ($DockerfilePath -like "*Netherite*") { + $appRunArgs += @("--env", "SingleHost=$NetheriteEventHubsConnection") + } + $appRunArgs += $ImageName + & $engine @appRunArgs Exit-OnError } else { Write-Host "Starting $ContainerName application container" -ForegroundColor Yellow - docker run --name $ContainerName -p 8080:80 -it --add-host=host.docker.internal:host-gateway -d ` - --env 'AzureWebJobsStorage=UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://host.docker.internal' ` - --env 'WEBSITE_HOSTNAME=localhost:8080' ` - $ImageName + $appRunArgs = @("run") + if ($platformArgs.Count -gt 0) { + $appRunArgs += $platformArgs + } + $appRunArgs += @("--name", $ContainerName, "-p", "8080:80", "-it", "--add-host=host.docker.internal:host-gateway", "-d", + "--env", "AzureWebJobsStorage=UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://host.docker.internal", + "--env", "WEBSITE_HOSTNAME=localhost:8080", + "--env", "FUNCTIONS_WORKER_RUNTIME=dotnet-isolated") + if ($DockerfilePath -like "*Netherite*") { + $appRunArgs += @("--env", "SingleHost=$NetheriteEventHubsConnection") + } + $appRunArgs += $ImageName + & $engine @appRunArgs } Exit-OnError } @@ -153,15 +226,17 @@ if ($sleep -gt 0) { } # Check to see what containers are running -docker ps +& $engine ps Exit-OnError try { # Make sure the Functions runtime is up and running $pingUrl = "http://localhost:8080/admin/host/ping" Write-Host "Pinging app at $pingUrl to ensure the host is healthy" -ForegroundColor Yellow - Invoke-RestMethod -Method Post -Uri "http://localhost:8080/admin/host/ping" - Exit-OnError + $hostReady = Wait-ForHostPing -Uri $pingUrl + if (-not $hostReady) { + throw "Function host is not responding after waiting for readiness checks." + } if ($NoValidation -eq $false) { $startOrchestrationUri = "http://localhost:8080/$HttpStartPath" @@ -187,7 +262,7 @@ try { # Dump the docker logs to make debugging the issue easier Write-Host "Below are the docker logs for the app container:" -ForegroundColor Red - docker logs $ContainerName + & $engine logs $ContainerName # Rethrow the original exception throw diff --git a/test/TimeoutTests/CSharp/TimeoutTests.csproj b/test/TimeoutTests/CSharp/TimeoutTests.csproj index a5d27c195..4f577c87f 100644 --- a/test/TimeoutTests/CSharp/TimeoutTests.csproj +++ b/test/TimeoutTests/CSharp/TimeoutTests.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 diff --git a/test/TimeoutTests/Python/Nuget.config b/test/TimeoutTests/Python/Nuget.config index f137fb6a1..f46190d31 100644 --- a/test/TimeoutTests/Python/Nuget.config +++ b/test/TimeoutTests/Python/Nuget.config @@ -6,4 +6,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/TimeoutTests/Python/extensions.csproj b/test/TimeoutTests/Python/extensions.csproj index 87e940068..9316feffe 100644 --- a/test/TimeoutTests/Python/extensions.csproj +++ b/test/TimeoutTests/Python/extensions.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 v4 ** diff --git a/test/WebJobs.Extensions.DurableTask.Analyzers.Test/WebJobs.Extensions.DurableTask.Analyzers.Test.csproj b/test/WebJobs.Extensions.DurableTask.Analyzers.Test/WebJobs.Extensions.DurableTask.Analyzers.Test.csproj index e118c47a2..a0be6cd10 100644 --- a/test/WebJobs.Extensions.DurableTask.Analyzers.Test/WebJobs.Extensions.DurableTask.Analyzers.Test.csproj +++ b/test/WebJobs.Extensions.DurableTask.Analyzers.Test/WebJobs.Extensions.DurableTask.Analyzers.Test.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 Microsoft.Azure.WebJobs.Extensions.DurableTask.Analyzers.Test Microsoft.Azure.WebJobs.Extensions.DurableTask.Analyzers.Test diff --git a/test/Worker.Extensions.DurableTask.Tests/DurableTaskRegistryExtensionsTests.cs b/test/Worker.Extensions.DurableTask.Tests/DurableTaskRegistryExtensionsTests.cs index 29088070b..757e66d0f 100644 --- a/test/Worker.Extensions.DurableTask.Tests/DurableTaskRegistryExtensionsTests.cs +++ b/test/Worker.Extensions.DurableTask.Tests/DurableTaskRegistryExtensionsTests.cs @@ -35,8 +35,8 @@ public void GetOrchestrators_WithRegisteredOrchestrators_ShouldReturnThem() { // Arrange DurableTaskRegistry registry = new DurableTaskRegistry(); - registry.AddOrchestrator("Orchestrator1"); - registry.AddOrchestrator("Orchestrator2"); + registry.AddOrchestrator("Orchestrator1"); + registry.AddOrchestrator("Orchestrator2"); // Act List>> orchestrators = registry.GetOrchestrators().ToList(); @@ -73,8 +73,8 @@ public void GetActivities_WithRegisteredActivities_ShouldReturnThem() { // Arrange DurableTaskRegistry registry = new DurableTaskRegistry(); - registry.AddActivity("Activity1"); - registry.AddActivity("Activity2"); + registry.AddActivity("Activity1"); + registry.AddActivity("Activity2"); // Act List>> activities = registry.GetActivities().ToList(); @@ -111,8 +111,8 @@ public void GetEntities_WithRegisteredEntities_ShouldReturnThem() { // Arrange DurableTaskRegistry registry = new DurableTaskRegistry(); - registry.AddEntity("Entity1"); - registry.AddEntity("Entity2"); + registry.AddEntity("Entity1"); + registry.AddEntity("Entity2"); // Act List>> entities = registry.GetEntities().ToList(); @@ -128,9 +128,9 @@ public void GetOrchestrators_ShouldNotReturnActivitiesOrEntities() { // Arrange DurableTaskRegistry registry = new DurableTaskRegistry(); - registry.AddOrchestrator("Orchestrator1"); - registry.AddActivity("Activity1"); - registry.AddEntity("Entity1"); + registry.AddOrchestrator("Orchestrator1"); + registry.AddActivity("Activity1"); + registry.AddEntity("Entity1"); // Act List>> orchestrators = registry.GetOrchestrators().ToList(); @@ -145,9 +145,9 @@ public void GetActivities_ShouldNotReturnOrchestratorsOrEntities() { // Arrange DurableTaskRegistry registry = new DurableTaskRegistry(); - registry.AddOrchestrator("Orchestrator1"); - registry.AddActivity("Activity1"); - registry.AddEntity("Entity1"); + registry.AddOrchestrator("Orchestrator1"); + registry.AddActivity("Activity1"); + registry.AddEntity("Entity1"); // Act List>> activities = registry.GetActivities().ToList(); @@ -162,9 +162,9 @@ public void GetEntities_ShouldNotReturnOrchestratorsOrActivities() { // Arrange DurableTaskRegistry registry = new DurableTaskRegistry(); - registry.AddOrchestrator("Orchestrator1"); - registry.AddActivity("Activity1"); - registry.AddEntity("Entity1"); + registry.AddOrchestrator("Orchestrator1"); + registry.AddActivity("Activity1"); + registry.AddEntity("Entity1"); // Act List>> entities = registry.GetEntities().ToList(); @@ -174,7 +174,7 @@ public void GetEntities_ShouldNotReturnOrchestratorsOrActivities() Assert.Equal("Entity1", entities[0].Key.ToString()); } - private class TestOrchestrator : TaskOrchestrator + private class RegistryTestOrchestrator : TaskOrchestrator { public override Task RunAsync(TaskOrchestrationContext context, object input) { @@ -182,7 +182,7 @@ public override Task RunAsync(TaskOrchestrationContext context, object i } } - private class TestActivity : TaskActivity + private class RegistryTestActivity : TaskActivity { public override Task RunAsync(TaskActivityContext context, object input) { @@ -190,7 +190,7 @@ public override Task RunAsync(TaskActivityContext context, object input) } } - private class TestEntity : TaskEntity + private class RegistryTestEntity : TaskEntity { public Task RunAsync(TaskEntityContext context) { diff --git a/test/Worker.Extensions.DurableTask.Tests/FunctionContextExtensionsTests.cs b/test/Worker.Extensions.DurableTask.Tests/FunctionContextExtensionsTests.cs index 00296440b..9811a1058 100644 --- a/test/Worker.Extensions.DurableTask.Tests/FunctionContextExtensionsTests.cs +++ b/test/Worker.Extensions.DurableTask.Tests/FunctionContextExtensionsTests.cs @@ -285,7 +285,7 @@ class TestBindingContext : BindingContext { public TestBindingContext(IDictionary bindingData) { - this.BindingData = bindingData.AsReadOnly(); + this.BindingData = new System.Collections.ObjectModel.ReadOnlyDictionary(bindingData); } public override IReadOnlyDictionary BindingData { get; } } diff --git a/test/Worker.Extensions.DurableTask.Tests/Worker.Extensions.DurableTask.Tests.csproj b/test/Worker.Extensions.DurableTask.Tests/Worker.Extensions.DurableTask.Tests.csproj index 9690c06d3..e9b3892d2 100644 --- a/test/Worker.Extensions.DurableTask.Tests/Worker.Extensions.DurableTask.Tests.csproj +++ b/test/Worker.Extensions.DurableTask.Tests/Worker.Extensions.DurableTask.Tests.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable false diff --git a/test/e2e/Apps/BasicDotNetIsolated/EntitySchedulesVersionedOrchestration.cs b/test/e2e/Apps/BasicDotNetIsolated/EntitySchedulesVersionedOrchestration.cs index 2e396bd6f..10179c088 100644 --- a/test/e2e/Apps/BasicDotNetIsolated/EntitySchedulesVersionedOrchestration.cs +++ b/test/e2e/Apps/BasicDotNetIsolated/EntitySchedulesVersionedOrchestration.cs @@ -143,7 +143,7 @@ public string ScheduleOrchestration(ScheduleOrchestrationRequest request) { string? explicitVersion = request?.ExplicitVersion; StartOrchestrationOptions options = string.IsNullOrWhiteSpace(explicitVersion) - ? new StartOrchestrationOptions() + ? new StartOrchestrationOptions { Version = null } : new StartOrchestrationOptions { Version = explicitVersion }; string instanceId = this.Context.ScheduleNewOrchestration( diff --git a/test/e2e/Apps/BasicDotNetIsolated/app.csproj b/test/e2e/Apps/BasicDotNetIsolated/app.csproj index caadc90af..a60e59d82 100644 --- a/test/e2e/Apps/BasicDotNetIsolated/app.csproj +++ b/test/e2e/Apps/BasicDotNetIsolated/app.csproj @@ -1,10 +1,11 @@  - net8.0 + net10.0 v4 Exe enable enable + latest Microsoft.Azure.Durable.Tests.E2E diff --git a/test/e2e/Apps/BasicJava/extensions.csproj b/test/e2e/Apps/BasicJava/extensions.csproj index 1307e2a17..34db8ff54 100644 --- a/test/e2e/Apps/BasicJava/extensions.csproj +++ b/test/e2e/Apps/BasicJava/extensions.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0 false ** diff --git a/test/e2e/Apps/BasicNode/extensions.csproj b/test/e2e/Apps/BasicNode/extensions.csproj index 1307e2a17..34db8ff54 100644 --- a/test/e2e/Apps/BasicNode/extensions.csproj +++ b/test/e2e/Apps/BasicNode/extensions.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0 false ** diff --git a/test/e2e/Apps/BasicPowerShell/extensions.csproj b/test/e2e/Apps/BasicPowerShell/extensions.csproj index 1307e2a17..34db8ff54 100644 --- a/test/e2e/Apps/BasicPowerShell/extensions.csproj +++ b/test/e2e/Apps/BasicPowerShell/extensions.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0 false ** diff --git a/test/e2e/Apps/BasicPython/extensions.csproj b/test/e2e/Apps/BasicPython/extensions.csproj index 1307e2a17..34db8ff54 100644 --- a/test/e2e/Apps/BasicPython/extensions.csproj +++ b/test/e2e/Apps/BasicPython/extensions.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0 false ** diff --git a/test/e2e/Tests/E2ETests.csproj b/test/e2e/Tests/E2ETests.csproj index 20167b7ae..b96711c6d 100644 --- a/test/e2e/Tests/E2ETests.csproj +++ b/test/e2e/Tests/E2ETests.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 latest enable enable diff --git a/test/e2e/Tests/Fixtures/FixtureHelpers.cs b/test/e2e/Tests/Fixtures/FixtureHelpers.cs index c20771d24..906a15ac2 100644 --- a/test/e2e/Tests/Fixtures/FixtureHelpers.cs +++ b/test/e2e/Tests/Fixtures/FixtureHelpers.cs @@ -37,6 +37,8 @@ public static Process GetFuncHostProcess(string appPath, bool enableAuth = false funcProcess.StartInfo.ArgumentList.Add("host"); funcProcess.StartInfo.ArgumentList.Add("start"); funcProcess.StartInfo.ArgumentList.Add("--verbose"); + funcProcess.StartInfo.ArgumentList.Add("--target-framework"); + funcProcess.StartInfo.ArgumentList.Add("net10.0"); if (enableAuth) { @@ -48,13 +50,15 @@ public static Process GetFuncHostProcess(string appPath, bool enableAuth = false public static void StartProcessWithLogging(Process funcProcess, ILogger logger) { - funcProcess.ErrorDataReceived += (sender, e) => { - try { logger.LogError(e?.Data); } - catch (InvalidOperationException) { } + funcProcess.ErrorDataReceived += (sender, e) => + { + try { logger.LogError(e?.Data); } + catch (InvalidOperationException) { } }; - funcProcess.OutputDataReceived += (sender, e) => { - try { logger.LogInformation(e?.Data); } - catch (InvalidOperationException) { } + funcProcess.OutputDataReceived += (sender, e) => + { + try { logger.LogInformation(e?.Data); } + catch (InvalidOperationException) { } }; funcProcess.Start(); diff --git a/test/e2e/Tests/Fixtures/FunctionAppProcess.cs b/test/e2e/Tests/Fixtures/FunctionAppProcess.cs index bf729a314..2d72089fe 100644 --- a/test/e2e/Tests/Fixtures/FunctionAppProcess.cs +++ b/test/e2e/Tests/Fixtures/FunctionAppProcess.cs @@ -63,7 +63,7 @@ public async Task InitializeAsync() else e2eAppBuiltLocationPath = Path.Combine(rootDir, @$"test/e2e/Apps/{this.appName}/bin"); - if (!Path.Exists(e2eAppBuiltLocationPath)) + if (!Directory.Exists(e2eAppBuiltLocationPath)) { throw new InvalidOperationException($"The app bin path {e2eAppBuiltLocationPath} does not exist!"); } diff --git a/test/e2e/Tests/Tests/DistributedTracingEntitiesTests.cs b/test/e2e/Tests/Tests/DistributedTracingEntitiesTests.cs index 8108cfaba..faf13b817 100644 --- a/test/e2e/Tests/Tests/DistributedTracingEntitiesTests.cs +++ b/test/e2e/Tests/Tests/DistributedTracingEntitiesTests.cs @@ -14,6 +14,7 @@ public class DistributedTracingEntitiesTests { private readonly FunctionAppFixture _fixture; private readonly ActivityListener _activityListener; + private static readonly ActivitySource activitySource = new ActivitySource("DistributedTracingEntitiesTests"); public DistributedTracingEntitiesTests(FunctionAppFixture fixture, ITestOutputHelper testOutputHelper) { @@ -45,7 +46,6 @@ public DistributedTracingEntitiesTests(FunctionAppFixture fixture, ITestOutputHe public async Task DistributedTracingEntitiesTest() { // Start an Activity here which will appear as the root of all other Activities generated by this test - ActivitySource activitySource = new ActivitySource("DistributedTracingEntitiesTests"); using Activity? activity = activitySource.StartActivity("OrchestrationTests"); Assert.NotNull(activity); @@ -89,7 +89,6 @@ public async Task DistributedTracingEntitiesTest() public async Task DistributedTracingEntitiesFromClientTest() { // Start an Activity here which will appear as the root of all other Activities generated by this test - ActivitySource activitySource = new ActivitySource("DistributedTracingEntitiesTests"); using Activity? activity = activitySource.StartActivity("ClientTests"); Assert.NotNull(activity); diff --git a/test/e2e/Tests/Tests/DistributedTracingTests.cs b/test/e2e/Tests/Tests/DistributedTracingTests.cs index 09d78f568..415a9d123 100644 --- a/test/e2e/Tests/Tests/DistributedTracingTests.cs +++ b/test/e2e/Tests/Tests/DistributedTracingTests.cs @@ -13,6 +13,7 @@ public class DistributedTracingTests private readonly FunctionAppFixture fixture; private readonly ITestOutputHelper output; private readonly ActivityListener activityListener; + private static readonly ActivitySource activitySource = new ActivitySource("DistributedTracingTests"); public DistributedTracingTests(FunctionAppFixture fixture, ITestOutputHelper testOutputHelper) { @@ -40,7 +41,6 @@ public DistributedTracingTests(FunctionAppFixture fixture, ITestOutputHelper tes public async Task DistributedTracingTest() { // Start Activity - ActivitySource activitySource = new ActivitySource("DistributedTracingTests"); using Activity? activity = activitySource.StartActivity("HttpTriggerTests"); Assert.NotNull(activity); diff --git a/test/e2e/Tests/Tests/ErrorHandlingTests.cs b/test/e2e/Tests/Tests/ErrorHandlingTests.cs index f191faf15..cf99b101e 100644 --- a/test/e2e/Tests/Tests/ErrorHandlingTests.cs +++ b/test/e2e/Tests/Tests/ErrorHandlingTests.cs @@ -35,7 +35,7 @@ public async Task OrchestratorWithUncaughtActivityException_ShouldFail() await DurableHelpers.WaitForOrchestrationStateAsync(statusQueryGetUri, "Failed", 30); var orchestrationDetails = await DurableHelpers.GetRunningOrchestrationDetailsAsync(statusQueryGetUri); - + Assert.StartsWith(this.fixture.functionLanguageLocalizer?.GetLocalizedStringValue("RethrownActivityException.ErrorMessage"), orchestrationDetails.Output); Assert.Contains("This activity failed", orchestrationDetails.Output); } @@ -55,7 +55,7 @@ public async Task OrchestratorWithUncaughtEntityException_ShouldFail() await DurableHelpers.WaitForOrchestrationStateAsync(statusQueryGetUri, "Failed", 30); var orchestrationDetails = await DurableHelpers.GetRunningOrchestrationDetailsAsync(statusQueryGetUri); - + Assert.StartsWith(this.fixture.functionLanguageLocalizer.GetLocalizedStringValue("RethrownEntityException.ErrorMessage"), orchestrationDetails.Output); // Bug: https://github.com/Azure/azure-functions-durable-js/issues/642 if (this.fixture.functionLanguageLocalizer.GetLanguageType() != LanguageType.Node) @@ -149,7 +149,7 @@ public async Task OrchestratorWithRetriedActivityException_ShouldSucceed() Assert.Equal("Success", orchestrationDetails.Output); // Give some time for Core Tools to write logs out - Thread.Sleep(500); + Thread.Sleep(2000); Assert.Contains(this.fixture.TestLogs.CoreToolsLogs, x => x.Contains(nameof(InvalidOperationException)) && x.Contains("This activity failed")); @@ -174,7 +174,7 @@ public async Task OrchestratorWithRetriedEntityException_ShouldSucceed() Assert.Equal("Success", orchestrationDetails.Output); // Give some time for Core Tools to write logs out - Thread.Sleep(500); + Thread.Sleep(2000); if (this.fixture.functionLanguageLocalizer.GetLanguageType() == LanguageType.Python || this.fixture.functionLanguageLocalizer.GetLanguageType() == LanguageType.Node) @@ -214,7 +214,7 @@ public async Task OrchestratorWithCustomRetriedActivityException_ShouldSucceed() Assert.Equal("Success", orchestrationDetails.Output); // Give some time for Core Tools to write logs out - Thread.Sleep(500); + Thread.Sleep(2000); // We want to ensure that multiline exception messages and inner exceptions are preserved Assert.Contains(this.fixture.TestLogs.CoreToolsLogs, x => x.Contains(nameof(InvalidOperationException)) && @@ -239,7 +239,7 @@ public async Task CustomExceptionPropertiesInFailureDetails() string statusQueryGetUri = await DurableHelpers.ParseStatusQueryGetUriAsync(response); await DurableHelpers.WaitForOrchestrationStateAsync(statusQueryGetUri, "Completed", 30); - + var orchestrationDetails = await DurableHelpers.GetRunningOrchestrationDetailsAsync(statusQueryGetUri); // Deserialize the output to FailureDetails var failureDetails = JsonConvert.DeserializeObject(orchestrationDetails.Output); @@ -251,19 +251,19 @@ public async Task CustomExceptionPropertiesInFailureDetails() // Check that custom properties are included Assert.NotNull(failureDetails.Properties); - + // Verify string property Assert.True(failureDetails.Properties.ContainsKey("StringProperty")); Assert.Equal("validation-error-123", failureDetails.Properties["StringProperty"]); - + // Verify int property Assert.True(failureDetails.Properties.ContainsKey("IntProperty")); Assert.Equal((long)100, failureDetails.Properties["IntProperty"]); - + // Verify long property Assert.True(failureDetails.Properties.ContainsKey("LongProperty")); Assert.Equal(999999999L, failureDetails.Properties["LongProperty"]); - + // Verify DateTime property Assert.True(failureDetails.Properties.ContainsKey("DateTimeProperty")); @@ -276,7 +276,7 @@ public async Task CustomExceptionPropertiesInFailureDetails() Assert.Equal("VALIDATION_FAILED", dictProperty["error_code"]); Assert.Equal((long)3, dictProperty["retry_count"]); Assert.Equal(true, dictProperty["is_critical"]); - + // Verify list property Assert.True(failureDetails.Properties.ContainsKey("ListProperty")); var listProperty = JsonConvert.DeserializeObject>(failureDetails.Properties["ListProperty"]!.ToString()!); @@ -286,7 +286,7 @@ public async Task CustomExceptionPropertiesInFailureDetails() Assert.Equal("error2", listProperty[1]); Assert.Equal((long)500, listProperty[2]); Assert.Null(listProperty[3]); - + // Verify null property Assert.True(failureDetails.Properties.ContainsKey("NullProperty")); Assert.Null(failureDetails.Properties["NullProperty"]); diff --git a/test/e2e/Tests/build-e2e-test.ps1 b/test/e2e/Tests/build-e2e-test.ps1 index 1d6ca7a3a..0b2052199 100644 --- a/test/e2e/Tests/build-e2e-test.ps1 +++ b/test/e2e/Tests/build-e2e-test.ps1 @@ -27,7 +27,13 @@ param( $SkipBuild, [string] - $E2EAppName = "" + $E2EAppName = "", + + [string] + $ContainerEngine = "docker", + + [string] + $Platform = "" ) if ($PSVersionTable.PSEdition -ne 'Core') { @@ -38,6 +44,12 @@ if ($PSVersionTable.PSEdition -ne 'Core') { $ErrorActionPreference = "Stop" +$engine = $ContainerEngine +$platformArgs = @() +if (-not [string]::IsNullOrWhiteSpace($Platform)) { + $platformArgs = @("--platform", $Platform) +} + $CORE_TOOLS_VERSION = '4.0.7317' $ProjectBaseDirectory = "$PSScriptRoot\..\..\..\" @@ -231,11 +243,20 @@ else function StartMSSQLContainer($mssqlPwd) { Write-Host "Pulling down the mcr.microsoft.com/mssql/server:2022-latest image..." - docker pull mcr.microsoft.com/mssql/server:2022-latest + $pullArgs = @("pull", "mcr.microsoft.com/mssql/server:2022-latest") + if ($platformArgs.Count -gt 0) { + $pullArgs += $platformArgs + } + & $engine @pullArgs # Start the SQL Server docker container with the specified edition Write-Host "Starting SQL Server 2022-latest Express docker container on port 1433" -ForegroundColor DarkYellow - docker run --name mssql-server -e ACCEPT_EULA=Y -e "MSSQL_SA_PASSWORD=$mssqlPwd" -e "MSSQL_PID=Express" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2022-latest + $runArgs = @("run", "--name", "mssql-server", "-e", "ACCEPT_EULA=Y", "-e", "MSSQL_SA_PASSWORD=$mssqlPwd", "-e", "MSSQL_PID=Express", "-p", "1433:1433", "-d") + if ($platformArgs.Count -gt 0) { + $runArgs = @("run") + $platformArgs + $runArgs[1..($runArgs.Count - 1)] + } + $runArgs += "mcr.microsoft.com/mssql/server:2022-latest" + & $engine @runArgs if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE @@ -246,16 +267,25 @@ function StartMSSQLContainer($mssqlPwd) { Start-Sleep -Seconds 30 # Check to see what containers are running - docker ps + & $engine ps } function StartDTSContainer() { Write-Host "Pulling down the mcr.microsoft.com/dts/dts-emulator:latest image..." - docker pull mcr.microsoft.com/dts/dts-emulator:latest + $pullArgs = @("pull", "mcr.microsoft.com/dts/dts-emulator:latest") + if ($platformArgs.Count -gt 0) { + $pullArgs += $platformArgs + } + & $engine @pullArgs # Start the DTS Server docker container with the specified edition Write-Host "Starting DTS docker container on port 8080" -ForegroundColor DarkYellow - docker run -i -p 8080:8080 -p 8082:8082 -d mcr.microsoft.com/dts/dts-emulator:latest + $runArgs = @("run", "-i", "-p", "8080:8080", "-p", "8082:8082", "-d") + if ($platformArgs.Count -gt 0) { + $runArgs = @("run") + $platformArgs + $runArgs[1..($runArgs.Count - 1)] + } + $runArgs += "mcr.microsoft.com/dts/dts-emulator:latest" + & $engine @runArgs if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE @@ -266,7 +296,7 @@ function StartDTSContainer() { Start-Sleep -Seconds 30 # Check to see what containers are running - docker ps + & $engine ps } Set-Location $PSScriptRoot