e0ec2a0507
An OperationCanceledException escaping RunAsync after ApplicationStopping has fired (WindowsServiceLifetime.StopAsync gets a cancelled token after shutdown finished) is a normal stop. Program.IsGracefulShutdown now routes it to an Information line; any other exception, or a cancellation with no shutdown requested, still logs Fatal and rethrows.
40 lines
1.5 KiB
C#
40 lines
1.5 KiB
C#
namespace ZB.MOM.WW.ScadaBridge.Host.Tests;
|
|
|
|
/// <summary>
|
|
/// ScadaBridge#76: a routine Windows service stop must not be logged as
|
|
/// <c>[FTL] host terminated unexpectedly</c>.
|
|
/// </summary>
|
|
public class GracefulShutdownTests
|
|
{
|
|
/// <summary>A cancellation escaping RunAsync after ApplicationStopping fired is a routine stop.</summary>
|
|
[Fact]
|
|
public void Cancellation_AfterStopRequested_IsGraceful()
|
|
{
|
|
using var cts = new CancellationTokenSource();
|
|
cts.Cancel();
|
|
|
|
Assert.True(Program.IsGracefulShutdown(new OperationCanceledException(), cts.Token));
|
|
Assert.True(Program.IsGracefulShutdown(new TaskCanceledException(), cts.Token));
|
|
}
|
|
|
|
/// <summary>A cancellation with no shutdown requested is still a genuine failure.</summary>
|
|
[Fact]
|
|
public void Cancellation_WithoutStopRequested_IsNotGraceful()
|
|
{
|
|
using var cts = new CancellationTokenSource();
|
|
|
|
Assert.False(Program.IsGracefulShutdown(new OperationCanceledException(), cts.Token));
|
|
Assert.False(Program.IsGracefulShutdown(new OperationCanceledException(), CancellationToken.None));
|
|
}
|
|
|
|
/// <summary>A real fault during shutdown must still be reported as fatal.</summary>
|
|
[Fact]
|
|
public void NonCancellationException_IsNeverGraceful()
|
|
{
|
|
using var cts = new CancellationTokenSource();
|
|
cts.Cancel();
|
|
|
|
Assert.False(Program.IsGracefulShutdown(new InvalidOperationException("boom"), cts.Token));
|
|
}
|
|
}
|