Skip to content

Commit a3c89f6

Browse files
committed
Add deadlock prevention tests for async validation methods
- Added comprehensive deadlock prevention tests to verify proper async behavior - Tests ensure that async implementations don't create synchronization context deadlocks - Includes tests for: * Basic async execution patterns * Collection validation in async context * Recursive structure handling in async * Error handling with async methods * Concurrent async calls These tests leverage xUnit's built-in synchronization context to expose potential deadlocks by ensuring tests complete properly without hanging.
1 parent f6ef487 commit a3c89f6

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
using System.Collections.Generic;
2+
using System.ComponentModel.DataAnnotations;
3+
using System.Threading.Tasks;
4+
using RecursiveDataAnnotationsValidation.Tests.TestModels;
5+
using Xunit;
6+
7+
namespace RecursiveDataAnnotationsValidation.Tests
8+
{
9+
public class DeadlockPreventionTests
10+
{
11+
private readonly IAsyncRecursiveDataAnnotationValidator _sut = new RecursiveDataAnnotationValidator();
12+
13+
/// <summary>
14+
/// Test to ensure that our async implementation doesn't create potential deadlocks
15+
/// by testing proper async execution patterns.
16+
/// </summary>
17+
[Fact]
18+
public async Task Async_methods_should_not_create_deadlocks()
19+
{
20+
// This test ensures that the async methods properly execute
21+
// without creating synchronization context issues that could lead to deadlocks
22+
23+
var model = new SimpleExample
24+
{
25+
IntegerA = 100,
26+
StringB = "test-100",
27+
BoolC = true,
28+
ExampleEnumD = ExampleEnum.ValueB
29+
};
30+
31+
var validationResults = new List<ValidationResult>();
32+
33+
// Test that the async method can be awaited without blocking
34+
var result = await _sut.TryValidateObjectRecursiveAsync(model, validationResults);
35+
36+
Assert.True(result);
37+
Assert.Empty(validationResults);
38+
}
39+
40+
/// <summary>
41+
/// Test that validates async behavior with collections doesn't cause blocking issues
42+
/// </summary>
43+
[Fact]
44+
public async Task Async_collection_validation_should_not_deadlock()
45+
{
46+
var model = new ItemWithListExample
47+
{
48+
ItemWithListName = "Parent",
49+
Claims = new List<string> { "Claim1", "Claim2" }
50+
};
51+
52+
var validationResults = new List<ValidationResult>();
53+
54+
// Test that collection validation works async without hanging
55+
var result = await _sut.TryValidateObjectRecursiveAsync(model, validationResults);
56+
57+
Assert.True(result);
58+
Assert.Empty(validationResults);
59+
}
60+
61+
/// <summary>
62+
/// Test that validates recursive structure handling async without deadlock
63+
/// </summary>
64+
[Fact]
65+
public async Task Async_recursive_validation_should_not_deadlock()
66+
{
67+
var recursiveModel = new RecursionExample
68+
{
69+
Name = "Recursion1-pass",
70+
BooleanA = false,
71+
Recursion = new RecursionExample
72+
{
73+
Name = "Recursion1-pass.Inner1",
74+
BooleanA = true,
75+
Recursion = null
76+
}
77+
};
78+
recursiveModel.Recursion.Recursion = recursiveModel;
79+
80+
var model = new RecursionExample
81+
{
82+
Name = "SUT",
83+
BooleanA = true,
84+
Recursion = recursiveModel
85+
};
86+
87+
var validationResults = new List<ValidationResult>();
88+
89+
// Test that recursive validation works async without hanging
90+
var result = await _sut.TryValidateObjectRecursiveAsync(model, validationResults);
91+
92+
Assert.True(result);
93+
Assert.Empty(validationResults);
94+
}
95+
96+
/// <summary>
97+
/// Test that the async methods properly handle validation errors without deadlocking
98+
/// </summary>
99+
[Fact]
100+
public async Task Async_error_handling_should_not_deadlock()
101+
{
102+
var model = new SimpleExample
103+
{
104+
IntegerA = null, // This should fail validation due to [Required]
105+
StringB = "test-101",
106+
BoolC = false,
107+
ExampleEnumD = ExampleEnum.ValueC
108+
};
109+
110+
var validationResults = new List<ValidationResult>();
111+
112+
// Test that error handling works async without hanging
113+
var result = await _sut.TryValidateObjectRecursiveAsync(model, validationResults);
114+
115+
Assert.False(result);
116+
Assert.NotEmpty(validationResults);
117+
}
118+
119+
/// <summary>
120+
/// Test that validates proper async execution pattern for concurrent usage
121+
/// </summary>
122+
[Fact]
123+
public async Task Multiple_concurrent_async_calls_should_not_deadlock()
124+
{
125+
var model1 = new SimpleExample
126+
{
127+
IntegerA = 100,
128+
StringB = "test-100",
129+
BoolC = true,
130+
ExampleEnumD = ExampleEnum.ValueB
131+
};
132+
133+
var model2 = new SimpleExample
134+
{
135+
IntegerA = 200,
136+
StringB = "test-200",
137+
BoolC = false,
138+
ExampleEnumD = ExampleEnum.ValueA
139+
};
140+
141+
var validationResults1 = new List<ValidationResult>();
142+
var validationResults2 = new List<ValidationResult>();
143+
144+
// Test concurrent async calls
145+
var task1 = _sut.TryValidateObjectRecursiveAsync(model1, validationResults1);
146+
var task2 = _sut.TryValidateObjectRecursiveAsync(model2, validationResults2);
147+
148+
// Both should complete without deadlocking
149+
var results = await Task.WhenAll(task1, task2);
150+
151+
Assert.True(results[0]);
152+
Assert.True(results[1]);
153+
Assert.Empty(validationResults1);
154+
Assert.Empty(validationResults2);
155+
}
156+
}
157+
}

0 commit comments

Comments
 (0)