Skip to content

Conversation

@danielcrenna
Copy link

This pull request stabilizes multiple issues, particular in .NET 4.6.2 and .NET 4.8, that prevented running unit tests in parallel end-to-end.

This addresses #7 as well as test isolation issues preventing stable parallel test runs, and platform warnings for the use of unsupported/untested framework libraries from transitive assemblies.

It also addresses flaws in Tuple backwards compatibility in .NET 4.6.2, with some limitations.

image

danielcrenna and others added 16 commits August 5, 2025 17:11
Later versions of System.Text.Json and its transitive assemblies don't support .NET 6, forcing a suppression of a warning by Microsoft that the configuration is unsupported and used at our own risk.��To mitigate this, we can choose appropriate dependencies for each TFM to avoid taking on this risk.��Corrected Warnings:�System.Text.Json 9.0.8 doesn't support net6.0 and has not been tested with it. Consider upgrading your TargetFramework to net8.0 or later. You may also set <SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings> in the project file to ignore this warning and attempt to run in this unsupported configuration at your own risk.
System.Text.Encodings.Web 9.0.8 doesn't support net6.0 and has not been tested with it. Consider upgrading your TargetFramework to net8.0 or later. You may also set <SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings> in the project file to ignore this warning and attempt to run in this unsupported configuration at your own risk.
System.IO.Pipelines 9.0.8 doesn't support net6.0 and has not been tested with it. Consider upgrading your TargetFramework to net8.0 or later. You may also set <SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings> in the project file to ignore this warning and attempt to run in this unsupported configuration at your own risk.
Microsoft.Bcl.AsyncInterfaces 9.0.8 doesn't support net6.0 and has not been tested with it. Consider upgrading your TargetFramework to net8.0 or later. You may also set <SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings> in the project file to ignore this warning and attempt to run in this unsupported configuration at your own risk.
… due to scientific notation and epsilon differences
This causes test failures when running multiple TFMs in parallel. We need to build a sync primitive around adding type handlers to avoid race conditions.
…TTP handling between frameworks��Try to match the .NET Core sockets parameters
In .NET Framework TFMs, when running thousands of tests in parallel over HTTP, we can exhaust ports due to too many created connections. So we have to pool a reasonable number of them to unblock execution.��The default pool implementation is still suspect, as it creates an HttpClient on every single request, obviating the benefit of a factory.
… TFM because the Tuple polyfill uses object arrays due to missing ITuple, which will not conform to the way these types are consumed in library code at runtime, causing multiple test failures, and likely issues for consumers using them.
…due to differences in CH vs. client wall time
…FMs, due to tight timeout windows, the internal WebException on request timeout might throw before TaskCanceledException does, causing a false failure.
internal sealed class TestPoolHttpClientFactory : IHttpClientFactory
{
#if NETFRAMEWORK
private const int PoolSize = 16;
Copy link
Collaborator

@alex-clickhouse alex-clickhouse Nov 7, 2025

Choose a reason for hiding this comment

The 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...

Copy link
Author

Choose a reason for hiding this comment

The 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.

@alex-clickhouse
Copy link
Collaborator

Thanks for this, it's really valuable.

I think 094b9bd is not a good idea, referencing all those different versions plus the workarounds needed on top is overkill just to get rid of the warning. The packages are still compatible, just unsupported.

.Select(sample => new TestCaseData($"SELECT {{value:{sample.ClickHouseType}}}", sample.ExampleValue));

static DapperTests()
private static readonly object TypeHandlerLock = new();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary, the different TFMs should be running in separate processes, right? How do we get interference here?

@codecov
Copy link

codecov bot commented Nov 7, 2025

Codecov Report

❌ Patch coverage is 10.00000% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
ClickHouse.Driver/Types/JsonType.cs 10.00% 3 Missing and 6 partials ⚠️

📢 Thoughts on this report? Let us know!

{
private const double DefaultEpsilon = 1e-7;

public static void AssertFloatingPointEquals(this string actualResult, object expectedValue, double epsilon = DefaultEpsilon)
Copy link
Collaborator

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.

@alex-clickhouse
Copy link
Collaborator

The whole tuple thing feels a bit clunky, and a lot of extra code with a lot of #ifs to support an edge case...how big is the benefit compared to returning a plan array, and is it worth the downsides?

@danielcrenna
Copy link
Author

The whole tuple thing feels a bit clunky, and a lot of extra code with a lot of #ifs to support an edge case...how big is the benefit compared to returning a plan array, and is it worth the downsides?

If it were me, I would likely want to know how many customers are actually using this TFM, and consider dropping support for it. The Tuple logic is verbose, but it wasn't possible to avoid intermittent test failures for this TFM without it. My approach was to run the unit tests continuously to surface these variable failures, and removing this will resurface those failures.

I have been away travelling for work but will dig into your PR comments and attempt to address or provide background for each.

@danielcrenna
Copy link
Author

Thanks for this, it's really valuable.

I think 094b9bd is not a good idea, referencing all those different versions plus the workarounds needed on top is overkill just to get rid of the warning. The packages are still compatible, just unsupported.

This is fair, I was under the impression based on the code evolution that this was unintended, and I decided to avoid unsupported paths that ship to customers in case they conflict or produce side effects with those solutions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants