Commit 15cb2b12 authored by Nick Craver's avatar Nick Craver

Tests: more tuning/concurrency friendly

parent 0d8ebb3b
......@@ -52,7 +52,7 @@ public void PingMany()
using (var muxer = Create())
{
var conn = muxer.GetDatabase();
var tasks = new Task<TimeSpan>[10000];
var tasks = new Task<TimeSpan>[100];
for (int i = 0; i < tasks.Length; i++)
{
......@@ -284,7 +284,7 @@ public void GetWithExpiryWrongTypeSync()
}
[Fact]
public void TestQuit()
public async Task TestQuit()
{
string Time() => DateTime.UtcNow.ToString("HH:mm:ss.fff");
SetExpectedAmbientFailureCount(1);
......@@ -303,7 +303,7 @@ public void TestQuit()
Assert.Throws<RedisConnectionException>(() => Log("Ping time: " + db.Ping().ToString()));
watch.Stop();
Log("Time to notice quit: {0}ms (any order)", watch.ElapsedMilliseconds);
Thread.Sleep(20);
await Task.Delay(20).ForAwait();
Debug.WriteLine("Pinging...");
Assert.Equal(key, (string)db.StringGet(key));
}
......
......@@ -105,25 +105,25 @@ public async Task BasicStringGetPerf()
{
RedisKey key = Me();
var db = conn.GetDatabase();
await db.StringSetAsync(key, "some value");
await db.StringSetAsync(key, "some value").ForAwait();
// this is just to JIT everything before we try testing
var syncVal = db.StringGet(key);
var asyncVal = await db.StringGetAsync(key);
var asyncVal = await db.StringGetAsync(key).ForAwait();
var syncTimer = Stopwatch.StartNew();
syncVal = db.StringGet(key);
syncTimer.Stop();
var asyncTimer = Stopwatch.StartNew();
asyncVal = await db.StringGetAsync(key);
asyncVal = await db.StringGetAsync(key).ForAwait();
asyncTimer.Stop();
Log($"Sync: {syncTimer.ElapsedMilliseconds}; Async: {asyncTimer.ElapsedMilliseconds}");
Assert.Equal("some value", syncVal);
Assert.Equal("some value", asyncVal);
// let's allow 20% async overhead
Assert.True(asyncTimer.ElapsedTicks <= (syncTimer.ElapsedTicks * 1.2M));
Assert.True(asyncTimer.ElapsedMilliseconds <= (syncTimer.ElapsedMilliseconds * 1.2M));
}
}
}
......
......@@ -333,7 +333,7 @@ public void TestPublishWithSubscribers()
}
[Fact]
public void TestMultipleSubscribersGetMessage()
public async Task TestMultipleSubscribersGetMessage()
{
var channel = Me();
using (var muxerA = GetUnsecuredConnection())
......@@ -350,7 +350,7 @@ public void TestMultipleSubscribersGetMessage()
listenA.Wait(tA);
listenB.Wait(tB);
Assert.Equal(2, pub.Publish(channel, "message"));
AllowReasonableTimeToPublishAndProcess();
await AllowReasonableTimeToPublishAndProcess().ForAwait();
Assert.Equal(1, Interlocked.CompareExchange(ref gotA, 0, 0));
Assert.Equal(1, Interlocked.CompareExchange(ref gotB, 0, 0));
......@@ -358,14 +358,14 @@ public void TestMultipleSubscribersGetMessage()
tA = listenA.UnsubscribeAsync(channel);
listenA.Wait(tA);
Assert.Equal(1, pub.Publish(channel, "message"));
AllowReasonableTimeToPublishAndProcess();
await AllowReasonableTimeToPublishAndProcess().ForAwait();
Assert.Equal(1, Interlocked.CompareExchange(ref gotA, 0, 0));
Assert.Equal(2, Interlocked.CompareExchange(ref gotB, 0, 0));
}
}
[Fact]
public void Issue38()
public async Task Issue38()
{ // https://code.google.com/p/booksleeve/issues/detail?id=38
using (var pub = GetUnsecuredConnection(waitForOpen: true))
{
......@@ -387,20 +387,17 @@ public void Issue38()
pub.WaitAll(c, d, e, f);
long total = c.Result + d.Result + e.Result + f.Result;
AllowReasonableTimeToPublishAndProcess();
await AllowReasonableTimeToPublishAndProcess().ForAwait();
Assert.Equal(6, total); // sent
Assert.Equal(6, Interlocked.CompareExchange(ref count, 0, 0)); // received
}
}
internal static void AllowReasonableTimeToPublishAndProcess()
{
Thread.Sleep(100);
}
internal static Task AllowReasonableTimeToPublishAndProcess() => Task.Delay(100);
[Fact]
public void TestPartialSubscriberGetMessage()
public async Task TestPartialSubscriberGetMessage()
{
using (var muxerA = GetUnsecuredConnection())
using (var muxerB = GetUnsecuredConnection())
......@@ -416,7 +413,7 @@ public void TestPartialSubscriberGetMessage()
listenA.Wait(tA);
listenB.Wait(tB);
Assert.Equal(2, pub.Publish(prefix + "channel", "message"));
AllowReasonableTimeToPublishAndProcess();
await AllowReasonableTimeToPublishAndProcess().ForAwait();
Assert.Equal(1, Interlocked.CompareExchange(ref gotA, 0, 0));
Assert.Equal(1, Interlocked.CompareExchange(ref gotB, 0, 0));
......@@ -424,14 +421,14 @@ public void TestPartialSubscriberGetMessage()
tB = listenB.UnsubscribeAsync(prefix + "chann*", null);
listenB.Wait(tB);
Assert.Equal(1, pub.Publish(prefix + "channel", "message"));
AllowReasonableTimeToPublishAndProcess();
await AllowReasonableTimeToPublishAndProcess().ForAwait();
Assert.Equal(2, Interlocked.CompareExchange(ref gotA, 0, 0));
Assert.Equal(1, Interlocked.CompareExchange(ref gotB, 0, 0));
}
}
[Fact]
public void TestSubscribeUnsubscribeAndSubscribeAgain()
public async Task TestSubscribeUnsubscribeAndSubscribeAgain()
{
using (var pubMuxer = GetUnsecuredConnection())
using (var subMuxer = GetUnsecuredConnection())
......@@ -444,7 +441,7 @@ public void TestSubscribeUnsubscribeAndSubscribeAgain()
var t2 = sub.SubscribeAsync(prefix + "ab*", delegate { Interlocked.Increment(ref y); });
sub.WaitAll(t1, t2);
pub.Publish(prefix + "abc", "");
AllowReasonableTimeToPublishAndProcess();
await AllowReasonableTimeToPublishAndProcess().ForAwait();
Assert.Equal(1, Volatile.Read(ref x));
Assert.Equal(1, Volatile.Read(ref y));
t1 = sub.UnsubscribeAsync(prefix + "abc", null);
......@@ -457,7 +454,7 @@ public void TestSubscribeUnsubscribeAndSubscribeAgain()
t2 = sub.SubscribeAsync(prefix + "ab*", delegate { Interlocked.Increment(ref y); });
sub.WaitAll(t1, t2);
pub.Publish(prefix + "abc", "");
AllowReasonableTimeToPublishAndProcess();
await AllowReasonableTimeToPublishAndProcess().ForAwait();
Assert.Equal(2, Volatile.Read(ref x));
Assert.Equal(2, Volatile.Read(ref y));
}
......
......@@ -2,6 +2,7 @@
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
......@@ -32,7 +33,7 @@ public void TalkToNonsenseServer()
}
[Fact]
public void TestManaulHeartbeat()
public async Task TestManaulHeartbeat()
{
using (var muxer = Create(keepAlive: 2))
{
......@@ -42,7 +43,7 @@ public void TestManaulHeartbeat()
var before = muxer.OperationCount;
Log("sleeping to test heartbeat...");
Thread.Sleep(TimeSpan.FromSeconds(5));
await Task.Delay(5000).ForAwait();
var after = muxer.OperationCount;
......@@ -232,7 +233,7 @@ public void SlowLog()
}
[Fact]
public void TestAutomaticHeartbeat()
public async Task TestAutomaticHeartbeat()
{
RedisValue oldTimeout = RedisValue.Null;
using (var configMuxer = Create(allowAdmin: true))
......@@ -252,7 +253,7 @@ public void TestAutomaticHeartbeat()
var before = innerMuxer.OperationCount;
Log("sleeping to test heartbeat...");
Thread.Sleep(TimeSpan.FromSeconds(8));
await Task.Delay(8000).ForAwait();
var after = innerMuxer.OperationCount;
Assert.True(after >= before + 4);
......
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
......@@ -11,7 +12,7 @@ public class ConnectToUnexistingHost : TestBase
#if DEBUG
[Fact]
public void FailsWithinTimeout()
public async Task FailsWithinTimeout()
{
const int timeout = 1000;
var sw = Stopwatch.StartNew();
......@@ -25,7 +26,7 @@ public void FailsWithinTimeout()
using (var muxer = ConnectionMultiplexer.Connect(config, Writer))
{
Thread.Sleep(10000);
await Task.Delay(10000).ForAwait();
}
Assert.True(false, "Connect should fail with RedisConnectionException exception");
......
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
......@@ -10,7 +11,7 @@ public class ConnectingFailDetection : TestBase
#if DEBUG
[Fact]
public void FastNoticesFailOnConnectingSyncComlpetion()
public async Task FastNoticesFailOnConnectingSyncComlpetion()
{
try
{
......@@ -38,7 +39,7 @@ public void FastNoticesFailOnConnectingSyncComlpetion()
// should reconnect within 1 keepalive interval
muxer.AllowConnect = true;
Log("Waiting for reconnect");
Thread.Sleep(2000);
await Task.Delay(2000).ForAwait();
Assert.True(muxer.IsConnected);
}
......@@ -69,7 +70,7 @@ public void ConnectsWhenBeginConnectCompletesSynchronously()
}
[Fact]
public void FastNoticesFailOnConnectingAsyncComlpetion()
public async Task FastNoticesFailOnConnectingAsyncComlpetion()
{
try
{
......@@ -97,7 +98,7 @@ public void FastNoticesFailOnConnectingAsyncComlpetion()
// should reconnect within 1 keepalive interval
muxer.AllowConnect = true;
Log("Waiting for reconnect");
Thread.Sleep(2000);
await Task.Delay(2000).ForAwait();
Assert.True(muxer.IsConnected);
}
......@@ -109,7 +110,7 @@ public void FastNoticesFailOnConnectingAsyncComlpetion()
}
[Fact]
public void ReconnectsOnStaleConnection()
public async Task ReconnectsOnStaleConnection()
{
try
{
......@@ -121,11 +122,11 @@ public void ReconnectsOnStaleConnection()
Assert.True(muxer.IsConnected);
PhysicalConnection.EmulateStaleConnection = true;
Thread.Sleep(500);
await Task.Delay(500).ForAwait();
Assert.False(muxer.IsConnected);
PhysicalConnection.EmulateStaleConnection = false;
Thread.Sleep(1000);
await Task.Delay(1000).ForAwait();
Assert.True(muxer.IsConnected);
}
}
......
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
......@@ -12,7 +13,7 @@ public class ConnectionFailedErrors : TestBase
[Theory]
[InlineData(true)]
[InlineData(false)]
public void SSLCertificateValidationError(bool isCertValidationSucceeded)
public async Task SSLCertificateValidationError(bool isCertValidationSucceeded)
{
Skip.IfNoConfig(nameof(TestConfig.Config.AzureCacheServer), TestConfig.Current.AzureCacheServer);
Skip.IfNoConfig(nameof(TestConfig.Config.AzureCachePassword), TestConfig.Current.AzureCachePassword);
......@@ -42,12 +43,12 @@ public void SSLCertificateValidationError(bool isCertValidationSucceeded)
}
//wait for a second for connectionfailed event to fire
Thread.Sleep(1000);
await Task.Delay(1000).ForAwait();
}
}
[Fact]
public void AuthenticationFailureError()
public async Task AuthenticationFailureError()
{
Skip.IfNoConfig(nameof(TestConfig.Config.AzureCacheServer), TestConfig.Current.AzureCacheServer);
......@@ -66,7 +67,7 @@ public void AuthenticationFailureError()
Assert.Equal(ConnectionFailureType.AuthenticationFailure, rde.FailureType);
Assert.Equal("Error: NOAUTH Authentication required. Verify if the Redis password provided is correct.", rde.InnerException.Message);
//wait for a second for connectionfailed event to fire
Thread.Sleep(1000);
await Task.Delay(1000).ForAwait();
}
}
......@@ -108,7 +109,7 @@ public void AbortOnConnectFailFalseConnectTimeoutError()
}
[Fact]
public void CheckFailureRecovered()
public async Task CheckFailureRecovered()
{
try
{
......@@ -125,7 +126,7 @@ public void CheckFailureRecovered()
// should reconnect within 1 keepalive interval
muxer.AllowConnect = true;
Thread.Sleep(2000);
await Task.Delay(2000).ForAwait();
Assert.Null(muxer.GetServerSnapshot()[0].LastException);
}
......
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
......@@ -11,7 +12,7 @@ public class ConnectionShutdown : TestBase
public ConnectionShutdown(ITestOutputHelper output) : base (output) { }
[Fact(Skip="Unfriendly")]
public void ShutdownRaisesConnectionFailedAndRestore()
public async Task ShutdownRaisesConnectionFailedAndRestore()
{
using (var conn = Create(allowAdmin: true))
{
......@@ -31,6 +32,7 @@ public void ShutdownRaisesConnectionFailedAndRestore()
db.Ping();
Assert.Equal(0, Interlocked.CompareExchange(ref failed, 0, 0));
Assert.Equal(0, Interlocked.CompareExchange(ref restored, 0, 0));
await Task.Delay(1).ForAwait(); // To make compiler happy in Release
#if DEBUG
conn.AllowConnect = false;
......@@ -40,12 +42,12 @@ public void ShutdownRaisesConnectionFailedAndRestore()
server.SimulateConnectionFailure();
db.Ping(CommandFlags.FireAndForget);
Thread.Sleep(250);
await Task.Delay(250).ForAwait();
Assert.Equal(2, Interlocked.CompareExchange(ref failed, 0, 0));
Assert.Equal(0, Interlocked.CompareExchange(ref restored, 0, 0));
conn.AllowConnect = true;
db.Ping(CommandFlags.FireAndForget);
Thread.Sleep(1500);
await Task.Delay(1500).ForAwait();
Assert.Equal(2, Interlocked.CompareExchange(ref failed, 0, 0));
Assert.Equal(2, Interlocked.CompareExchange(ref restored, 0, 0));
#endif
......
......@@ -50,7 +50,7 @@ public async Task ConfigureAsync()
{
using (var muxer = Create())
{
Thread.Sleep(1000);
await Task.Delay(1000).ForAwait();
Log("About to reconfigure.....");
await muxer.ConfigureAsync().ForAwait();
Log("Reconfigured");
......@@ -58,11 +58,11 @@ public async Task ConfigureAsync()
}
[Fact]
public void ConfigureSync()
public async Task ConfigureSync()
{
using (var muxer = Create())
{
Thread.Sleep(1000);
await Task.Delay(1000).ForAwait();
Log("About to reconfigure.....");
muxer.Configure();
Log("Reconfigured");
......
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
......@@ -10,7 +11,7 @@ public class SO24807536 : TestBase
public SO24807536(ITestOutputHelper output) : base (output) { }
[Fact]
public void Exec()
public async Task Exec()
{
var key = Me();
using(var conn = Create())
......@@ -31,7 +32,7 @@ public void Exec()
Assert.Equal("some value", fullWait.Result);
// wait for expiry
Thread.Sleep(TimeSpan.FromSeconds(4));
await Task.Delay(4000).ForAwait();
// test once expired
keyExists = cache.KeyExists(key);
......
......@@ -280,7 +280,7 @@ private object LeaksCollectedAndRePooled_Initialize(ConnectionMultiplexer conn,
}
[FactLongRunning]
public void LeaksCollectedAndRePooled()
public async Task LeaksCollectedAndRePooled()
{
const int ThreadCount = 16;
......@@ -292,7 +292,7 @@ public void LeaksCollectedAndRePooled()
GC.Collect(3, GCCollectionMode.Forced, blocking: true);
GC.WaitForPendingFinalizers();
Thread.Sleep(TimeSpan.FromMinutes(1.01));
await Task.Delay(TimeSpan.FromMinutes(1.01)).ForAwait();
conn.FinishProfiling(anyContext);
// make sure we haven't left anything in the active contexts dictionary
......
......@@ -12,7 +12,7 @@ public class PubSub : TestBase
public PubSub(ITestOutputHelper output) : base(output) { }
[Fact]
public void ExplicitPublishMode()
public async Task ExplicitPublishMode()
{
using (var mx = Create(channelPrefix: "foo:"))
{
......@@ -23,16 +23,16 @@ public void ExplicitPublishMode()
pub.Subscribe(new RedisChannel("ab*d", RedisChannel.PatternMode.Auto), (x, y) => Interlocked.Increment(ref c));
pub.Subscribe("abc*", (x, y) => Interlocked.Increment(ref d));
Thread.Sleep(1000);
await Task.Delay(4100).ForAwait();
pub.Publish("abcd", "efg");
Thread.Sleep(500);
await Task.Delay(500).ForAwait();
Assert.Equal(0, Thread.VolatileRead(ref a));
Assert.Equal(1, Thread.VolatileRead(ref b));
Assert.Equal(1, Thread.VolatileRead(ref c));
Assert.Equal(1, Thread.VolatileRead(ref d));
pub.Publish("*bcd", "efg");
Thread.Sleep(500);
await Task.Delay(500).ForAwait();
Assert.Equal(1, Thread.VolatileRead(ref a));
//Assert.Equal(1, Thread.VolatileRead(ref b));
//Assert.Equal(1, Thread.VolatileRead(ref c));
......@@ -48,13 +48,13 @@ public void ExplicitPublishMode()
[InlineData(null, true, "d")]
[InlineData("", true, "e")]
[InlineData("Foo:", true, "f")]
public void TestBasicPubSub(string channelPrefix, bool wildCard, string breaker)
public async Task TestBasicPubSub(string channelPrefix, bool wildCard, string breaker)
{
using (var muxer = Create(channelPrefix: channelPrefix))
{
var pub = GetAnyMaster(muxer);
var sub = muxer.GetSubscriber();
Ping(muxer, pub, sub);
await PingAsync(muxer, pub, sub).ForAwait();
HashSet<string> received = new HashSet<string>();
int secondHandler = 0;
string subChannel = (wildCard ? "a*c" : "abc") + breaker;
......@@ -84,7 +84,7 @@ public void TestBasicPubSub(string channelPrefix, bool wildCard, string breaker)
Assert.Equal(0, Thread.VolatileRead(ref secondHandler));
var count = sub.Publish(pubChannel, "def");
Ping(muxer, pub, sub, 3);
await PingAsync(muxer, pub, sub, 3).ForAwait();
lock (received)
{
......@@ -95,7 +95,7 @@ public void TestBasicPubSub(string channelPrefix, bool wildCard, string breaker)
// unsubscribe from first; should still see second
sub.Unsubscribe(subChannel, handler1);
count = sub.Publish(pubChannel, "ghi");
Ping(muxer, pub, sub);
await PingAsync(muxer, pub, sub).ForAwait();
lock (received)
{
Assert.Single(received);
......@@ -106,7 +106,7 @@ public void TestBasicPubSub(string channelPrefix, bool wildCard, string breaker)
// unsubscribe from second; should see nothing this time
sub.Unsubscribe(subChannel, handler2);
count = sub.Publish(pubChannel, "ghi");
Ping(muxer, pub, sub);
await PingAsync(muxer, pub, sub).ForAwait();
lock (received)
{
Assert.Single(received);
......@@ -117,7 +117,7 @@ public void TestBasicPubSub(string channelPrefix, bool wildCard, string breaker)
}
[Fact]
public void TestBasicPubSubFireAndForget()
public async Task TestBasicPubSubFireAndForget()
{
using (var muxer = Create())
{
......@@ -127,7 +127,7 @@ public void TestBasicPubSubFireAndForget()
RedisChannel key = Guid.NewGuid().ToString();
HashSet<string> received = new HashSet<string>();
int secondHandler = 0;
Ping(muxer, pub, sub);
await PingAsync(muxer, pub, sub).ForAwait();
sub.Subscribe(key, (channel, payload) =>
{
lock (received)
......@@ -146,9 +146,9 @@ public void TestBasicPubSubFireAndForget()
Assert.Empty(received);
}
Assert.Equal(0, Thread.VolatileRead(ref secondHandler));
Ping(muxer, pub, sub);
await PingAsync(muxer, pub, sub).ForAwait();
var count = sub.Publish(key, "def", CommandFlags.FireAndForget);
Ping(muxer, pub, sub);
await PingAsync(muxer, pub, sub).ForAwait();
lock (received)
{
......@@ -159,7 +159,7 @@ public void TestBasicPubSubFireAndForget()
sub.Unsubscribe(key);
count = sub.Publish(key, "ghi", CommandFlags.FireAndForget);
Ping(muxer, pub, sub);
await PingAsync(muxer, pub, sub).ForAwait();
lock (received)
{
......@@ -169,7 +169,7 @@ public void TestBasicPubSubFireAndForget()
}
}
private static void Ping(ConnectionMultiplexer muxer, IServer pub, ISubscriber sub, int times = 1)
private static async Task PingAsync(ConnectionMultiplexer muxer, IServer pub, ISubscriber sub, int times = 1)
{
while (times-- > 0)
{
......@@ -177,14 +177,14 @@ private static void Ping(ConnectionMultiplexer muxer, IServer pub, ISubscriber s
// way to prove that is to use TPL objects
var t1 = sub.PingAsync();
var t2 = pub.PingAsync();
Thread.Sleep(100); // especially useful when testing any-order mode
await Task.Delay(100).ForAwait(); // especially useful when testing any-order mode
if (!Task.WaitAll(new[] { t1, t2 }, muxer.TimeoutMilliseconds * 2)) throw new TimeoutException();
}
}
[Fact]
public void TestPatternPubSub()
public async Task TestPatternPubSub()
{
using (var muxer = Create())
{
......@@ -212,7 +212,7 @@ public void TestPatternPubSub()
Assert.Equal(0, Thread.VolatileRead(ref secondHandler));
var count = sub.Publish("abc", "def");
Ping(muxer, pub, sub);
await PingAsync(muxer, pub, sub).ForAwait();
lock (received)
{
......@@ -223,7 +223,7 @@ public void TestPatternPubSub()
sub.Unsubscribe("a*c");
count = sub.Publish("abc", "ghi");
Ping(muxer, pub, sub);
await PingAsync(muxer, pub, sub).ForAwait();
lock (received)
{
......
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
......@@ -9,7 +10,7 @@ public class RealWorld : TestBase
public RealWorld(ITestOutputHelper output) : base(output) { }
[Fact]
public void WhyDoesThisNotWork()
public async Task WhyDoesThisNotWork()
{
Log("first:");
var config = ConfigurationOptions.Parse("localhost:6379,localhost:6380,name=Core (Q&A),tiebreaker=:RedisMaster,abortConnect=False");
......@@ -21,7 +22,7 @@ public void WhyDoesThisNotWork()
{
Log("");
Log("pausing...");
Thread.Sleep(200);
await Task.Delay(200).ForAwait();
Log("second:");
bool result = conn.Configure(Writer);
......
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
......@@ -11,14 +12,14 @@ public class TestInfoReplicationChecks : TestBase
public TestInfoReplicationChecks(ITestOutputHelper output) : base (output) { }
[Fact]
public void Exec()
public async Task Exec()
{
using(var conn = Create())
{
var parsed = ConfigurationOptions.Parse(conn.Configuration);
Assert.Equal(2, parsed.ConfigCheckSeconds);
var before = conn.GetCounters();
Thread.Sleep(TimeSpan.FromSeconds(7));
await Task.Delay(7000).ForAwait();
var after = conn.GetCounters();
int done = (int)(after.Interactive.CompletedSynchronously - before.Interactive.CompletedSynchronously);
Assert.True(done >= 2);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment