From d56a2ec616d29dd031c231da8ef2bbfd93f5d767 Mon Sep 17 00:00:00 2001 From: David Justo Date: Wed, 19 Jun 2024 10:57:36 -0700 Subject: [PATCH] Replace ADO tests with GitHub actions (#2855) --- .github/workflows/validate-build-analyzer.yml | 58 ++++++++++++++++++ .github/workflows/validate-build-e2e.yml | 60 ++++++++++++++++++ .github/workflows/validate-build.yml | 61 +++++++++++++++++++ ...bs.Extensions.DurableTask.Analyzers.csproj | 1 + .../WebJobs.Extensions.DurableTask.csproj | 2 +- test/Common/DurableTaskEndToEndTests.cs | 3 + test/Common/TestDurableClient.cs | 2 +- test/Common/TestHelpers.cs | 2 +- test/FunctionsV2/CorrelationEndToEndTests.cs | 14 +---- test/FunctionsV2/OutOfProcTests.cs | 3 + .../PlatformSpecificHelpers.FunctionsV2.cs | 3 +- .../SmokeTests/SmokeTestsV1/VSSampleV1.csproj | 1 - 12 files changed, 194 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/validate-build-analyzer.yml create mode 100644 .github/workflows/validate-build-e2e.yml create mode 100644 .github/workflows/validate-build.yml diff --git a/.github/workflows/validate-build-analyzer.yml b/.github/workflows/validate-build-analyzer.yml new file mode 100644 index 000000000..ee49e3585 --- /dev/null +++ b/.github/workflows/validate-build-analyzer.yml @@ -0,0 +1,58 @@ +name: Validate Build (analyzer) + +on: + push: + branches: + - main + paths-ignore: [ '**.md' ] + pull_request: + branches: + - main + paths-ignore: [ '**.md' ] + +env: + solution: WebJobs.Extensions.DurableTask.sln + config: Release + AzureWebJobsStorage: UseDevelopmentStorage=true + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + + - name: Set up .NET Core 3.1 + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '3.1.x' + + - name: Set up .NET Core 2.1 + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '2.1.x' + + - name: Restore dependencies + run: dotnet restore $solution + + - name: Build + run: dotnet build $solution + + # Install Azurite + - name: Set up Node.js (needed for Azurite) + uses: actions/setup-node@v3 + with: + node-version: '18.x' # Azurite requires at least Node 18 + + - name: Install Azurite + run: npm install -g azurite + + # Run tests + - name: Run Analyzer tests + run: azurite --silent --blobPort 10000 --queuePort 10001 --tablePort 10002 & dotnet test ./test/WebJobs.Extensions.DurableTask.Analyzers.Test/WebJobs.Extensions.DurableTask.Analyzers.Test.csproj + diff --git a/.github/workflows/validate-build-e2e.yml b/.github/workflows/validate-build-e2e.yml new file mode 100644 index 000000000..8290d61e1 --- /dev/null +++ b/.github/workflows/validate-build-e2e.yml @@ -0,0 +1,60 @@ +name: Validate Build (E2E tests) + +on: + push: + branches: + - main + paths-ignore: [ '**.md' ] + pull_request: + branches: + - main + paths-ignore: [ '**.md' ] + +env: + solution: WebJobs.Extensions.DurableTask.sln + config: Release + AzureWebJobsStorage: UseDevelopmentStorage=true + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + + - name: Set up .NET Core 3.1 + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '3.1.x' + + - name: Set up .NET Core 2.1 + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '2.1.x' + + - name: Restore dependencies + run: dotnet restore $solution + + - name: Build + run: dotnet build $solution + + # Install Azurite + - name: Set up Node.js (needed for Azurite) + uses: actions/setup-node@v3 + with: + node-version: '18.x' # Azurite requires at least Node 18 + + - name: Install Azurite + run: npm install -g azurite + + # Run tests + - name: Run FunctionsV2 tests (only DurableEntity_CleanEntityStorage test, which is flaky) + run: azurite --silent --blobPort 10000 --queuePort 10001 --tablePort 10002 & dotnet test ./test/FunctionsV2/WebJobs.Extensions.DurableTask.Tests.V2.csproj --filter "FullyQualifiedName~Microsoft.Azure.WebJobs.Extensions.DurableTask.Tests.DurableTaskEndToEndTests.DurableEntity_CleanEntityStorage" + + - name: Run FunctionsV2 tests (all other E2E tests) + run: azurite --silent --blobPort 10000 --queuePort 10001 --tablePort 10002 & dotnet test ./test/FunctionsV2/WebJobs.Extensions.DurableTask.Tests.V2.csproj --filter "FullyQualifiedName~Microsoft.Azure.WebJobs.Extensions.DurableTask.Tests.DurableTaskEndToEndTests&FullyQualifiedName!~Microsoft.Azure.WebJobs.Extensions.DurableTask.Tests.DurableTaskEndToEndTests.DurableEntity_CleanEntityStorage" \ No newline at end of file diff --git a/.github/workflows/validate-build.yml b/.github/workflows/validate-build.yml new file mode 100644 index 000000000..6c23b1198 --- /dev/null +++ b/.github/workflows/validate-build.yml @@ -0,0 +1,61 @@ +name: Validate Build (except E2E tests) + +on: + push: + branches: + - main + paths-ignore: [ '**.md' ] + pull_request: + branches: + - main + paths-ignore: [ '**.md' ] + +env: + solution: WebJobs.Extensions.DurableTask.sln + config: Release + AzureWebJobsStorage: UseDevelopmentStorage=true + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + + - name: Set up .NET Core 3.1 + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '3.1.x' + + - name: Set up .NET Core 2.1 + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '2.1.x' + + - name: Restore dependencies + run: dotnet restore $solution + + - name: Build + run: dotnet build $solution + + # Install Azurite + - name: Set up Node.js (needed for Azurite) + uses: actions/setup-node@v3 + with: + node-version: '18.x' # Azurite requires at least Node 18 + + - name: Install Azurite + run: npm install -g azurite + + # Run tests + - name: Run FunctionsV2 tests (except E2E tests) + run: azurite --silent --blobPort 10000 --queuePort 10001 --tablePort 10002 & dotnet test ./test/FunctionsV2/WebJobs.Extensions.DurableTask.Tests.V2.csproj --filter "FullyQualifiedName!~Microsoft.Azure.WebJobs.Extensions.DurableTask.Tests.DurableTaskEndToEndTests" + + - name: Run Worker Extension tests + run: azurite --silent --blobPort 10000 --queuePort 10001 --tablePort 10002 & dotnet test ./test/Worker.Extensions.DurableTask.Tests/Worker.Extensions.DurableTask.Tests.csproj + diff --git a/src/WebJobs.Extensions.DurableTask.Analyzers/WebJobs.Extensions.DurableTask.Analyzers.csproj b/src/WebJobs.Extensions.DurableTask.Analyzers/WebJobs.Extensions.DurableTask.Analyzers.csproj index be27d32a9..6c627046e 100644 --- a/src/WebJobs.Extensions.DurableTask.Analyzers/WebJobs.Extensions.DurableTask.Analyzers.csproj +++ b/src/WebJobs.Extensions.DurableTask.Analyzers/WebJobs.Extensions.DurableTask.Analyzers.csproj @@ -4,6 +4,7 @@ netstandard2.0 false true + RS1026 diff --git a/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj b/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj index 5bbf2feae..d5e067333 100644 --- a/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj +++ b/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj @@ -58,12 +58,12 @@ - + diff --git a/test/Common/DurableTaskEndToEndTests.cs b/test/Common/DurableTaskEndToEndTests.cs index 9b5d279a6..7a7f4d43d 100644 --- a/test/Common/DurableTaskEndToEndTests.cs +++ b/test/Common/DurableTaskEndToEndTests.cs @@ -741,6 +741,9 @@ await TestHelpers.WaitUntilTrue( conditionDescription: "Log file exists", timeout: TimeSpan.FromSeconds(30)); + // add a minute wait to ensure logs are fully written + await Task.Delay(TimeSpan.FromMinutes(1)); + await TestHelpers.WaitUntilTrue( predicate: () => { diff --git a/test/Common/TestDurableClient.cs b/test/Common/TestDurableClient.cs index d9f41d4c4..6e35e5e49 100644 --- a/test/Common/TestDurableClient.cs +++ b/test/Common/TestDurableClient.cs @@ -182,7 +182,7 @@ public async Task WaitForCompletionAsync( { if (timeout == null) { - timeout = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(30); + timeout = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromMinutes(1); } Stopwatch sw = Stopwatch.StartNew(); diff --git a/test/Common/TestHelpers.cs b/test/Common/TestHelpers.cs index ac9d7feaa..990ba8515 100644 --- a/test/Common/TestHelpers.cs +++ b/test/Common/TestHelpers.cs @@ -16,8 +16,8 @@ using DurableTask.AzureStorage; using Microsoft.ApplicationInsights.Channel; #if !FUNCTIONS_V1 -using Microsoft.Extensions.Hosting; using Microsoft.Azure.WebJobs.Host.Scale; +using Microsoft.Extensions.Hosting; #endif using Microsoft.Azure.WebJobs.Extensions.DurableTask.Storage; using Microsoft.Azure.WebJobs.Host.TestCommon; diff --git a/test/FunctionsV2/CorrelationEndToEndTests.cs b/test/FunctionsV2/CorrelationEndToEndTests.cs index 0b9e31eac..6eb2e9090 100644 --- a/test/FunctionsV2/CorrelationEndToEndTests.cs +++ b/test/FunctionsV2/CorrelationEndToEndTests.cs @@ -234,7 +234,7 @@ internal async Task, List>> [InlineData(false, true, true)] [InlineData(true, true, false)] [InlineData(true, true, true)] - public async void TelemetryClientSetup_AppInsights_Warnings(bool instrumentationKeyIsSet, bool connStringIsSet, bool extendedSessions) + public void TelemetryClientSetup_AppInsights_Warnings(bool instrumentationKeyIsSet, bool connStringIsSet, bool extendedSessions) { TraceOptions traceOptions = new TraceOptions() { @@ -258,11 +258,11 @@ public async void TelemetryClientSetup_AppInsights_Warnings(bool instrumentation } else if (instrumentationKeyIsSet) { - mockNameResolver = GetNameResolverMock(new[] { (instKeyEnvVarName, environmentVariableValue), (connStringEnvVarName, String.Empty) }); + mockNameResolver = GetNameResolverMock(new[] { (instKeyEnvVarName, environmentVariableValue), (connStringEnvVarName, string.Empty) }); } else if (connStringIsSet) { - mockNameResolver = GetNameResolverMock(new[] { (instKeyEnvVarName, String.Empty), (connStringEnvVarName, connStringValue) }); + mockNameResolver = GetNameResolverMock(new[] { (instKeyEnvVarName, string.Empty), (connStringEnvVarName, connStringValue) }); } using (var host = TestHelpers.GetJobHost( @@ -405,14 +405,6 @@ private static List GetCorrelationSortedList(OperationTeleme var result = new List(); if (current.Count != 0) { - foreach (var some in current) - { - if (parent.Id == some.Context.Operation.ParentId) - { - Console.WriteLine("match"); - } - } - IOrderedEnumerable nexts = current.Where(p => p.Context.Operation.ParentId == parent.Id).OrderBy(p => p.Timestamp.Ticks); foreach (OperationTelemetry next in nexts) { diff --git a/test/FunctionsV2/OutOfProcTests.cs b/test/FunctionsV2/OutOfProcTests.cs index 4f95c1a2b..69fa450a5 100644 --- a/test/FunctionsV2/OutOfProcTests.cs +++ b/test/FunctionsV2/OutOfProcTests.cs @@ -342,6 +342,7 @@ public async Task TestLocalRcpEndpointRuntimeVersion(string runtimeVersion, bool // Validate if we opened local RPC endpoint by looking at log statements. var logger = this.loggerProvider.CreatedLoggers.Single(l => l.Category == TestHelpers.LogCategory); var logMessages = logger.LogMessages.ToList(); + bool enabledRpcEndpoint = logMessages.Any(msg => msg.Level == Microsoft.Extensions.Logging.LogLevel.Information && msg.FormattedMessage.StartsWith($"Opened local {expectedProtocol} endpoint:")); Assert.Equal(enabledExpected, enabledRpcEndpoint); @@ -363,6 +364,7 @@ public async Task InvokeLocalRpcEndpoint() { await host.StartAsync(); +#pragma warning disable SYSLIB0014 // Type or member is obsolete using (var client = new WebClient()) { string jsonString = client.DownloadString("http://localhost:17071/durabletask/instances"); @@ -370,6 +372,7 @@ public async Task InvokeLocalRpcEndpoint() // The result is expected to be an empty array JArray array = JArray.Parse(jsonString); } +#pragma warning restore SYSLIB0014 // Type or member is obsolete await host.StopAsync(); } diff --git a/test/FunctionsV2/PlatformSpecificHelpers.FunctionsV2.cs b/test/FunctionsV2/PlatformSpecificHelpers.FunctionsV2.cs index a85c05c64..7436f47e5 100644 --- a/test/FunctionsV2/PlatformSpecificHelpers.FunctionsV2.cs +++ b/test/FunctionsV2/PlatformSpecificHelpers.FunctionsV2.cs @@ -232,7 +232,6 @@ private static IWebJobsBuilder AddEmulatorDurableTask(this IWebJobsBuilder build internal class FunctionsV2HostWrapper : ITestHost { - internal readonly IHost InnerHost; private readonly JobHost innerWebJobsHost; private readonly DurableTaskOptions options; private readonly INameResolver nameResolver; @@ -257,6 +256,8 @@ internal FunctionsV2HostWrapper( this.options = options.Value; } + internal IHost InnerHost { get; private set; } + public Task CallAsync(string methodName, IDictionary args) => this.innerWebJobsHost.CallAsync(methodName, args); diff --git a/test/SmokeTests/SmokeTestsV1/VSSampleV1.csproj b/test/SmokeTests/SmokeTestsV1/VSSampleV1.csproj index 1d2b30732..304a6fe3b 100644 --- a/test/SmokeTests/SmokeTestsV1/VSSampleV1.csproj +++ b/test/SmokeTests/SmokeTestsV1/VSSampleV1.csproj @@ -10,7 +10,6 @@ -