Forráskód Böngészése

Expose WaitHandle.

Gert Driesen 8 éve
szülő
commit
82634b4662

+ 7 - 1
src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj

@@ -273,6 +273,12 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Common\CountdownEventTest.cs">
       <Link>Classes\Common\CountdownEventTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\CountdownEventTest_Dispose_NotSet.cs">
+      <Link>Classes\Common\CountdownEventTest_Dispose_NotSet.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\CountdownEventTest_Dispose_Set.cs">
+      <Link>Classes\Common\CountdownEventTest_Dispose_Set.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Common\DerDataTest.cs">
       <Link>Classes\Common\DerDataTest.cs</Link>
     </Compile>
@@ -1596,7 +1602,7 @@
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
     <VisualStudio>
-      <UserProperties ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
+      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 136 - 5
src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs

@@ -26,6 +26,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             var countdownEvent = CreateCountdownEvent(initialCount);
             Assert.AreEqual(initialCount, countdownEvent.CurrentCount);
             Assert.IsFalse(countdownEvent.IsSet);
+            Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0));
             countdownEvent.Dispose();
         }
 
@@ -37,6 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             var countdownEvent = CreateCountdownEvent(0);
             Assert.AreEqual(initialCount, countdownEvent.CurrentCount);
             Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
             countdownEvent.Dispose();
         }
 
@@ -49,6 +51,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.IsFalse(countdownEvent.Signal());
             Assert.AreEqual(--initialCount, countdownEvent.CurrentCount);
             Assert.IsFalse(countdownEvent.IsSet);
+            Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0));
             countdownEvent.Dispose();
         }
 
@@ -59,6 +62,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.IsTrue(countdownEvent.Signal());
             Assert.AreEqual(0, countdownEvent.CurrentCount);
             Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
             countdownEvent.Dispose();
         }
 
@@ -82,10 +86,6 @@ namespace Renci.SshNet.Tests.Classes.Common
             }
         }
 
-        public void CurrentCountShouldReturnZeroAfterAttemptToDecrementCountBelowZero()
-        {
-        }
-
         [TestMethod]
         public void Wait_TimeoutInfinite_ShouldBlockUntilCountdownEventIsSet()
         {
@@ -118,6 +118,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.IsTrue(actual);
             Assert.AreEqual(expectedSignalCount, signalCount);
             Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
             Assert.IsTrue(elapsedTime >= sleep);
             Assert.IsTrue(elapsedTime <= sleep.Add(TimeSpan.FromMilliseconds(100)));
 
@@ -156,6 +157,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.IsTrue(actual);
             Assert.AreEqual(expectedSignalCount, signalCount);
             Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
             Assert.IsTrue(elapsedTime >= sleep);
             Assert.IsTrue(elapsedTime <= timeout);
 
@@ -163,7 +165,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         }
 
         [TestMethod]
