-
Notifications
You must be signed in to change notification settings - Fork 7
Stabilize tests to run locally and parallel across all TFMs #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a2cb6a4
094b9bd
c23c132
7a623ca
3d63021
90d14ae
2bc74f5
4c82b9c
51b3f4c
69abc16
ad0d5c5
aa401ad
fc93515
6859550
9cb1203
8e12777
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| using System; | ||
| using System.Globalization; | ||
|
|
||
| namespace ClickHouse.Driver.Tests.Extensions; | ||
|
|
||
| internal static class AssertionExtensions | ||
| { | ||
| private const double DefaultEpsilon = 1e-7; | ||
|
|
||
| public static void AssertFloatingPointEquals(this string actualResult, object expectedValue, double epsilon = DefaultEpsilon) | ||
| { | ||
| switch (expectedValue) | ||
| { | ||
| case float @float: | ||
| float.Parse(actualResult, CultureInfo.InvariantCulture).AssertFloatingPointEquals(@float, (float)epsilon); | ||
| break; | ||
| case double @double: | ||
| double.Parse(actualResult, CultureInfo.InvariantCulture).AssertFloatingPointEquals(@double, epsilon); | ||
| break; | ||
| default: | ||
| var expected = Convert.ToString(expectedValue, CultureInfo.InvariantCulture); | ||
| Assert.That(actualResult, Is.EqualTo(expected)); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| public static void AssertFloatingPointEquals(this double actual, double expected, double epsilon = DefaultEpsilon) | ||
| { | ||
| Assert.That(Math.Abs(actual - expected), Is.LessThan(epsilon), | ||
| $"Expected: {expected}, Actual: {actual}"); | ||
| } | ||
|
|
||
| public static void AssertFloatingPointEquals(this float actual, float expected, float epsilon = (float)DefaultEpsilon) | ||
| { | ||
| Assert.That(Math.Abs(actual - expected), Is.LessThan(epsilon), | ||
| $"Expected: {expected}, Actual: {actual}"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| using System; | ||
| using System.Collections.Concurrent; | ||
| using System.Net; | ||
| using System.Net.Http; | ||
| using System.Threading; | ||
|
|
||
| namespace ClickHouse.Driver.Tests.Infrastructure; | ||
|
|
||
| /// <summary> | ||
| /// HttpClientFactory that uses connection pooling to prevent port exhaustion during heavy parallel load in .NET Framework TFMs. | ||
| /// </summary> | ||
| internal sealed class TestPoolHttpClientFactory : IHttpClientFactory | ||
| { | ||
| #if NETFRAMEWORK | ||
| private const int PoolSize = 16; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need a pool of Handlers here? If port exhaustion is an issue I don't see how this fixes it...
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that on first look, we shouldn't need this, but the way these connections are managed in this TFM, it's not possible to get a clean test run end to end (after multiple repetitions) without it. Easiest confirmation is to remove this to see the reproduction eventually. I can take another look at the internals to try to avoid this, but my instinct is very few actual users are using this TFM. Most will use .NET 4.8 and I believe this TFM should be dropped to enable much better performance and availability of lower level memory primitives, which is why I decided to build my own driver. But I can review this to complete the PR. I do want to get in touch with you directly, if possible, about this work. |
||
| private static readonly ConcurrentBag<HttpClientHandler> HandlerPool = new ConcurrentBag<HttpClientHandler>(); | ||
| private static readonly int[] Slots = new int[1]; | ||
| private static readonly HttpClientHandler[] Handlers; | ||
|
|
||
| static TestPoolHttpClientFactory() | ||
| { | ||
| Handlers = new HttpClientHandler[PoolSize]; | ||
| for (int i = 0; i < PoolSize; i++) | ||
| { | ||
| var handler = new HttpClientHandler() | ||
| { | ||
| AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, | ||
| MaxConnectionsPerServer = 100, | ||
| UseProxy = false | ||
| }; | ||
| Handlers[i] = handler; | ||
| HandlerPool.Add(handler); | ||
| } | ||
| } | ||
|
|
||
| public TimeSpan Timeout { get; init; } = TimeSpan.FromMinutes(2); | ||
|
|
||
| public HttpClient CreateClient(string name) | ||
| { | ||
| var index = (uint)Interlocked.Increment(ref Slots[0]) % PoolSize; | ||
| return new HttpClient(Handlers[index], false) { Timeout = Timeout }; | ||
| } | ||
| #else | ||
| private static readonly HttpClientHandler DefaultHttpClientHandler = new() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }; | ||
|
|
||
| public TimeSpan Timeout { get; init; } = TimeSpan.FromMinutes(2); | ||
|
|
||
| public HttpClient CreateClient(string name) => new(DefaultHttpClientHandler, false) { Timeout = Timeout }; | ||
| #endif | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a global DefaultFloatingPointTolerance for the whole project now, we can just parse the string and compare using the regular NUnit method.