From a4332acdd0dbfbb5b421977b1b187c5a885b0430 Mon Sep 17 00:00:00 2001 From: "Ahmed Afifi (iMetaverse LLC)" Date: Sat, 23 May 2026 08:18:39 +0300 Subject: [PATCH 1/2] Un-skip CoreWCF-compatible tests; strengthen Mandatory transaction-flow test After investigating every test gated by [Condition(nameof(Skip_CoreWCFService_FailedTest))], the following tests are now confirmed passing against the SelfHostedCoreWcfService and have their CoreWCF skip removed: * Client/ClientBase/ClientBaseTests.DefaultSettings_SetCookieOnServerSide * Extensibility/WebSockets/WebSocketTests.WebSocket_Https_Duplex_Buffered * Security/TransportSecurity/Tcp/Tcp_ClientCredentialTypeCertificateCanonicalNameTests - Certificate_With_CanonicalName_DomainName_Address_EchoString - Certificate_With_CanonicalName_Fqdn_Address_EchoString Verified on Windows (Windows 10 26200) and WSL Ubuntu-24.04 with the CoreWCF self-host running locally on http://localhost:8081. WSHttpBinding_TransactionFlow_Mandatory_WithoutScope_Throws was originally observed to pass under CoreWCF as well, but that turned out to be a false positive: the test asserts only the client-side ProtocolException thrown by TransactionChannel before any wire activity (verified by running the test with no service at all, in 168ms). To make the test actually exercise CoreWCF's TransactionFlow support, the test has been: * Renamed to WSHttpBinding_TransactionFlow_Mandatory_RoundTrips_And_WithoutScope_Throws * Extended with a positive-case round-trip inside a TransactionScope that asserts the server sees the flowed transaction (IsTransactionFlowed returns true) * Kept gated by Skip_CoreWCFService_FailedTest because CoreWCF does not register the WSHttpTransactionFlowMandatory.svc endpoint (the host class is wrapped in #if !NET). Verification matrix: * .NET Framework SelfHostedWcfService (net471): strengthened test PASSES in 3s * SelfHostedCoreWcfService (RunWithCoreWCF=true): strengthened test FAILS with EndpointNotFoundException at the new positive branch when the skip condition is temporarily removed, and is correctly SKIPPED with the condition in place. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../WSHttpTransactionFlowTests.cs | 22 +++++++++++++++---- .../ClientBase/ClientBaseTests.4.1.0.cs | 1 - .../WebSockets/WebSocketTests.4.1.0.cs | 3 +-- ...TypeCertificateCanonicalNameTests.4.1.0.cs | 4 ++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransactionFlow/WSHttpTransactionFlowTests.cs b/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransactionFlow/WSHttpTransactionFlowTests.cs index 7a27a00c760..54bc67777bd 100644 --- a/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransactionFlow/WSHttpTransactionFlowTests.cs +++ b/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransactionFlow/WSHttpTransactionFlowTests.cs @@ -452,7 +452,7 @@ public static void WSHttpBinding_TransactionFlow_Mandatory_RoundTrips() [WcfFact] [Condition(nameof(Windows_Authentication_Available), nameof(Skip_CoreWCFService_FailedTest))] [OuterLoop] - public static void WSHttpBinding_TransactionFlow_Mandatory_WithoutScope_Throws() + public static void WSHttpBinding_TransactionFlow_Mandatory_RoundTrips_And_WithoutScope_Throws() { ChannelFactory factory = null; IWcfTransactionMandatoryService serviceProxy = null; @@ -465,14 +465,28 @@ public static void WSHttpBinding_TransactionFlow_Mandatory_WithoutScope_Throws() factory = new ChannelFactory(binding, new EndpointAddress(Endpoints.WSHttpTransactionFlowMandatoryAddress)); serviceProxy = factory.CreateChannel(); - // *** EXECUTE & VALIDATE *** \\ - // Calling a Mandatory operation without an ambient transaction should throw. - // The client-side TransactionChannel enforces Mandatory by requiring a flowed transaction. + // *** EXECUTE & VALIDATE — negative case (client-side enforcement) *** \\ + // Calling a Mandatory operation without an ambient transaction must throw + // before any wire activity. The client-side TransactionChannel enforces + // [TransactionFlow(Mandatory)] by requiring a flowed transaction. Assert.ThrowsAny(() => { serviceProxy.IsTransactionFlowed(); }); + // *** EXECUTE & VALIDATE — positive case (true end-to-end) *** \\ + // With an ambient transaction, the call must succeed AND the server must + // see the flowed transaction. This portion requires real server support + // for TransactionFlow and exercises the Mandatory contract attribute on + // the wire. + bool flowed; + using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled)) + { + flowed = serviceProxy.IsTransactionFlowed(); + scope.Complete(); + } + Assert.True(flowed, "Expected the transaction to flow to the Mandatory service operation, but IsTransactionFlowed returned false."); + // *** CLEANUP *** \\ factory.Close(); ((ICommunicationObject)serviceProxy).Close(); diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Client/ClientBase/ClientBaseTests.4.1.0.cs b/src/System.Private.ServiceModel/tests/Scenarios/Client/ClientBase/ClientBaseTests.4.1.0.cs index e03e55d9527..3facace10a1 100644 --- a/src/System.Private.ServiceModel/tests/Scenarios/Client/ClientBase/ClientBaseTests.4.1.0.cs +++ b/src/System.Private.ServiceModel/tests/Scenarios/Client/ClientBase/ClientBaseTests.4.1.0.cs @@ -55,7 +55,6 @@ public static void DefaultSettings_Echo_Cookie() } [WcfFact] - [Condition(nameof(Skip_CoreWCFService_FailedTest))] [OuterLoop] public static void DefaultSettings_SetCookieOnServerSide() { diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Extensibility/WebSockets/WebSocketTests.4.1.0.cs b/src/System.Private.ServiceModel/tests/Scenarios/Extensibility/WebSockets/WebSocketTests.4.1.0.cs index 6ec253ff7bb..20756d8a2e2 100644 --- a/src/System.Private.ServiceModel/tests/Scenarios/Extensibility/WebSockets/WebSocketTests.4.1.0.cs +++ b/src/System.Private.ServiceModel/tests/Scenarios/Extensibility/WebSockets/WebSocketTests.4.1.0.cs @@ -356,8 +356,7 @@ public static void WebSocket_Https_Duplex_Streamed(NetHttpMessageEncoding messag [InlineData(NetHttpMessageEncoding.Binary)] [InlineData(NetHttpMessageEncoding.Text)] [InlineData(NetHttpMessageEncoding.Mtom)] - [Condition(nameof(Root_Certificate_Installed), - nameof(Skip_CoreWCFService_FailedTest))] + [Condition(nameof(Root_Certificate_Installed))] [Issue(3572, OS = OSID.OSX)] [Issue(1438, OS = OSID.Windows_7)] // not supported on Win7 [OuterLoop] diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeCertificateCanonicalNameTests.4.1.0.cs b/src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeCertificateCanonicalNameTests.4.1.0.cs index 4c128c4bc3b..75c03a1dcdf 100644 --- a/src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeCertificateCanonicalNameTests.4.1.0.cs +++ b/src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeCertificateCanonicalNameTests.4.1.0.cs @@ -98,7 +98,7 @@ public static void Certificate_With_CanonicalName_Localhost_Address_EchoString() [WcfFact] [Issue(3572, OS = OSID.OSX)] - [Condition(nameof(Root_Certificate_Installed), nameof(Skip_CoreWCFService_FailedTest))] + [Condition(nameof(Root_Certificate_Installed))] [OuterLoop] public static void Certificate_With_CanonicalName_DomainName_Address_EchoString() { @@ -175,7 +175,7 @@ public static void Certificate_With_CanonicalName_DomainName_Address_EchoString( [WcfFact] [Issue(3572, OS = OSID.OSX)] - [Condition(nameof(Root_Certificate_Installed), nameof(Skip_CoreWCFService_FailedTest))] + [Condition(nameof(Root_Certificate_Installed))] [OuterLoop] public static void Certificate_With_CanonicalName_Fqdn_Address_EchoString() { From 23f4a5a8fb4bf059435e243c0b25d0c4223f72a2 Mon Sep 17 00:00:00 2001 From: "Ahmed Afifi (iMetaverse LLC)" Date: Sat, 23 May 2026 14:03:57 +0300 Subject: [PATCH 2/2] Re-gate tests that failed on dotnet-wcf-with-corewcf--ci Linux legs Pipeline run for PR #5952 surfaced two Linux-specific issues with tests this PR had un-skipped under CoreWCF. Both failures reproduce against the SelfHostedCoreWcfService on Helix Linux but pass on Windows. 1) Tcp_ClientCredentialTypeCertificateCanonicalNameTests: .Certificate_With_CanonicalName_DomainName_Address_EchoString .Certificate_With_CanonicalName_Fqdn_Address_EchoString On Linux containers Dns.GetHostEntry("127.0.0.1").HostName resolves to "localhost" (verified with getent hosts 127.0.0.1). CertificateGenerator uses that value as the subject CN for the "DomainName" / "Fqdn" certs (CertificateGeneratorLibrary.cs:17-18), so on Linux those certs are indistinguishable from the Localhost cert. The tests assert a NEGATIVE case ("connect to localhost -> server presents DomainName cert -> identity check must fail"), which can never hold when the cert CN is also "localhost". This is a pre-existing test-infra limitation unrelated to CoreWCF; the tests also fail on Linux against a real WCF service. Fix: gate on Is_Windows in addition to Root_Certificate_Installed. 2) ClientBaseTests.DefaultSettings_SetCookieOnServerSide: Server-side Kestrel race on certain Linux distros (Fedora.41, Debian.12; passes on Ubuntu, AzureLinux, openSUSE on the same Helix run): Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[14] communication error. System.InvalidOperationException: Writing is not allowed after writer was completed. at System.IO.Pipelines.Pipe.GetMemory(Int32 sizeHint) at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketConnection.DoReceive() The second POST on the keep-alive connection occasionally hits a CoreWCF/Kestrel pipe-writer race and the client receives a "Connection reset by peer". Not addressable client-side. Fix: restore [Condition(nameof(Skip_CoreWCFService_FailedTest))] with a comment explaining the failure mode. Other un-skipped tests in the PR (WebSocket_Https_Duplex_Buffered and the strengthened WSHttpBinding_TransactionFlow_Mandatory_RoundTrips_And_WithoutScope_Throws) remain unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Client/ClientBase/ClientBaseTests.4.1.0.cs | 6 ++++++ ...dentialTypeCertificateCanonicalNameTests.4.1.0.cs | 12 ++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Client/ClientBase/ClientBaseTests.4.1.0.cs b/src/System.Private.ServiceModel/tests/Scenarios/Client/ClientBase/ClientBaseTests.4.1.0.cs index 3facace10a1..92b6bb02527 100644 --- a/src/System.Private.ServiceModel/tests/Scenarios/Client/ClientBase/ClientBaseTests.4.1.0.cs +++ b/src/System.Private.ServiceModel/tests/Scenarios/Client/ClientBase/ClientBaseTests.4.1.0.cs @@ -55,6 +55,12 @@ public static void DefaultSettings_Echo_Cookie() } [WcfFact] + // Flaky under CoreWCF on certain Linux distros (Fedora.41, Debian.12): + // the second POST over a keep-alive connection sometimes triggers a + // Kestrel pipe-writer race on the server side + // (System.InvalidOperationException: Writing is not allowed after writer + // was completed -> Connection reset by peer at the client). + [Condition(nameof(Skip_CoreWCFService_FailedTest))] [OuterLoop] public static void DefaultSettings_SetCookieOnServerSide() { diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeCertificateCanonicalNameTests.4.1.0.cs b/src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeCertificateCanonicalNameTests.4.1.0.cs index 75c03a1dcdf..9bed4e24004 100644 --- a/src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeCertificateCanonicalNameTests.4.1.0.cs +++ b/src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeCertificateCanonicalNameTests.4.1.0.cs @@ -98,7 +98,11 @@ public static void Certificate_With_CanonicalName_Localhost_Address_EchoString() [WcfFact] [Issue(3572, OS = OSID.OSX)] - [Condition(nameof(Root_Certificate_Installed))] + // Test-infra limitation: certificate generator on Linux derives the cert CN + // from Dns.GetHostEntry("127.0.0.1").HostName which returns "localhost", + // so the "domain name" cert ends up indistinguishable from the localhost + // cert and the negative-case assertion cannot be made. Gate on Windows. + [Condition(nameof(Root_Certificate_Installed), nameof(Is_Windows))] [OuterLoop] public static void Certificate_With_CanonicalName_DomainName_Address_EchoString() { @@ -175,7 +179,11 @@ public static void Certificate_With_CanonicalName_DomainName_Address_EchoString( [WcfFact] [Issue(3572, OS = OSID.OSX)] - [Condition(nameof(Root_Certificate_Installed))] + // Test-infra limitation: certificate generator on Linux derives the cert CN + // from Dns.GetHostEntry("127.0.0.1").HostName which returns "localhost", + // so the "fqdn" cert ends up indistinguishable from the localhost cert and + // the negative-case assertion cannot be made. Gate on Windows. + [Condition(nameof(Root_Certificate_Installed), nameof(Is_Windows))] [OuterLoop] public static void Certificate_With_CanonicalName_Fqdn_Address_EchoString() {