improve socket timout tests (dotnet/corefx#41078)
authorTomas Weinfurt <tweinfurt@yahoo.com>
Tue, 17 Sep 2019 13:16:25 +0000 (06:16 -0700)
committerStephen Toub <stoub@microsoft.com>
Tue, 17 Sep 2019 13:16:25 +0000 (09:16 -0400)
* improve socket timout tests

* feedback from review

Commit migrated from https://github.com/dotnet/corefx/commit/938b24dc397e11eab8688deca71ecd13ffc6fa4a

src/libraries/System.Net.Sockets/src/System/Net/Sockets/SafeSocketHandle.Unix.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs
src/libraries/System.Net.Sockets/tests/FunctionalTests/TimeoutTest.cs

index 06e4d33..2972b63 100644 (file)
@@ -144,6 +144,14 @@ namespace System.Net.Sockets
             }
         }
 
+        internal bool IsUnderlyingBlocking
+        {
+            get
+            {
+                return !_underlyingHandleNonBlocking;
+            }
+        }
+
         internal int ReceiveTimeout
         {
             get
index b9392eb..0399459 100644 (file)
@@ -703,6 +703,8 @@ namespace System.Net.Sockets
         public static bool TryCompleteSendTo(SafeSocketHandle socket, ReadOnlySpan<byte> buffer, IList<ArraySegment<byte>> buffers, ref int bufferIndex, ref int offset, ref int count, SocketFlags flags, byte[] socketAddress, int socketAddressLen, ref int bytesSent, out SocketError errorCode)
         {
             bool successfulSend = false;
+            long start = socket.IsUnderlyingBlocking && socket.SendTimeout > 0 ? Environment.TickCount64 : 0; // Get ticks only if timeout is set and socket is blocking.
+
             while (true)
             {
                 int sent;
@@ -743,6 +745,17 @@ namespace System.Net.Sockets
                     errorCode = SocketError.Success;
                     return true;
                 }
+
+                if (socket.IsUnderlyingBlocking && socket.SendTimeout > 0 && (Environment.TickCount64 - start) >= socket.SendTimeout)
+                {
+                    // When socket is truly in blocking mode, we depend on OS to enforce send timeout.
+                    // When we are here we had partial send when we neither completed or failed.
+                    // If we loop again, OS will wait another configured timeout before returning from system call.
+                    // This block check checks is we used all our timer across all iterations.
+                    errorCode = SocketError.TimedOut;
+                    return true;
+                }
+
             }
         }
 
index 983c894..8e858aa 100644 (file)
@@ -7,9 +7,9 @@ using Xunit;
 
 namespace System.Net.Sockets.Tests
 {
+    [Collection("NoParallelTests")]
     public class TimeoutTest
     {
-        [OuterLoop] // TODO: Issue #11345
         [Fact]
         public void GetAndSet_Success()
         {
@@ -25,7 +25,6 @@ namespace System.Net.Sockets.Tests
             }
         }
 
-        [OuterLoop] // TODO: Issue #11345
         [Fact]
         public void SocketSendTimeout_GetAndSet_Success()
         {
@@ -45,7 +44,6 @@ namespace System.Net.Sockets.Tests
         // but also not so large that it takes too long to run.
         private const int Timeout = 2000;
 
-        [ActiveIssue(23767, TestPlatforms.AnyUnix)]
         [OuterLoop] // TODO: Issue #11345
         [Theory]
         [InlineData(true)]
@@ -68,22 +66,20 @@ namespace System.Net.Sockets.Tests
 
                 acceptedSocket.ForceNonBlocking(forceNonBlocking);
 
-                DateTime start = default(DateTime);
+                long start = Environment.TickCount64;
 
                 SocketException sockEx = Assert.Throws<SocketException>(() =>
                 {
-                    start = DateTime.UtcNow;
                     acceptedSocket.Receive(new byte[1]);
                 });
 
-                double elapsed = (DateTime.UtcNow - start).TotalMilliseconds;
-
+                long elapsed = Environment.TickCount64 - start;
                 Assert.Equal(SocketError.TimedOut, sockEx.SocketErrorCode);
                 Assert.True(acceptedSocket.Connected);
 
                 // Try to ensure that the elapsed timeout is reasonably correct
                 // Sometimes test machines run slowly
-                Assert.InRange(elapsed, Timeout * 0.75, Timeout * 2);
+                Assert.InRange(elapsed, Timeout * 0.75, Timeout * 1.9999);
             }
         }
 
@@ -109,7 +105,7 @@ namespace System.Net.Sockets.Tests
 
                 acceptedSocket.ForceNonBlocking(forceNonBlocking);
 
-                var sw = new Stopwatch();
+                long start = Environment.TickCount64;
 
                 // Force Send to timeout by filling the kernel buffer.
                 var sendBuffer = new byte[16 * 1024];
@@ -117,19 +113,18 @@ namespace System.Net.Sockets.Tests
                 {
                     while (true)
                     {
-                        sw.Restart();
+                        start = Environment.TickCount64;
                         acceptedSocket.Send(sendBuffer);
                     }
                 }));
 
-                double elapsed = sw.Elapsed.TotalMilliseconds;
-
+                long elapsed = Environment.TickCount64 - start;
                 Assert.Equal(SocketError.TimedOut, sockEx.SocketErrorCode);
                 Assert.True(acceptedSocket.Connected);
 
                 // Try to ensure that the elapsed timeout is reasonably correct
                 // Sometimes test machines run slowly
-                Assert.InRange(elapsed, Timeout * 0.5, Timeout * 3);
+                Assert.InRange(elapsed, Timeout * 0.75, Timeout * 1.9999);
             }
         }
     }