Skip to content

Commit 7e4279c

Browse files
committed
Refactor DistributedLockResilienceTests to simplify workflow client creation, consolidate assertion logic, and remove redundant test cases.
1 parent a70a649 commit 7e4279c

1 file changed

Lines changed: 35 additions & 67 deletions

File tree

test/component/Elsa.Workflows.ComponentTests/Scenarios/DistributedLockResilience/DistributedLockResilienceTests.cs

Lines changed: 35 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,7 @@ public async Task AcquireLockWithRetry_AcquisitionFailures_BehavesAsExpected(int
5959
public async Task RunInstanceAsync_TransientLockFailures_RetriesCorrectly(int failureCount, bool shouldThrow)
6060
{
6161
// Arrange
62-
var workflowRuntime = Scope.ServiceProvider.GetRequiredService<IWorkflowRuntime>();
63-
64-
// First, create the workflow instance to get its ID
65-
var createRequest = new CreateWorkflowInstanceRequest
66-
{
67-
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(SimpleWorkflow.DefinitionId, VersionOptions.Latest)
68-
};
69-
70-
var workflowClient = await workflowRuntime.CreateClientAsync();
71-
await workflowClient.CreateInstanceAsync(createRequest);
62+
var workflowClient = await CreateWorkflowClientAsync();
7263
var workflowInstanceId = workflowClient.WorkflowInstanceId;
7364

7465
// Reset and configure failures for this specific workflow instance's lock
@@ -82,98 +73,75 @@ public async Task RunInstanceAsync_TransientLockFailures_RetriesCorrectly(int fa
8273
// Act & Assert
8374
if (shouldThrow)
8475
{
85-
// Should throw after exhausting retries
8676
await Assert.ThrowsAsync<TimeoutException>(async () =>
8777
await workflowClient.RunInstanceAsync(runRequest));
8878
}
8979
else
9080
{
91-
// Should succeed after retries
9281
var response = await workflowClient.RunInstanceAsync(runRequest);
9382
Assert.NotNull(response);
9483
}
9584

9685
// Verify retries occurred - check the delta from before the operation to account for background noise
97-
var actualAttempts = MockProvider.AcquisitionAttemptCount - attemptCountBefore;
9886
var expectedAttempts = failureCount + 1; // failures + 1 success (or final failure for shouldThrow case)
99-
Assert.True(actualAttempts >= expectedAttempts,
100-
$"Expected at least {expectedAttempts} acquisition attempts, but got {actualAttempts}");
101-
}
102-
103-
[Fact]
104-
public async Task RunInstanceAsync_TransientLockFailureOnSecondRun_RetriesCorrectly()
105-
{
106-
// Arrange
107-
var workflowRuntime = Scope.ServiceProvider.GetRequiredService<IWorkflowRuntime>();
108-
109-
// First run - reset and don't inject failures
110-
MockProvider.Reset();
111-
var workflowClient = await workflowRuntime.CreateClientAsync();
112-
113-
var createRequest = new CreateAndRunWorkflowInstanceRequest
114-
{
115-
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(SimpleWorkflow.DefinitionId, VersionOptions.Latest)
116-
};
117-
118-
var firstResponse = await workflowClient.CreateAndRunInstanceAsync(createRequest);
119-
Assert.NotNull(firstResponse.WorkflowInstanceId);
120-
121-
// Verify first run succeeded (at least 1 attempt, possibly more from background workers)
122-
Assert.True(MockProvider.AcquisitionAttemptCount >= 1);
123-
124-
// Setup second workflow with failure - reset right before to minimize background noise
125-
MockProvider.Reset();
126-
MockProvider.FailAcquisitionTimes(2); // Fail twice, succeed on third
127-
128-
var secondClient = await workflowRuntime.CreateClientAsync();
129-
var secondResponse = await secondClient.CreateAndRunInstanceAsync(createRequest);
130-
131-
// Act & Assert - Second run should succeed after retries
132-
Assert.NotNull(secondResponse);
133-
Assert.NotNull(secondResponse.WorkflowInstanceId);
134-
Assert.NotEqual(firstResponse.WorkflowInstanceId, secondResponse.WorkflowInstanceId);
135-
136-
// Verify retries occurred (at least 3 attempts: 2 failures + 1 success, possibly more from background)
137-
Assert.True(MockProvider.AcquisitionAttemptCount >= 3,
138-
$"Expected at least 3 acquisition attempts, but got {MockProvider.AcquisitionAttemptCount}");
87+
AssertMinimumAttempts(MockProvider.AcquisitionAttemptCount - attemptCountBefore, expectedAttempts, "acquisition");
13988
}
14089

14190
[Fact]
14291
public async Task RunInstanceAsync_TransientReleaseFailure_ShouldLogButNotThrow()
14392
{
14493
// Arrange
14594
MockProvider.Reset();
146-
147-
var workflowRuntime = Scope.ServiceProvider.GetRequiredService<IWorkflowRuntime>();
148-
var workflowClient = await workflowRuntime.CreateClientAsync();
149-
150-
var createRequest = new CreateAndRunWorkflowInstanceRequest
151-
{
152-
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(SimpleWorkflow.DefinitionId, VersionOptions.Latest)
153-
};
95+
var workflowClient = await CreateWorkflowClientAsync(createInstance: false);
15496

15597
// Configure failure after client creation to minimize background interference
15698
MockProvider.FailReleaseOnce();
15799
var releaseCountBefore = MockProvider.ReleaseAttemptCount;
158100

159101
// Act - Release failure should be caught and logged, not thrown
160-
var response = await workflowClient.CreateAndRunInstanceAsync(createRequest);
102+
var response = await workflowClient.CreateAndRunInstanceAsync(CreateAndRunRequest());
161103

162104
// Assert
163105
Assert.NotNull(response);
164106
Assert.NotNull(response.WorkflowInstanceId);
165-
166-
// Verify at least one release occurred (allow for background noise)
167-
var actualReleaseAttempts = MockProvider.ReleaseAttemptCount - releaseCountBefore;
168-
Assert.True(actualReleaseAttempts >= 1,
169-
$"Expected at least 1 release attempt, but got {actualReleaseAttempts}");
107+
AssertMinimumAttempts(MockProvider.ReleaseAttemptCount - releaseCountBefore, 1, "release");
170108
}
171109

172110
private async Task<IDistributedSynchronizationHandle?> AcquireLockWithRetryAsync(string lockName) =>
173111
await RetryPipeline.ExecuteAsync(async ct =>
174112
await MockProvider.AcquireLockAsync(lockName, LockOptions.LockAcquisitionTimeout, ct),
175113
CancellationToken.None);
176114

115+
/// <summary>
116+
/// Creates a workflow client with an optional workflow instance already created.
117+
/// </summary>
118+
private async Task<IWorkflowClient> CreateWorkflowClientAsync(bool createInstance = true)
119+
{
120+
var workflowRuntime = Scope.ServiceProvider.GetRequiredService<IWorkflowRuntime>();
121+
var workflowClient = await workflowRuntime.CreateClientAsync();
122+
123+
if (createInstance)
124+
{
125+
var createRequest = new CreateWorkflowInstanceRequest
126+
{
127+
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(SimpleWorkflow.DefinitionId, VersionOptions.Latest)
128+
};
129+
await workflowClient.CreateInstanceAsync(createRequest);
130+
}
131+
132+
return workflowClient;
133+
}
134+
135+
private static CreateAndRunWorkflowInstanceRequest CreateAndRunRequest() =>
136+
new()
137+
{
138+
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(SimpleWorkflow.DefinitionId, VersionOptions.Latest)
139+
};
140+
141+
private static void AssertMinimumAttempts(int actualAttempts, int expectedAttempts, string attemptType) =>
142+
Assert.True(actualAttempts >= expectedAttempts,
143+
$"Expected at least {expectedAttempts} {attemptType} attempts, but got {actualAttempts}");
144+
177145
private static ResiliencePipeline CreateRetryPipeline(ITransientExceptionDetector transientExceptionDetector, ILogger logger) =>
178146
new ResiliencePipelineBuilder()
179147
.AddRetry(new()

0 commit comments

Comments
 (0)