Skip to content

Commit b12b1ae

Browse files
author
Renan Pereira
committed
Fixing race condition
1 parent a2098ae commit b12b1ae

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ public ExpressionPromoter(ParsingConfig config)
5050
}
5151
else
5252
{
53-
if (_constantExpressionHelper.TryGetText(ce, out var text))
53+
if (!_constantExpressionHelper.TryGetText(ce, out var text))
54+
{
55+
text = ce.Value?.ToString();
56+
}
57+
58+
if (text != null)
5459
{
5560
Type target = TypeHelper.GetNonNullableType(type);
5661
object? value = null;

test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionPromoterTests.cs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
using Moq;
1+
using FluentAssertions;
2+
using Moq;
23
using System.Collections.Generic;
34
using System.Linq.Dynamic.Core.CustomTypeProviders;
45
using System.Linq.Dynamic.Core.Parser;
56
using System.Linq.Expressions;
7+
using System.Threading.Tasks;
8+
using System.Threading;
69
using Xunit;
710

811
namespace System.Linq.Dynamic.Core.Tests.Parser;
@@ -53,4 +56,49 @@ public void DynamicExpressionParser_ParseLambda_WithCustomExpressionPromoter()
5356

5457
_expressionPromoterMock.Verify(e => e.Promote(It.IsAny<ConstantExpression>(), typeof(Guid), true, true), Times.Once);
5558
}
59+
60+
[Fact]
61+
public async Task Promote_Should_Succeed_Even_When_LiteralsCache_Is_Cleaned()
62+
{
63+
// Arrange
64+
var parsingConfig = new ParsingConfig()
65+
{
66+
ConstantExpressionCacheConfig = new Core.Util.Cache.CacheConfig
67+
{
68+
CleanupFrequency = TimeSpan.FromMilliseconds(500), // Run cleanup more often
69+
TimeToLive = TimeSpan.FromMilliseconds(500), // Shorten TTL to force expiration
70+
ReturnExpiredItems = false
71+
}
72+
};
73+
var constantExpressionHelper = ConstantExpressionHelperFactory.GetInstance(parsingConfig);
74+
var expressionPromoter = new ExpressionPromoter(parsingConfig);
75+
76+
double value = 0.40;
77+
string text = "0.40";
78+
Type targetType = typeof(decimal);
79+
80+
// Step 1: Add constant to cache
81+
var literalExpression = constantExpressionHelper.CreateLiteral(value, text);
82+
Assert.NotNull(literalExpression); // Ensure it was added
83+
84+
// Step 2: Manually trigger cleanup
85+
var cts = new CancellationTokenSource(500);
86+
await Task.Run(async () =>
87+
{
88+
while (!cts.IsCancellationRequested)
89+
{
90+
constantExpressionHelper.TryGetText(literalExpression, out _);
91+
await Task.Delay(50); // Give some time for cleanup to be triggered
92+
}
93+
});
94+
95+
// Ensure some cleanup cycles have passed
96+
await Task.Delay(500); // Allow cache cleanup to happen
97+
98+
// Step 3: Attempt to promote the expression after cleanup
99+
var promotedExpression = expressionPromoter.Promote(literalExpression, targetType, exact: false, convertExpression: true);
100+
101+
// Assert: Promotion should still work even if the cache was cleaned
102+
promotedExpression.Should().NotBeNull(); // Ensure `Promote()` still returns a valid expression
103+
}
56104
}

0 commit comments

Comments
 (0)