-        public void Wait_ShouldReturnFalseTimeoutExpiresBeforeCountdownEventIsSet()
+        public void Wait_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdownEventIsSet()
         {
             var sleep = TimeSpan.FromMilliseconds(100);
             var timeout = TimeSpan.FromMilliseconds(30);
@@ -193,6 +195,135 @@ namespace Renci.SshNet.Tests.Classes.Common
 
             Assert.IsFalse(actual);
             Assert.IsFalse(countdownEvent.IsSet);
+            Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0));
+            Assert.IsTrue(elapsedTime >= timeout);
+
+            countdownEvent.Wait(Session.InfiniteTimeSpan);
+            countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void WaitHandle_ShouldAlwaysReturnSameInstance()
+        {
+            var countdownEvent = CreateCountdownEvent(1);
+
+            var waitHandleA = countdownEvent.WaitHandle;
+            Assert.IsNotNull(waitHandleA);
+
+            var waitHandleB = countdownEvent.WaitHandle;
+            Assert.AreSame(waitHandleA, waitHandleB);
+        }
+
+        [TestMethod]
+        public void WaitHandle_WaitOne_TimeoutInfinite_ShouldBlockUntilCountdownEventIsSet()
+        {
+            var sleep = TimeSpan.FromMilliseconds(100);
+            var timeout = Session.InfiniteTimeSpan;
+
+            var countdownEvent = CreateCountdownEvent(1);
+            var signalCount = 0;
+            var expectedSignalCount = _random.Next(5, 20);
+
+            for (var i = 0; i < (expectedSignalCount - 1); i++)
+                countdownEvent.AddCount();
+
+            var threads = new Thread[expectedSignalCount];
+            for (var i = 0; i < expectedSignalCount; i++)
+            {
+                threads[i] = new Thread(() =>
+                {
+                    Thread.Sleep(sleep);
+                    Interlocked.Increment(ref signalCount);
+                    countdownEvent.Signal();
+                });
+                threads[i].Start();
+            }
+
+            var start = DateTime.Now;
+            var actual = countdownEvent.WaitHandle.WaitOne(timeout);
+            var elapsedTime = DateTime.Now - start;
+
+            Assert.IsTrue(actual);
+            Assert.AreEqual(expectedSignalCount, signalCount);
+            Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
+            Assert.IsTrue(elapsedTime >= sleep);
+            Assert.IsTrue(elapsedTime <= sleep.Add(TimeSpan.FromMilliseconds(100)));
+
+            countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void WaitHandle_WaitOne_ShouldReturnTrueWhenCountdownEventIsSetBeforeTimeoutExpires()
+        {
+            var sleep = TimeSpan.FromMilliseconds(100);
+            var timeout = sleep.Add(TimeSpan.FromSeconds(2));
+
+            var countdownEvent = CreateCountdownEvent(1);
+            var signalCount = 0;
+            var expectedSignalCount = _random.Next(5, 20);
+
+            for (var i = 0; i < (expectedSignalCount - 1); i++)
+                countdownEvent.AddCount();
+
+            var threads = new Thread[expectedSignalCount];
+            for (var i = 0; i < expectedSignalCount; i++)
+            {
+                threads[i] = new Thread(() =>
+                {
+                    Thread.Sleep(sleep);
+                    Interlocked.Increment(ref signalCount);
+                    countdownEvent.Signal();
+                });
+                threads[i].Start();
+            }
+
+            var start = DateTime.Now;
+            var actual = countdownEvent.Wait(timeout);
+            var elapsedTime = DateTime.Now - start;
+
+            Assert.IsTrue(actual);
+            Assert.AreEqual(expectedSignalCount, signalCount);
+            Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
+            Assert.IsTrue(elapsedTime >= sleep);
+            Assert.IsTrue(elapsedTime <= timeout);
+
+            countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void WaitHandle_WaitOne_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdownEventIsSet()
+        {
+            var sleep = TimeSpan.FromMilliseconds(100);
+            var timeout = TimeSpan.FromMilliseconds(30);
+
+            var countdownEvent = CreateCountdownEvent(1);
+            var signalCount = 0;
+            var expectedSignalCount = _random.Next(5, 20);
+
+            for (var i = 0; i < (expectedSignalCount - 1); i++)
+                countdownEvent.AddCount();
+
+            var threads = new Thread[expectedSignalCount];
+            for (var i = 0; i < expectedSignalCount; i++)
+            {
+                threads[i] = new Thread(() =>
+                {
+                    Thread.Sleep(sleep);
+                    countdownEvent.Signal();
+                    Interlocked.Increment(ref signalCount);
+                });
+                threads[i].Start();
+            }
+
+            var start = DateTime.Now;
+            var actual = countdownEvent.WaitHandle.WaitOne(timeout);
+            var elapsedTime = DateTime.Now - start;
+
+            Assert.IsFalse(actual);
+            Assert.IsFalse(countdownEvent.IsSet);
+            Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0));
             Assert.IsTrue(elapsedTime >= timeout);
 
             countdownEvent.Wait(Session.InfiniteTimeSpan);

+ 109 - 0
src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs

@@ -0,0 +1,109 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+#if !FEATURE_THREAD_COUNTDOWNEVENT
+using CountdownEvent = Renci.SshNet.Common.CountdownEvent;
+#else
+using System.Threading;
+#endif
+
+namespace Renci.SshNet.Tests.Classes.Common
+{
+    [TestClass]
+    public class CountdownEventTest_Dispose_NotSet
+    {
+        private int _signalsRequired;
+        private CountdownEvent _countdownEvent;
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Arrange()
+        {
+            _signalsRequired = new Random().Next(1, 20);
+            _countdownEvent = new CountdownEvent(_signalsRequired);
+        }
+
+        private void Act()
+        {
+            _countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void AddCount_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                _countdownEvent.AddCount();
+                Assert.Fail();
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void CurrentCount_ShouldReturnRemainingSignalsRequiredToSetEvent()
+        {
+            var actual = _countdownEvent.CurrentCount;
+
+            Assert.AreEqual(_signalsRequired, actual);
+        }
+
+        [TestMethod]
+        public void Dispose_ShouldNotThrow()
+        {
+            _countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void IsSet_ShouldReturnFalse()
+        {
+            var actual = _countdownEvent.IsSet;
+
+            Assert.IsFalse(actual);
+        }
+
+        [TestMethod]
+        public void Signal_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var set = _countdownEvent.Signal();
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + set);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void Wait_TimeSpan_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var set = _countdownEvent.Wait(TimeSpan.FromSeconds(5));
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + set);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void WaitHandle_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var waitHandle = _countdownEvent.WaitHandle;
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + waitHandle);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+    }
+}

