|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Time.Testing;
using Xunit;
namespace Microsoft.Extensions.Diagnostics.Probes.Test;
[CollectionDefinition(nameof(TcpEndpointProbesServiceTests), DisableParallelization = true)]
public class TcpEndpointProbesServiceTests
{
[Fact]
public async Task ExecuteAsync_CheckListenerOpenAndCloseAfterHealthStatusEvents()
{
var port = GetFreeTcpPort();
using var cts = new CancellationTokenSource();
var healthCheckService = new MockHealthCheckService();
var options = new TcpEndpointProbesOptions
{
TcpPort = port,
};
var timeProvider = new FakeTimeProvider();
using var tcpEndpointProbesService = new TcpEndpointProbesService(
new FakeLogger<TcpEndpointProbesService>(),
healthCheckService,
options)
{
TimeProvider = timeProvider
};
Assert.False(IsTcpOpened(port));
await tcpEndpointProbesService.StartAsync(cts.Token);
await tcpEndpointProbesService.UpdateHealthStatusAsync(cts.Token);
Assert.True(IsTcpOpened(port));
timeProvider.Advance(TimeSpan.FromMinutes(1));
Assert.True(IsTcpOpened(port));
healthCheckService.IsHealthy = false;
await tcpEndpointProbesService.UpdateHealthStatusAsync(cts.Token);
Assert.False(IsTcpOpened(port));
timeProvider.Advance(TimeSpan.FromMinutes(1));
Assert.False(IsTcpOpened(port));
healthCheckService.IsHealthy = true;
await tcpEndpointProbesService.UpdateHealthStatusAsync(cts.Token);
Assert.True(IsTcpOpened(port));
cts.Cancel();
}
#if NET5_0_OR_GREATER
[Fact]
public async Task ExecuteAsync_Does_Nothing_On_Cancellation()
{
var port = GetFreeTcpPort();
var healthCheckService = new MockHealthCheckService();
var options = new TcpEndpointProbesOptions
{
TcpPort = port,
};
var timeProvider = new FakeTimeProvider();
using var tcpEndpointProbesService = new TcpEndpointProbesService(
new FakeLogger<TcpEndpointProbesService>(),
healthCheckService,
options)
{
TimeProvider = timeProvider
};
using var cts = new CancellationTokenSource();
cts.Cancel();
await tcpEndpointProbesService.StartAsync(cts.Token);
Assert.False(IsTcpOpened(port));
}
#endif
private static bool IsTcpOpened(int port)
{
try
{
using TcpClient tcpClient = new TcpClient();
tcpClient.Connect(new IPEndPoint(IPAddress.Loopback, port));
tcpClient.Close();
return true;
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.ConnectionRefused)
{
return false;
}
else
{
throw;
}
}
}
private static int GetFreeTcpPort()
{
#pragma warning disable CA2000 // Dispose objects before losing scope
var listener = new TcpListener(IPAddress.Loopback, 0);
#pragma warning restore CA2000 // Dispose objects before losing scope
listener.Start();
int port = ((IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
return port;
}
}
|