< Summary

Information
Class: Elsa.Alterations.Services.DefaultAlterationRunner
Assembly: Elsa.Alterations
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Alterations/Services/DefaultAlterationRunner.cs
Line coverage
90%
Covered lines: 36
Uncovered lines: 4
Coverable lines: 40
Total lines: 100
Line coverage: 90%
Branch coverage
62%
Covered branches: 5
Total branches: 8
Branch coverage: 62.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
RunAsync()75%44100%
RunAsync()50%4484%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Alterations/Services/DefaultAlterationRunner.cs

#LineLine coverage
 1using Elsa.Alterations.Core.Contracts;
 2using Elsa.Alterations.Core.Models;
 3using Elsa.Alterations.Core.Results;
 4using Elsa.Alterations.Middleware.Workflows;
 5using Elsa.Common;
 6using Elsa.Workflows;
 7using Elsa.Workflows.CommitStates;
 8using Elsa.Workflows.Management;
 9using Elsa.Workflows.Pipelines.WorkflowExecution;
 10using Elsa.Workflows.Runtime;
 11using Microsoft.Extensions.Logging;
 12
 13namespace Elsa.Alterations.Services;
 14
 15/// <inheritdoc />
 216public class DefaultAlterationRunner(
 217    IWorkflowRuntime workflowRuntime,
 218    IWorkflowExecutionPipeline workflowExecutionPipeline,
 219    IWorkflowDefinitionService workflowDefinitionService,
 220    IWorkflowStateExtractor workflowStateExtractor,
 221    ICommitStateHandler commitStateHandler,
 222    ISystemClock systemClock,
 223    IServiceProvider serviceProvider)
 24    : IAlterationRunner
 25{
 26    /// <inheritdoc />
 27    public async Task<ICollection<RunAlterationsResult>> RunAsync(IEnumerable<string> workflowInstanceIds, IEnumerable<I
 28    {
 129        var results = new List<RunAlterationsResult>();
 130        var alterationList = alterations as ICollection<IAlteration> ?? alterations.ToList();
 31
 432        foreach (var workflowInstanceId in workflowInstanceIds)
 33        {
 134            var result = await RunAsync(workflowInstanceId, alterationList, cancellationToken);
 135            results.Add(result);
 36        }
 37
 138        return results;
 139    }
 40
 41    /// <inheritdoc />
 42    public async Task<RunAlterationsResult> RunAsync(string workflowInstanceId, IEnumerable<IAlteration> alterations, Ca
 43    {
 144        var log = new AlterationLog(systemClock);
 145        var result = new RunAlterationsResult(workflowInstanceId, log);
 146        var workflowClient = await workflowRuntime.CreateClientAsync(workflowInstanceId, cancellationToken: cancellation
 47
 48        // Load workflow instance.
 149        var workflowState = await workflowClient.ExportStateAsync(cancellationToken);
 50
 151        if (workflowState == null)
 52        {
 053            log.Add($"Workflow instance with ID '{workflowInstanceId}' not found.", LogLevel.Error);
 054            return result;
 55        }
 56
 57        // Load workflow definition.
 158        var workflowGraph = await workflowDefinitionService.FindWorkflowGraphAsync(workflowState.DefinitionVersionId, ca
 59
 160        if (workflowGraph == null)
 61        {
 062            log.Add($"Workflow definition with ID '{workflowState.DefinitionVersionId}' not found.", LogLevel.Error);
 063            return result;
 64        }
 65
 66        // Create workflow execution context.
 167        var workflowExecutionContext = await WorkflowExecutionContext.CreateAsync(serviceProvider, workflowGraph, workfl
 168        workflowExecutionContext.TransientProperties.Add(RunAlterationsMiddleware.AlterationsPropertyKey, alterations);
 169        workflowExecutionContext.TransientProperties.Add(RunAlterationsMiddleware.AlterationsLogPropertyKey, log);
 70
 71        // Build a new workflow execution pipeline.
 172        var pipelineBuilder = new WorkflowExecutionPipelineBuilder(serviceProvider);
 173        workflowExecutionPipeline.ConfigurePipelineBuilder(pipelineBuilder);
 74
 75        // Replace the terminal DefaultActivitySchedulerMiddleware with the RunAlterationsMiddleware terminal.
 176        pipelineBuilder.ReplaceTerminal<RunAlterationsMiddleware>();
 77
 78        // Build modified pipeline.
 179        var pipeline = pipelineBuilder.Build();
 80
 81        // Execute the pipeline.
 182        await pipeline(workflowExecutionContext);
 83
 84        // Extract workflow state.
 185        workflowState = workflowStateExtractor.Extract(workflowExecutionContext);
 86
 87        // Commit workflow state.
 188        await commitStateHandler.CommitAsync(workflowExecutionContext, workflowState, cancellationToken);
 89
 90        // Apply updated workflow state.
 91        // TODO: Importing back into the workflow runtime makes sense, but this also causes another SAVE ction of the wo
 92        // Can we avoid this? Perhaps we need more granular control over when we purge and when we save to DB.
 193        await workflowClient.ImportStateAsync(workflowState, cancellationToken);
 94
 95        // Check if the workflow has scheduled work.
 196        result.WorkflowHasScheduledWork = workflowExecutionContext.Scheduler.HasAny;
 97
 198        return result;
 199    }
 100}