+ 107 - 0
src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs

@@ -0,0 +1,107 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+#if !FEATURE_THREAD_COUNTDOWNEVENT
+using CountdownEvent = Renci.SshNet.Common.CountdownEvent;
+#else
+using System.Threading;
+#endif
+
+namespace Renci.SshNet.Tests.Classes.Common
+{
+    [TestClass]
+    public class CountdownEventTest_Dispose_Set
+    {
+        private CountdownEvent _countdownEvent;
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Arrange()
+        {
+            _countdownEvent = new CountdownEvent(0);
+        }
+
+        private void Act()
+        {
+            _countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void AddCount_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                _countdownEvent.AddCount();
+                Assert.Fail();
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void CurrentCount_ShouldReturnZero()
+        {
+            var actual = _countdownEvent.CurrentCount;
+
+            Assert.AreEqual(0, actual);
+        }
+
+        [TestMethod]
+        public void Dispose_ShouldNotThrow()
+        {
+            _countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void IsSet_ShouldReturnTrue()
+        {
+            var actual = _countdownEvent.IsSet;
+
+            Assert.IsTrue(actual);
+        }
+
+        [TestMethod]
+        public void Signal_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var set = _countdownEvent.Signal();
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + set);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void Wait_TimeSpan_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var set = _countdownEvent.Wait(TimeSpan.FromSeconds(5));
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + set);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void WaitHandle_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var waitHandle = _countdownEvent.WaitHandle;
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + waitHandle);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+    }
+}

+ 2 - 0
src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj

@@ -144,6 +144,8 @@
     <Compile Include="Classes\ClientAuthenticationTest_Success_MultiList_SkipFailedAuthenticationMethod.cs" />
     <Compile Include="Classes\ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess.cs" />
     <Compile Include="Classes\Common\CountdownEventTest.cs" />
+    <Compile Include="Classes\Common\CountdownEventTest_Dispose_NotSet.cs" />
+    <Compile Include="Classes\Common\CountdownEventTest_Dispose_Set.cs" />
     <Compile Include="Classes\Common\ExtensionsTest_Concat.cs" />
     <Compile Include="Classes\Common\ExtensionsTest_IsEqualTo_ByteArray.cs" />
     <Compile Include="Classes\Common\ExtensionsTest_Reverse.cs" />

+ 18 - 0
src/Renci.SshNet/Common/CountdownEvent.cs

@@ -57,6 +57,24 @@ namespace Renci.SshNet.Common
             get { return _count == 0; }
         }
 
+        /// <summary>
+        /// Gets a <see cref="WaitHandle"/> that is used to wait for the event to be set.
+        /// </summary>
+        /// <value>
+        /// A <see cref="WaitHandle"/> that is used to wait for the event to be set.
+        /// </value>
+        /// <exception cref="ObjectDisposedException">The current instance has already been disposed.</exception>
+        public WaitHandle WaitHandle
+        {
+            get
+            {
+                EnsureNotDisposed();
+
+                return _event;
+            }
+        }
+
+
         /// <summary>
         /// Registers a signal with the <see cref="CountdownEvent"/>, decrementing the value of <see cref="CurrentCount"/>.
         /// </summary>