Adds integration tests for core activities (#7100)
* Add unit and integration tests for `DownloadHttpFile` activity - Developed comprehensive unit tests for the `DownloadHttpFile` activity validating method execution (GET, POST), URL handling, headers, and status codes. - Added integration tests to verify functionality like authorization headers, filename extraction, and response stream handling. - Updated `IntegrationTests` project references to include the required `Elsa.Http` module. * Refactor `DownloadHttpFileTests` to simplify test setup and improve reusability - Consolidated test initialization logic into `RunActivityAsync` for cleaner and reusable test setup. - Updated existing tests to use `RunActivityAsync`, reducing boilerplate code. - Unified filename extraction tests into a parameterized theory to improve test coverage and clarity. - Simplified helper handlers with expression-bodied members for readability. * Add comments to clarify HttpResponseMessage disposal responsibility in `DownloadHttpFileTests`. * Ensure `HttpResponseMessage.Content` is always set to prevent null reference issues in `DownloadHttpFileTests`. * Refactor `DownloadHttpFileTests` to ensure `HttpResponseMessage.Content` is always initialized and simplify content assignment logic. * Update `DownloadHttpFileTests` to set an empty `HttpResponseMessage.Content` for testing `HasContent` behavior * Add `GitHubActionsTestLogger` package to test projects and refactor `Directory.Packages.props` - Updated unit and integration test projects to include `GitHubActionsTestLogger` for improved test reporting in CI. - Refactored `Directory.Packages.props` to add conditional dependencies for .NET 8, 9, and 10 compatibility. * Remove `GitHubActionsTestLogger` package from test projects. * Add project reference for unit tests and update `DownloadHttpFileTests` - Included `Elsa.Activities.UnitTests` project reference in `IntegrationTests` to reuse helpers. - Removed redundant `TestHttpMessageHandler` by utilizing shared helper from `UnitTests`. * Refactor `DownloadHttpFileTests` to remove unused methods and simplify imports * Update target framework to .NET 10 and upgrade `Nuke.Components` package to v10.0.0 * Add integration tests for smoke testing all core workflow activities - Introduced `ActivitiesSmokeTests` to validate basic functionality of core workflow activities, including control flow and data manipulation. - Added comprehensive `ActivitiesSmokeTestWorkflow` to test activities such as `Start`, `Finish`, `If`, `Switch`, `For`, `While`, `ForEach`, `SetVariable`, and `SetOutput`. * Refactor `ActivitiesSmokeTestWorkflow` to reorder and clarify activity test cases * Update test/integration/Elsa.Workflows.IntegrationTests/Scenarios/SmokeTests/ActivitiesSmokeTestWorkflow.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update test/integration/Elsa.Workflows.IntegrationTests/Scenarios/SmokeTests/ActivitiesSmokeTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
b0d93d347b
commit
f020c5e9d3
|
|
@ -0,0 +1,209 @@
|
|||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.Management.Activities.SetOutput;
|
||||
using Elsa.Workflows.Memory;
|
||||
using Elsa.Workflows.Models;
|
||||
|
||||
namespace Elsa.Workflows.IntegrationTests.Scenarios.SmokeTests;
|
||||
|
||||
/// <summary>
|
||||
/// Comprehensive smoke test workflow that exercises basic control flow and data manipulation activities.
|
||||
/// Tests: Start, Sequence, Break, Complete, If, Switch, While, For, ForEach,
|
||||
/// WriteLine, SetName, SetVariable<T>, SetVariable (untyped), SetOutput
|
||||
/// </summary>
|
||||
public class ActivitiesSmokeTestWorkflow : WorkflowBase
|
||||
{
|
||||
protected override void Build(IWorkflowBuilder workflow)
|
||||
{
|
||||
// Variables for testing
|
||||
var counter = new Variable<int>("Counter", 0);
|
||||
var name = new Variable<string>("Name", "Initial");
|
||||
var result = new Variable<string>("Result", "");
|
||||
var items = new Variable<List<string>>("Items", ["A", "B", "C"]);
|
||||
var currentItem = new Variable<string>("CurrentItem", "");
|
||||
var loopCounter = new Variable<int>("LoopCounter", 0);
|
||||
var untypedVar = new Variable<object?>("UntypedVar", null);
|
||||
var switchValue = new Variable<int>("SwitchValue", 2);
|
||||
|
||||
workflow.WithVariables(counter, name, result, items, currentItem, loopCounter, untypedVar, switchValue);
|
||||
|
||||
workflow.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
// Test Start activity
|
||||
new Start(),
|
||||
|
||||
// Test SetName
|
||||
new SetName
|
||||
{
|
||||
Value = new("SmokeTestWorkflow")
|
||||
},
|
||||
|
||||
// Test WriteLine
|
||||
new WriteLine(context => "=== Smoke Test Started ==="),
|
||||
|
||||
// Test SetVariable<T>
|
||||
new SetVariable<string>
|
||||
{
|
||||
Variable = name,
|
||||
Value = new("Updated Name")
|
||||
},
|
||||
new WriteLine(context => $"Name: {name.Get(context)}"),
|
||||
|
||||
// Test SetVariable (untyped)
|
||||
new SetVariable
|
||||
{
|
||||
Variable = untypedVar,
|
||||
Value = new("Untyped value")
|
||||
},
|
||||
new WriteLine(context => $"Untyped: {untypedVar.Get(context)}"),
|
||||
|
||||
// Test If activity (condition true)
|
||||
new If(() => true)
|
||||
{
|
||||
Then = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new WriteLine("If branch: True path executed"),
|
||||
new SetVariable<int> { Variable = counter, Value = new(10) }
|
||||
}
|
||||
},
|
||||
Else = new WriteLine("If branch: False path (should not execute)")
|
||||
},
|
||||
|
||||
// Test Switch activity
|
||||
new Switch
|
||||
{
|
||||
Cases =
|
||||
{
|
||||
new(
|
||||
"Case1",
|
||||
context => ValueTask.FromResult(switchValue.Get(context) == 1),
|
||||
new WriteLine("Switch: Case 1 (should not execute)")
|
||||
),
|
||||
new(
|
||||
"Case2",
|
||||
context => ValueTask.FromResult(switchValue.Get(context) == 2),
|
||||
new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new WriteLine("Switch: Case 2 executed"),
|
||||
new SetVariable<string> { Variable = result, Value = new("Switch-2") }
|
||||
}
|
||||
}
|
||||
),
|
||||
new(
|
||||
"Case3",
|
||||
context => ValueTask.FromResult(switchValue.Get(context) == 3),
|
||||
new WriteLine("Switch: Case 3 (should not execute)")
|
||||
)
|
||||
},
|
||||
Default = new WriteLine("Switch: Default (should not execute)")
|
||||
},
|
||||
|
||||
// Test For loop with Break
|
||||
new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new WriteLine("For loop: Starting"),
|
||||
new For
|
||||
{
|
||||
Start = new(0),
|
||||
End = new(100),
|
||||
Step = new(1),
|
||||
Body = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new SetVariable<int> { Variable = loopCounter, Value = new(context => loopCounter.Get(context) + 1) },
|
||||
// Break after 3 iterations
|
||||
new If(context => loopCounter.Get(context) >= 3)
|
||||
{
|
||||
Then = new Break()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new WriteLine(context => $"For loop: Completed with {loopCounter.Get(context)} iterations")
|
||||
}
|
||||
},
|
||||
|
||||
// Test While loop with Break
|
||||
new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new SetVariable<int> { Variable = loopCounter, Value = new(0) },
|
||||
new WriteLine("While loop: Starting"),
|
||||
new While(() => true)
|
||||
{
|
||||
Body = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new SetVariable<int> { Variable = loopCounter, Value = new(context => loopCounter.Get(context) + 1) },
|
||||
new WriteLine(context => $"While loop: Iteration {loopCounter.Get(context)}"),
|
||||
// Break after 3 iterations
|
||||
new If(context => loopCounter.Get(context) >= 3)
|
||||
{
|
||||
Then = new Break()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new WriteLine(context => $"While loop: Completed with {loopCounter.Get(context)} iterations")
|
||||
}
|
||||
},
|
||||
|
||||
// Test ForEach with Break
|
||||
new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new SetVariable<int> { Variable = loopCounter, Value = new(0) },
|
||||
new WriteLine("ForEach loop: Starting"),
|
||||
new ForEach<string>
|
||||
{
|
||||
Items = new(items),
|
||||
CurrentValue = new(currentItem),
|
||||
Body = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new SetVariable<int> { Variable = loopCounter, Value = new(context => loopCounter.Get(context) + 1) },
|
||||
new WriteLine(context => $"ForEach: Item '{currentItem.Get(context)}'"),
|
||||
// Break after processing 2 items (A, B)
|
||||
new If(context => loopCounter.Get(context) >= 2)
|
||||
{
|
||||
Then = new Break()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new WriteLine(context => $"ForEach loop: Completed with {loopCounter.Get(context)} items processed")
|
||||
}
|
||||
},
|
||||
|
||||
// Test SetOutput
|
||||
new SetOutput
|
||||
{
|
||||
OutputName = new("FinalResult"),
|
||||
OutputValue = new(context => $"Counter={counter.Get(context)}, Name={name.Get(context)}, Result={result.Get(context)}")
|
||||
},
|
||||
|
||||
// Test Finish and End activities
|
||||
new Finish(),
|
||||
new End(),
|
||||
|
||||
// Test Complete activity (ends workflow immediately)
|
||||
new Complete(),
|
||||
|
||||
// This should not execute due to Complete
|
||||
new WriteLine("After Complete (should not execute)")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
using Elsa.Testing.Shared;
|
||||
using Elsa.Workflows.Models;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Elsa.Workflows.IntegrationTests.Scenarios.SmokeTests;
|
||||
|
||||
/// <summary>
|
||||
/// Smoke tests that verify basic functionality of core workflow activities.
|
||||
/// </summary>
|
||||
public class ActivitiesSmokeTests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
private readonly WorkflowTestFixture _fixture = new(testOutputHelper);
|
||||
|
||||
[Fact(DisplayName = "Smoke test executes all core activities successfully")]
|
||||
public async Task SmokeTest_ExecutesAllActivities_Successfully()
|
||||
{
|
||||
// Act
|
||||
var (result, _) = await RunWorkflowAndCaptureOutput();
|
||||
|
||||
// Assert - Workflow completed successfully
|
||||
Assert.Equal(WorkflowStatus.Finished, result.WorkflowState.Status);
|
||||
Assert.Equal(WorkflowSubStatus.Finished, result.WorkflowState.SubStatus);
|
||||
|
||||
// Verify outputs were set correctly
|
||||
var outputs = result.WorkflowState.Output;
|
||||
Assert.NotNull(outputs);
|
||||
Assert.True(outputs.TryGetValue("FinalResult", out var finalResultObj));
|
||||
|
||||
var finalResult = finalResultObj?.ToString();
|
||||
Assert.NotNull(finalResult);
|
||||
Assert.Contains("Counter=10", finalResult);
|
||||
Assert.Contains("Name=Updated Name", finalResult);
|
||||
Assert.Contains("Result=Switch-2", finalResult);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Smoke test verifies all activities were executed")]
|
||||
public async Task SmokeTest_VerifiesActivityExecution()
|
||||
{
|
||||
// Act
|
||||
var (_, lines) = await RunWorkflowAndCaptureOutput();
|
||||
|
||||
// Assert - Verify key activities executed by checking WriteLine outputs
|
||||
Assert.Contains(lines, line => line.Contains("=== Smoke Test Started ==="));
|
||||
Assert.Contains(lines, line => line.Contains("Name: Updated Name"));
|
||||
Assert.Contains(lines, line => line.Contains("Untyped: Untyped value"));
|
||||
Assert.Contains(lines, line => line.Contains("If branch: True path executed"));
|
||||
Assert.Contains(lines, line => line.Contains("Switch: Case 2 executed"));
|
||||
Assert.Contains(lines, line => line.Contains("For loop: Completed with 3 iterations"));
|
||||
Assert.Contains(lines, line => line.Contains("While loop: Completed with 3 iterations"));
|
||||
Assert.Contains(lines, line => line.Contains("ForEach loop: Completed with 2 items processed"));
|
||||
|
||||
// Verify activities after Complete did NOT execute
|
||||
Assert.DoesNotContain(lines, line => line.Contains("After Complete (should not execute)"));
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Break activity works correctly in different loop contexts")]
|
||||
public async Task SmokeTest_BreakActivity_WorksInDifferentLoops()
|
||||
{
|
||||
// Act
|
||||
var (_, lines) = await RunWorkflowAndCaptureOutput();
|
||||
|
||||
// Assert - Verify Break worked in For loop (stopped at 3 iterations, not 100)
|
||||
Assert.Contains(lines, line => line.Contains("For loop: Completed with 3 iterations"));
|
||||
|
||||
// Verify Break worked in While loop (stopped at 3 iterations, didn't run infinitely)
|
||||
Assert.Contains(lines, line => line.Contains("While loop: Iteration 1"));
|
||||
Assert.Contains(lines, line => line.Contains("While loop: Iteration 2"));
|
||||
Assert.Contains(lines, line => line.Contains("While loop: Iteration 3"));
|
||||
Assert.Contains(lines, line => line.Contains("While loop: Completed with 3 iterations"));
|
||||
|
||||
// Verify Break worked in ForEach (stopped after 2 items: A, B, not C)
|
||||
Assert.Contains(lines, line => line.Contains("ForEach: Item 'A'"));
|
||||
Assert.Contains(lines, line => line.Contains("ForEach: Item 'B'"));
|
||||
Assert.DoesNotContain(lines, line => line.Contains("ForEach: Item 'C'"));
|
||||
Assert.Contains(lines, line => line.Contains("ForEach loop: Completed with 2 items processed"));
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Switch activity executes correct case")]
|
||||
public async Task SmokeTest_SwitchActivity_ExecutesCorrectCase()
|
||||
{
|
||||
// Act
|
||||
var (_, lines) = await RunWorkflowAndCaptureOutput();
|
||||
|
||||
// Assert - Only Case 2 should execute
|
||||
Assert.DoesNotContain(lines, line => line.Contains("Switch: Case 1 (should not execute)"));
|
||||
Assert.Contains(lines, line => line.Contains("Switch: Case 2 executed"));
|
||||
Assert.DoesNotContain(lines, line => line.Contains("Switch: Case 3 (should not execute)"));
|
||||
Assert.DoesNotContain(lines, line => line.Contains("Switch: Default (should not execute)"));
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "If activity executes correct branch")]
|
||||
public async Task SmokeTest_IfActivity_ExecutesCorrectBranch()
|
||||
{
|
||||
// Act
|
||||
var (_, lines) = await RunWorkflowAndCaptureOutput();
|
||||
|
||||
// Assert - Only Then branch should execute
|
||||
Assert.Contains(lines, line => line.Contains("If branch: True path executed"));
|
||||
Assert.DoesNotContain(lines, line => line.Contains("If branch: False path (should not execute)"));
|
||||
}
|
||||
|
||||
private async Task<(RunWorkflowResult Result, List<string> Lines)> RunWorkflowAndCaptureOutput()
|
||||
{
|
||||
var workflow = new ActivitiesSmokeTestWorkflow();
|
||||
var result = await _fixture.RunWorkflowAsync(workflow);
|
||||
var lines = _fixture.CapturingTextWriter.Lines.ToList();
|
||||
return (result, lines);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue