This is an automated email from the ASF dual-hosted git repository.

FreeAndNil pushed a commit to branch Feature/305-dotnet-10-build-cleanup
in repository https://gitbox.apache.org/repos/asf/logging-log4net.git

commit bc298db91ae8b45b0f2e7b2f69981d3d64394187
Author: Jan Friedrich <[email protected]>
AuthorDate: Tue Aug 4 23:37:41 2026 +0200

    Quieten the TelnetAppender test
    
      Dispose disposed the TcpClient while the reader was blocked in
      stream.Read, so teardown always aborted the socket and dumped an
      IOException with a stack trace, even on a passing run. Shut the socket
      down first, so the read returns 0 and the loop ends normally, and only
      report exceptions that arrive before disposal. Progress chatter removed;
      the test now prints nothing unless it fails.
    
      Two things this fixes beyond the noise:
    
      - The cancellation token never actually stopped the loop. The check ran 
only after a successful read, so the reader
      could only be broken by disposing the socket under it. Now 
Shutdown(SocketShutdown.Both) ends the stream and the loop
      exits through its normal condition.
      - Diagnostics are preserved for real failures. log is still wired to 
TestContext.Out.WriteLine, gated on !_disposing - so a genuine client error 
still surfaces, and Assert.Fail on timeout still reports what was received.
---
 .../Appender/Internal/SimpleTelnetClient.cs        | 47 +++++++++++++++-------
 src/log4net.Tests/Appender/TelnetAppenderTest.cs   |  5 ---
 2 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/src/log4net.Tests/Appender/Internal/SimpleTelnetClient.cs 
b/src/log4net.Tests/Appender/Internal/SimpleTelnetClient.cs
index 38f104ff..bc13c8c9 100644
--- a/src/log4net.Tests/Appender/Internal/SimpleTelnetClient.cs
+++ b/src/log4net.Tests/Appender/Internal/SimpleTelnetClient.cs
@@ -38,59 +38,78 @@ internal sealed class SimpleTelnetClient(
 {
   private readonly CancellationTokenSource _cancellationTokenSource = new();
   private readonly TcpClient _client = new();
+  private volatile bool _disposing;
 
   /// <summary>
   /// Runs the client (in a task)
   /// </summary>
+  /// <param name="log">Callback for unexpected errors - a passing run stays 
silent</param>
   internal void Run(Action<string> log) => Task.Run(() =>
   {
     try
     {
-      log("client: starting ...");
       _client.Connect(new IPEndPoint(IPAddress.Loopback, port));
-      log("client: connected");
       // Get a stream object for reading and writing
       using NetworkStream stream = _client.GetStream();
-      log("client: has stream");
 
       int i;
       byte[] bytes = new byte[256];
 
-      // Loop to receive all the data sent by the server
+      // Loop to receive all the data sent by the server. Dispose shuts the 
socket down,
+      // which ends the stream, so this read returns 0 and the loop exits 
without throwing.
       while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
       {
-        string data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
-        log("client: read: " + data);
-        received(data);
+        received(System.Text.Encoding.ASCII.GetString(bytes, 0, i));
         if (_cancellationTokenSource.Token.IsCancellationRequested)
         {
-          log("client: canceled");
           return;
         }
       }
-      log("client: end of stream");
     }
     // The test asserts on the received data, so a failing client must not end 
up
-    // as an unobserved task exception - log it instead.
+    // as an unobserved task exception - log it instead. Anything thrown once 
Dispose
+    // has started is teardown noise, so only genuine failures reach the 
output.
     catch (SocketException e)
     {
-      log("client: error: " + e);
+      Report(e);
     }
     catch (IOException e)
     {
-      log("client: error: " + e);
+      Report(e);
     }
     catch (ObjectDisposedException e)
     {
-      // expected when the client is disposed while reading
-      log("client: disposed: " + e.Message);
+      Report(e);
+    }
+
+    void Report(Exception e)
+    {
+      if (!_disposing)
+      {
+        log("client: error: " + e);
+      }
     }
   }, _cancellationTokenSource.Token);
 
   /// <inheritdoc/>
   public void Dispose()
   {
+    _disposing = true;
     _cancellationTokenSource.Cancel();
+    // Shut the socket down before disposing it: that ends the stream cleanly, 
so a read
+    // blocked in Run returns 0 instead of failing with a connection abort.
+    try
+    {
+      _client.Client?.Shutdown(SocketShutdown.Both);
+    }
+    catch (SocketException)
+    {
+      // not connected - nothing to shut down
+    }
+    catch (ObjectDisposedException)
+    {
+      // already disposed - nothing to shut down
+    }
     _cancellationTokenSource.Dispose();
     _client.Dispose();
   }
diff --git a/src/log4net.Tests/Appender/TelnetAppenderTest.cs 
b/src/log4net.Tests/Appender/TelnetAppenderTest.cs
index 9596f065..e8cf95ec 100644
--- a/src/log4net.Tests/Appender/TelnetAppenderTest.cs
+++ b/src/log4net.Tests/Appender/TelnetAppenderTest.cs
@@ -86,15 +86,11 @@ public void TelnetTest()
     {
       using (SimpleTelnetClient telnetClient = new(Received, port))
       {
-        TestContext.Out.WriteLine("test: starting client ...");
         telnetClient.Run(TestContext.Out.WriteLine);
         WaitForReceived("welcome message", WelcomeMessage);
         ILogger logger = repository.GetLogger("Telnet");
-        TestContext.Out.WriteLine("test: logging to client ...");
         logger.Log(typeof(TelnetAppenderTest), Level.Info, logId, null);
-        TestContext.Out.WriteLine("test: waiting for message of client ...");
         WaitForReceived("log message", logId);
-        TestContext.Out.WriteLine("test: canceling client ...");
       }
     }
     finally
@@ -130,7 +126,6 @@ void WaitForReceived(string what, string expected)
         }
         Thread.Sleep(20);
       }
-      TestContext.Out.WriteLine($"receiver: received {what} after 
{stopwatch.ElapsedMilliseconds} ms");
     }
   }
 

Reply via email to