aspnetcore/test/Microsoft.Extensions.Hostin.../BackgroundHostedServiceTest...

172 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.Extensions.Hosting.Tests
{
public class BackgroundHostedServiceTests
{
[Fact]
public void StartReturnsCompletedTaskIfLongRunningTaskIsIncomplete()
{
var tcs = new TaskCompletionSource<object>();
var service = new MyBackgroundService(tcs.Task);
var task = service.StartAsync(CancellationToken.None);
Assert.True(task.IsCompleted);
Assert.False(tcs.Task.IsCompleted);
// Complete the tsk
tcs.TrySetResult(null);
}
[Fact]
public void StartReturnsCompletedTaskIfCancelled()
{
var tcs = new TaskCompletionSource<object>();
tcs.TrySetCanceled();
var service = new MyBackgroundService(tcs.Task);
var task = service.StartAsync(CancellationToken.None);
Assert.True(task.IsCompleted);
}
[Fact]
public async Task StartReturnsLongRunningTaskIfFailed()
{
var tcs = new TaskCompletionSource<object>();
tcs.TrySetException(new Exception("fail!"));
var service = new MyBackgroundService(tcs.Task);
var exception = await Assert.ThrowsAsync<Exception>(() => service.StartAsync(CancellationToken.None));
Assert.Equal("fail!", exception.Message);
}
[Fact]
public async Task StopAsyncWithoutStartAsyncNoops()
{
var tcs = new TaskCompletionSource<object>();
var service = new MyBackgroundService(tcs.Task);
await service.StopAsync(CancellationToken.None);
}
[Fact]
public async Task StopAsyncStopsBackgroundService()
{
var tcs = new TaskCompletionSource<object>();
var service = new MyBackgroundService(tcs.Task);
await service.StartAsync(CancellationToken.None);
Assert.False(service.ExecuteTask.IsCompleted);
await service.StopAsync(CancellationToken.None);
Assert.True(service.ExecuteTask.IsCompleted);
}
[Fact]
public async Task StopAsyncStopsEvenIfTaskNeverEnds()
{
var service = new IgnoreCancellationService();
await service.StartAsync(CancellationToken.None);
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
await service.StopAsync(cts.Token);
}
[Fact]
public async Task StopAsyncThrowsIfCancellationCallbackThrows()
{
var service = new ThrowOnCancellationService();
await service.StartAsync(CancellationToken.None);
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
await Assert.ThrowsAsync<AggregateException>(() => service.StopAsync(cts.Token));
Assert.Equal(2, service.TokenCalls);
}
[Fact]
public async Task StartAsyncThenDisposeTriggersCancelledToken()
{
var service = new WaitForCancelledTokenService();
await service.StartAsync(CancellationToken.None);
service.Dispose();
}
private class WaitForCancelledTokenService : BackgroundService
{
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
return Task.Delay(Timeout.Infinite, stoppingToken);
}
}
private class ThrowOnCancellationService : BackgroundService
{
public int TokenCalls { get; set; }
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
stoppingToken.Register(() =>
{
TokenCalls++;
throw new InvalidOperationException();
});
stoppingToken.Register(() =>
{
TokenCalls++;
});
return new TaskCompletionSource<object>().Task;
}
}
private class IgnoreCancellationService : BackgroundService
{
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
return new TaskCompletionSource<object>().Task;
}
}
private class MyBackgroundService : BackgroundService
{
private readonly Task _task;
public Task ExecuteTask { get; set; }
public MyBackgroundService(Task task)
{
_task = task;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
ExecuteTask = ExecuteCore(stoppingToken);
await ExecuteTask;
}
private async Task ExecuteCore(CancellationToken stoppingToken)
{
var task = await Task.WhenAny(_task, Task.Delay(Timeout.Infinite, stoppingToken));
await task;
}
}
}
}