From 4ee8f6912d15359b1bfcb7fd69c007eccbfa9924 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Thu, 27 Nov 2025 20:51:59 +0100 Subject: [PATCH] Add unit and integration tests for the `Finish` activity to validate termination behavior (#7110) (#7114) * Add unit and integration tests for the `Finish` activity to validate termination behavior (#7110) - Added `FinishInSequenceWorkflow` to test `Finish` activity in a sequence workflow configuration. - Introduced integration tests (`FinishTests`) to confirm `Finish` terminates workflows and skips subsequent activities. - Developed unit tests to verify activity completion and workflow status transitions to `Finished`. * Update test/integration/Elsa.Activities.IntegrationTests/Primitives/Workflows/FinishInSequenceWorkflow.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update test/integration/Elsa.Activities.IntegrationTests/Primitives/Workflows/FinishInSequenceWorkflow.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add `Finish` activity unit test to verify ITerminalNode implementation * Add code coverage report generation and GitHub Pages deployment workflow - Removed unused `tempvalidator` project and its associated files. - Updated GitHub Actions workflow to include steps for generating code coverage reports in HTML format using `dotnet-reportgenerator-globaltool`. - Added deployment of coverage reports to GitHub Pages for the `main` branch. - Updated `.gitignore` to exclude test results and artifacts. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/packages.yml | 33 ++++++++++++ .gitignore | 4 ++ tempvalidator/Program.cs | 2 - tempvalidator/tempvalidator.csproj | 10 ---- .../Primitives/FinishTests.cs | 36 +++++++++++++ .../Workflows/FinishInSequenceWorkflow.cs | 24 +++++++++ .../Primitives/FinishTests.cs | 51 +++++++++++++++++++ 7 files changed, 148 insertions(+), 12 deletions(-) delete mode 100644 tempvalidator/Program.cs delete mode 100644 tempvalidator/tempvalidator.csproj create mode 100644 test/integration/Elsa.Activities.IntegrationTests/Primitives/FinishTests.cs create mode 100644 test/integration/Elsa.Activities.IntegrationTests/Primitives/Workflows/FinishInSequenceWorkflow.cs create mode 100644 test/unit/Elsa.Activities.UnitTests/Primitives/FinishTests.cs diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index 760b28067..6f058b390 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -70,6 +70,17 @@ jobs: dotnet test "$project" --configuration Release --no-build --logger "GitHubActions;report-warnings=false" /p:CollectCoverage=true done + - name: Install ReportGenerator + run: dotnet tool install -g dotnet-reportgenerator-globaltool + + - name: Generate HTML coverage report + run: | + reportgenerator \ + "-reports:./artifacts/coverage/**/coverage.cobertura.xml" \ + "-targetdir:./artifacts/coverage-report" \ + "-reporttypes:Html;Cobertura;TextSummary" \ + "-verbosity:Info" + - name: Upload coverage reports if: always() uses: actions/upload-artifact@v4 @@ -77,6 +88,12 @@ jobs: name: coverage-reports path: artifacts/coverage + - name: Upload Pages artifact + if: always() && github.ref == 'refs/heads/main' + uses: actions/upload-pages-artifact@v3 + with: + path: './artifacts/coverage-report' + build: name: Build packages needs: test @@ -168,3 +185,19 @@ jobs: - name: Publish to nuget.org run: dotnet nuget push *.nupkg -k ${{ secrets.NUGET_API_KEY }} -s ${{ env.nuget_feed_source }} --skip-duplicate + + deploy_coverage: + name: Deploy coverage to GitHub Pages + needs: test + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 68a650b2a..34040f1bf 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,7 @@ unlist.sh /docker/data/ /docker/azurite-data/ docker/docker-compose-datadog.yml + +# Test results +TestResults/ +artifacts/ diff --git a/tempvalidator/Program.cs b/tempvalidator/Program.cs deleted file mode 100644 index 3751555cb..000000000 --- a/tempvalidator/Program.cs +++ /dev/null @@ -1,2 +0,0 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); diff --git a/tempvalidator/tempvalidator.csproj b/tempvalidator/tempvalidator.csproj deleted file mode 100644 index 2150e3797..000000000 --- a/tempvalidator/tempvalidator.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - Exe - net8.0 - enable - enable - - - diff --git a/test/integration/Elsa.Activities.IntegrationTests/Primitives/FinishTests.cs b/test/integration/Elsa.Activities.IntegrationTests/Primitives/FinishTests.cs new file mode 100644 index 000000000..398e29819 --- /dev/null +++ b/test/integration/Elsa.Activities.IntegrationTests/Primitives/FinishTests.cs @@ -0,0 +1,36 @@ +using Elsa.Activities.IntegrationTests.Primitives.Workflows; +using Elsa.Testing.Shared; +using Elsa.Workflows; +using Elsa.Workflows.Activities; +using Elsa.Workflows.State; +using Xunit.Abstractions; + +namespace Elsa.Activities.IntegrationTests.Primitives; + +/// +/// Integration tests for the activity. +/// +public class FinishTests(ITestOutputHelper testOutputHelper) +{ + private readonly WorkflowTestFixture _fixture = new WorkflowTestFixture(testOutputHelper) + .AddWorkflow(); + + [Fact(DisplayName = "Finish terminates workflow and prevents subsequent activities from executing")] + public async Task Finish_TerminatesWorkflowAndPreventsSubsequentActivities() + { + // Act + var workflowState = await _fixture.RunWorkflowAsync(FinishInSequenceWorkflow.DefinitionId); + + // Assert + AssertWorkflowFinished(workflowState); + var lines = _fixture.CapturingTextWriter.Lines.ToList(); + Assert.Contains("Before Finish", lines); + Assert.DoesNotContain("After Finish", lines); + } + + private static void AssertWorkflowFinished(WorkflowState workflowState) + { + Assert.Equal(WorkflowStatus.Finished, workflowState.Status); + Assert.Equal(WorkflowSubStatus.Finished, workflowState.SubStatus); + } +} diff --git a/test/integration/Elsa.Activities.IntegrationTests/Primitives/Workflows/FinishInSequenceWorkflow.cs b/test/integration/Elsa.Activities.IntegrationTests/Primitives/Workflows/FinishInSequenceWorkflow.cs new file mode 100644 index 000000000..4963327ff --- /dev/null +++ b/test/integration/Elsa.Activities.IntegrationTests/Primitives/Workflows/FinishInSequenceWorkflow.cs @@ -0,0 +1,24 @@ +using Elsa.Workflows; +using Elsa.Workflows.Activities; +using System; + +namespace Elsa.Activities.IntegrationTests.Primitives.Workflows; + +public class FinishInSequenceWorkflow : WorkflowBase +{ + public static readonly string DefinitionId = Guid.NewGuid().ToString(); + + protected override void Build(IWorkflowBuilder workflow) + { + workflow.WithDefinitionId(DefinitionId); + workflow.Root = new Sequence + { + Activities = + { + new WriteLine("Before Finish"), + new Finish(), + new WriteLine("After Finish") + } + }; + } +} diff --git a/test/unit/Elsa.Activities.UnitTests/Primitives/FinishTests.cs b/test/unit/Elsa.Activities.UnitTests/Primitives/FinishTests.cs new file mode 100644 index 000000000..8e9fe5da5 --- /dev/null +++ b/test/unit/Elsa.Activities.UnitTests/Primitives/FinishTests.cs @@ -0,0 +1,51 @@ +using Elsa.Testing.Shared; +using Elsa.Workflows; + +namespace Elsa.Activities.UnitTests.Primitives; + +/// +/// Unit tests for the activity. +/// +public class FinishTests +{ + [Fact(DisplayName = "Finish implements ITerminalNode interface")] + public void Finish_ImplementsITerminalNode() + { + // Arrange + var finish = new Finish(); + + // Assert + Assert.IsAssignableFrom(finish); + } + + [Fact(DisplayName = "Finish completes successfully")] + public async Task Should_Complete_Successfully() + { + // Arrange + var finish = new Finish(); + + // Act + var context = await ExecuteAsync(finish); + + // Assert + Assert.Equal(ActivityStatus.Completed, context.Status); + } + + [Fact(DisplayName = "Finish transitions workflow to Finished substatus")] + public async Task Should_Transition_Workflow_To_Finished() + { + // Arrange + var finish = new Finish(); + + // Act + var context = await ExecuteAsync(finish); + + // Assert + Assert.Equal(WorkflowSubStatus.Finished, context.WorkflowExecutionContext.SubStatus); + } + + private static async Task ExecuteAsync(IActivity activity) + { + return await new ActivityTestFixture(activity).ExecuteAsync(); + } +}