Files
Andrey Ilnitsky f754c83069 [0.7.3] Target net5 and net6 (#588)
* [0.7.2] Start threads as background in HashedWheelTimer, LoopExecutor, ThreadDeathWatcher

* + code formatting

* [0.7.3] Target net5 and net6 (#2)

target net5 and net6
Adopted TlsHandler for the case when Handshake completion callback is dispatched asynchronously to thread pool
Introduced SingleThreadedEmbededChannel for TlsHandler and SniHandler tests

* + Update DotNetVersion to "6.0.302" in build.ps1
2022-08-02 16:37:48 -07:00

174 lines
6.1 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace DotNetty.Transport.Libuv.Tests
{
using System;
using System.Threading;
using System.Threading.Tasks;
using DotNetty.Common.Concurrency;
using DotNetty.Tests.Common;
using Xunit;
using Xunit.Abstractions;
using static TestUtil;
using TaskCompletionSource = DotNetty.Common.Concurrency.TaskCompletionSource;
public sealed class EventLoopTests : TestBase, IDisposable
{
readonly EventLoop eventLoop;
readonly NoOp noOp;
sealed class NoOp : IRunnable
{
public void Run() { }
}
sealed class RunCounter : IRunnable
{
readonly int expected;
readonly TaskCompletionSource completionSource;
int count;
public RunCounter(int expected)
{
this.expected = expected;
this.completionSource = new TaskCompletionSource();
}
public Task Completion => this.completionSource.Task;
public int Count => this.count;
public long EndTime { get; private set; }
public void Run()
{
if (Interlocked.Increment(ref this.count) >= this.expected)
{
this.EndTime = DateTime.UtcNow.Ticks;
this.completionSource.TryComplete();
}
}
}
public EventLoopTests(ITestOutputHelper output) : base(output)
{
this.eventLoop = new EventLoop(null, null);
this.noOp = new NoOp();
}
[Fact]
public void Shutdown()
{
Assert.True(this.eventLoop.ShutdownGracefullyAsync(TimeSpan.Zero, TimeSpan.Zero).Wait(DefaultTimeout));
Assert.True(this.eventLoop.IsTerminated);
Assert.Throws<RejectedExecutionException>(() => this.eventLoop.Execute(this.noOp));
}
[Fact]
public void ShutdownAfterExecute()
{
var counter = new RunCounter(1);
this.eventLoop.Execute(counter);
Assert.True(counter.Completion.Wait(DefaultTimeout));
Assert.Equal(1, counter.Count);
Assert.True(this.eventLoop.ShutdownGracefullyAsync(TimeSpan.Zero, TimeSpan.Zero).Wait(DefaultTimeout));
Assert.True(this.eventLoop.IsTerminated);
Assert.Throws<RejectedExecutionException>(() => this.eventLoop.Execute(this.noOp));
}
[Fact]
public void ScheduleTask()
{
const int Delay = 500;
var counter = new RunCounter(1);
long startTime = DateTime.UtcNow.Ticks;
IScheduledTask task = this.eventLoop.Schedule(counter, TimeSpan.FromMilliseconds(Delay));
Assert.True(task.Completion.Wait(DefaultTimeout));
Assert.Equal(1, counter.Count);
long delay = counter.EndTime - startTime;
Assert.True(delay > 0);
TimeSpan duration = TimeSpan.FromTicks(delay);
Assert.True(duration.TotalMilliseconds >= Delay, $"Expected delay : {Delay} milliseconds, but was : {duration}");
}
[Fact]
public void RegistrationAfterShutdown()
{
Assert.True(this.eventLoop.ShutdownGracefullyAsync(TimeSpan.Zero, TimeSpan.Zero).Wait(DefaultTimeout));
Assert.True(this.eventLoop.IsTerminated);
var channel = new TcpChannel();
var exception = Assert.Throws<AggregateException>(() => this.eventLoop.RegisterAsync(channel).Wait(DefaultTimeout));
Assert.IsType<RejectedExecutionException>(exception.InnerException);
Assert.False(channel.Open);
}
[Fact]
public void GracefulShutdownQuietPeriod()
{
Task task = this.eventLoop.ShutdownGracefullyAsync(TimeSpan.FromSeconds(1), TimeSpan.MaxValue);
// Keep Scheduling tasks for another 2 seconds.
for (int i = 0; i < 20; i++)
{
Thread.Sleep(100);
this.eventLoop.Execute(new NoOp());
}
long startTime = DateTime.UtcNow.Ticks;
Assert.True(this.eventLoop.IsShuttingDown);
Assert.False(this.eventLoop.IsShutdown);
Assert.True(task.Wait(DefaultTimeout), "Loop shutdown timed out");
Assert.True(this.eventLoop.IsShuttingDown);
Assert.True(this.eventLoop.IsShutdown);
long time = DateTime.UtcNow.Ticks - startTime;
long duration = (long)TimeSpan.FromTicks(time).TotalMilliseconds;
Assert.True(duration >= 1000, $"Expecting shutdown quite period >= 1000 milliseconds, but was {duration}");
}
[Fact]
public void GracefulShutdownTimeout()
{
Task task = this.eventLoop.ShutdownGracefullyAsync(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
// Keep Scheduling tasks for another 3 seconds.
// Submitted tasks must be rejected after 2 second timeout.
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
this.eventLoop.Execute(new NoOp());
}
bool rejected;
try
{
for (int i = 0; i < 20; i++)
{
Thread.Sleep(100);
this.eventLoop.Execute(new NoOp());
}
rejected = false;
}
catch (RejectedExecutionException)
{
// Expected
rejected = true;
}
Assert.True(rejected, "Submitted tasks must be rejected after 2 second timeout");
Assert.True(this.eventLoop.IsShuttingDown);
Assert.True(this.eventLoop.IsShutdown);
Assert.True(task.Wait(DefaultTimeout), "Loop shutdown timed out");
}
public void Dispose()
{
this.eventLoop.ShutdownGracefullyAsync(TimeSpan.Zero, TimeSpan.Zero).Wait(DefaultTimeout);
}
}
}