public static void SendTimeout_Zero_Throws_TimeoutException_Immediately() { TimeSpan serviceOperationTimeout = TimeSpan.FromMilliseconds(5000); BasicHttpBinding binding = new BasicHttpBinding(); binding.SendTimeout = TimeSpan.FromMilliseconds(0); ChannelFactory <IWcfService> factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.HttpBaseAddress_Basic)); Stopwatch watch = new Stopwatch(); try { var exception = Assert.Throws <TimeoutException>(() => { IWcfService proxy = factory.CreateChannel(); watch.Start(); proxy.EchoWithTimeout("Hello", serviceOperationTimeout); }); } finally { watch.Stop(); } // want to assert that this completed in < 2 s as an upper bound since the SendTimeout is 0 sec // (usual case is around 1 - 3 ms) Assert.InRange <long>(watch.ElapsedMilliseconds, 0, 2000); }
public static void TimeoutTest_SendTimeout0Seconds() { bool exceptionThrown = false; try { BasicHttpBinding binding = new BasicHttpBinding(); binding.SendTimeout = TimeSpan.FromMilliseconds(0); ChannelFactory <IWcfService> factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.HttpBaseAddress_Basic)); IWcfService proxy = factory.CreateChannel(); proxy.EchoWithTimeout("Hello"); } catch (TimeoutException) { exceptionThrown = true; } catch (Exception ex) { Assert.True(false, String.Format("Unexpected exception caught: {0}", ex.ToString())); } if (!exceptionThrown) { Assert.True(false, "Expected TimeoutException was not thrown nor was any other exception thrown."); } }
public static void NetTcp_TransportSecurity_Streamed_TimeOut_Long_Running_Operation() { string testString = "Hello"; NetTcpBinding binding = null; TimeSpan serviceOperationTimeout = TimeSpan.FromMilliseconds(10000); ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; try { // *** SETUP *** \\ binding = new NetTcpBinding(SecurityMode.Transport); binding.TransferMode = TransferMode.Streamed; binding.SendTimeout = TimeSpan.FromMilliseconds(5000); factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.Tcp_Transport_Security_Streamed_Address)); serviceProxy = factory.CreateChannel(); ((ICommunicationObject)serviceProxy).Open(); Stopwatch watch = new Stopwatch(); watch.Start(); // *** EXECUTE *** \\ try { Assert.Throws <TimeoutException>(() => { string returnString = serviceProxy.EchoWithTimeout(testString, serviceOperationTimeout); }); } finally { watch.Stop(); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } // *** VALIDATE *** \\ // want to assert that this completed in > 5 s as an upper bound since the SendTimeout is 5 sec // (usual case is around 5001-5005 ms) Assert.True(watch.ElapsedMilliseconds >= 4985 && watch.ElapsedMilliseconds < 6000, String.Format("Expected timeout was {0}ms but actual was {1}ms", serviceOperationTimeout.TotalMilliseconds, watch.ElapsedMilliseconds)); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void SendTimeout_For_Long_Running_Operation_Throws_TimeoutException() { TimeSpan serviceOperationTimeout = TimeSpan.FromMilliseconds(10000); BasicHttpBinding binding = null; EndpointAddress endpointAddress = null; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; Stopwatch watch = null; int lowRange = 4985; int highRange = 6000; // *** VALIDATE *** \\ TimeoutException exception = Assert.Throws <TimeoutException>(() => { // *** SETUP *** \\ binding = new BasicHttpBinding(); binding.SendTimeout = TimeSpan.FromMilliseconds(5000); endpointAddress = new EndpointAddress(Endpoints.HttpBaseAddress_Basic_Text); factory = new ChannelFactory <IWcfService>(binding, endpointAddress); serviceProxy = factory.CreateChannel(); watch = new Stopwatch(); // *** EXECUTE *** \\ try { watch = new Stopwatch(); watch.Start(); serviceProxy.EchoWithTimeout("Hello", serviceOperationTimeout); } finally { // *** ENSURE CLEANUP *** \\ watch.Stop(); ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }); // *** ADDITIONAL VALIDATION *** \\ // want to assert that this completed in > 5 s as an upper bound since the SendTimeout is 5 sec // (usual case is around 5001-5005 ms) Assert.True((watch.ElapsedMilliseconds >= lowRange && watch.ElapsedMilliseconds <= highRange), String.Format("Expected elapsed time to be >= to {0} and <= to {1}\nActual elapsed time was: {2}", lowRange, highRange, watch.ElapsedMilliseconds)); }
public static void Abort_During_Implicit_Open_Closes_Sync_Waiters() { // This test is a regression test of an issue with CallOnceManager. // When a single proxy is used to make several service calls without // explicitly opening it, the CallOnceManager queues up all the requests // that happen while it is opening the channel (or handling previously // queued service calls. If the channel was closed or faulted during // the handling of any queued requests, it caused a pathological worst // case where every queued request waited for its complete SendTimeout // before failing. // // This test operates by making multiple concurrent synchronous service // calls, but stalls the Opening event to allow them to be queued before // any of them are allowed to proceed. It then aborts the channel when // the first service operation is allowed to proceed. This causes the // CallOnce manager to deal with all its queued operations and cause // them to complete other than by timing out. BasicHttpBinding binding = null; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; int timeoutMs = 20000; long operationsQueued = 0; int operationCount = 5; Task <string>[] tasks = new Task <string> [operationCount]; Exception[] exceptions = new Exception[operationCount]; string[] results = new string[operationCount]; bool isClosed = false; DateTime endOfOpeningStall = DateTime.Now; int serverDelayMs = 100; TimeSpan serverDelayTimeSpan = TimeSpan.FromMilliseconds(serverDelayMs); string testMessage = "testMessage"; try { // *** SETUP *** \\ binding = new BasicHttpBinding(BasicHttpSecurityMode.None); binding.TransferMode = TransferMode.Streamed; // SendTimeout is the timeout used for implicit opens binding.SendTimeout = TimeSpan.FromMilliseconds(timeoutMs); factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.HttpBaseAddress_Basic)); serviceProxy = factory.CreateChannel(); // Force the implicit open to stall until we have multiple concurrent calls pending. // This forces the CallOnceManager to have a queue of waiters it will need to notify. ((ICommunicationObject)serviceProxy).Opening += (s, e) => { // Wait until we see sync calls have been queued DateTime startOfOpeningStall = DateTime.Now; while (true) { endOfOpeningStall = DateTime.Now; // Don't wait forever -- if we stall longer than the SendTimeout, it means something // is wrong other than what we are testing, so just fail early. if ((endOfOpeningStall - startOfOpeningStall).TotalMilliseconds > timeoutMs) { Assert.True(false, "The Opening event timed out waiting for operations to queue, which was not expected for this test."); } // As soon as we have all our Tasks at least running, wait a little // longer to allow them finish queuing up their waiters, then stop stalling the Opening if (Interlocked.Read(ref operationsQueued) >= operationCount) { Task.Delay(500).Wait(); endOfOpeningStall = DateTime.Now; return; } Task.Delay(100).Wait(); } }; // Each task will make a synchronous service call, which will cause all but the // first to be queued for the implicit open. The first call to complete then closes // the channel so that it is forced to deal with queued waiters. Func <string> callFunc = () => { // We increment the # ops queued before making the actual sync call, which is // technically a short race condition in the test. But reversing the order would // timeout the implicit open and fault the channel. Interlocked.Increment(ref operationsQueued); // The call of the operation is what creates the entry in the CallOnceManager queue. // So as each Task below starts, it increments the count and adds a waiter to the // queue. We ask for a small delay on the server side just to introduce a small // stall after the sync request has been made before it can complete. Otherwise // fast machines can finish all the requests before the first one finishes the Close(). string result = serviceProxy.EchoWithTimeout("test", serverDelayTimeSpan); lock (tasks) { if (!isClosed) { try { isClosed = true; ((ICommunicationObject)serviceProxy).Abort(); } catch { } } } return(result); }; // *** EXECUTE *** \\ DateTime startTime = DateTime.Now; for (int i = 0; i < operationCount; ++i) { tasks[i] = Task.Run(callFunc); } for (int i = 0; i < operationCount; ++i) { try { results[i] = tasks[i].GetAwaiter().GetResult(); } catch (Exception ex) { exceptions[i] = ex; } } // *** VALIDATE *** \\ double elapsedMs = (DateTime.Now - endOfOpeningStall).TotalMilliseconds; // Before validating that the issue was fixed, first validate that we received the exceptions or the // results we expected. This is to verify the fix did not introduce a behavioral change other than the // elimination of the long unnecessary timeouts after the channel was closed. int nFailures = 0; for (int i = 0; i < operationCount; ++i) { if (exceptions[i] == null) { Assert.True((String.Equals("test", results[i])), String.Format("Expected operation #{0} to return '{1}' but actual was '{2}'", i, testMessage, results[i])); } else { ++nFailures; TimeoutException toe = exceptions[i] as TimeoutException; Assert.True(toe == null, String.Format("Task [{0}] should not have failed with TimeoutException", i)); } } Assert.True(nFailures > 0, String.Format("Expected at least one operation to throw an exception, but none did. Elapsed time = {0} ms.", elapsedMs)); Assert.True(nFailures < operationCount, String.Format("Expected at least one operation to succeed but none did. Elapsed time = {0} ms.", elapsedMs)); // The original issue was that sync waiters in the CallOnceManager were not notified when // the channel became unusable and therefore continued to time out for the full amount. // Additionally, because they were executed sequentially, it was also possible for each one // to time out for the full amount. Given that we closed the channel, we expect all the queued // waiters to have been immediately waked up and detected failure. int expectedElapsedMs = (operationCount * serverDelayMs) + timeoutMs / 2; Assert.True(elapsedMs < expectedElapsedMs, String.Format("The {0} operations took {1} ms to complete which exceeds the expected {2} ms", operationCount, elapsedMs, expectedElapsedMs)); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void NetTcp_TransportSecurity_Streamed_TimeOut_Long_Running_Operation() { #if FULLXUNIT_NOTSUPPORTED bool root_Certificate_Installed = Root_Certificate_Installed(); bool client_Certificate_Installed = Client_Certificate_Installed(); bool windows_Authentication_Available = Windows_Authentication_Available(); bool ambient_Credentials_Available = Ambient_Credentials_Available(); if (!root_Certificate_Installed || !client_Certificate_Installed || !windows_Authentication_Available || !ambient_Credentials_Available) { Console.WriteLine("---- Test SKIPPED --------------"); Console.WriteLine("Attempting to run the test in ToF, a ConditionalFact evaluated as FALSE."); Console.WriteLine("Root_Certificate_Installed evaluated as {0}", root_Certificate_Installed); Console.WriteLine("Client_Certificate_Installed evaluated as {0}", client_Certificate_Installed); Console.WriteLine("Windows_Authentication_Available evaluated as {0}", windows_Authentication_Available); Console.WriteLine("Ambient_Credentials_Available evaluated as {0}", ambient_Credentials_Available); return; } #endif string testString = "Hello"; NetTcpBinding binding = null; TimeSpan serviceOperationTimeout = TimeSpan.FromMilliseconds(10000); ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; try { // *** SETUP *** \\ binding = new NetTcpBinding(SecurityMode.Transport); binding.TransferMode = TransferMode.Streamed; binding.SendTimeout = TimeSpan.FromMilliseconds(5000); factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.Tcp_Transport_Security_Streamed_Address)); serviceProxy = factory.CreateChannel(); Stopwatch watch = new Stopwatch(); watch.Start(); // *** EXECUTE *** \\ try { Assert.Throws <TimeoutException>(() => { string returnString = serviceProxy.EchoWithTimeout(testString, serviceOperationTimeout); }); } finally { watch.Stop(); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } // *** VALIDATE *** \\ // want to assert that this completed in > 5 s as an upper bound since the SendTimeout is 5 sec // (usual case is around 5001-5005 ms) Assert.True(watch.ElapsedMilliseconds >= 4985 && watch.ElapsedMilliseconds < 6000, String.Format("Expected timeout was {0}ms but actual was {1}ms", serviceOperationTimeout.TotalMilliseconds, watch.ElapsedMilliseconds)); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }