-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
117 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
namespace BetterHostedServices.Test.IntegrationUtils | ||
{ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
public class CrashingPeriodicTask: IPeriodicTask | ||
{ | ||
public async Task ExecuteAsync(CancellationToken stoppingToken) | ||
{ | ||
await Task.Delay(50, stoppingToken); // Just to yield control | ||
throw new Exception("oh no"); | ||
} | ||
} | ||
|
||
public class IncrementingThenCrashingPeriodicTask: IPeriodicTask | ||
{ | ||
private readonly SingletonStateHolder singletonStateHolder; | ||
|
||
public IncrementingThenCrashingPeriodicTask(SingletonStateHolder singletonStateHolder) => this.singletonStateHolder = singletonStateHolder; | ||
|
||
public async Task ExecuteAsync(CancellationToken stoppingToken) | ||
{ | ||
this.singletonStateHolder.Count += 1; | ||
throw new Exception("oh no"); | ||
} | ||
} | ||
|
||
public class SingletonStateHolder | ||
{ | ||
public int Count { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
namespace BetterHostedServices.Test | ||
{ | ||
using System; | ||
using System.Threading.Tasks; | ||
using FluentAssertions; | ||
using IntegrationUtils; | ||
using Microsoft.AspNetCore.TestHost; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Xunit; | ||
|
||
public class PeriodicTasksTest | ||
{ | ||
private readonly CustomWebApplicationFactory<DummyStartup> _factory; | ||
|
||
public PeriodicTasksTest() | ||
{ | ||
_factory = new CustomWebApplicationFactory<DummyStartup>(); | ||
} | ||
|
||
[Fact] | ||
public async Task PeriodicTask_ShouldEndApplication_IfFailureModeIsSetToCrash() | ||
{ | ||
// Arrange | ||
var applicationEnder = new ApplicationEnderMock(); | ||
|
||
var factory = this._factory.WithWebHostBuilder(builder => | ||
{ | ||
builder.ConfigureTestServices(services => | ||
{ | ||
services.AddTransient<IApplicationEnder>(s => applicationEnder); | ||
services.AddPeriodicTask<CrashingPeriodicTask>(PeriodicTaskFailureMode.CrashApplication, TimeSpan.FromSeconds(1)); | ||
}); | ||
}); | ||
|
||
var client = factory.CreateClient(); | ||
// Act & assert - we should crash here at some point | ||
|
||
// Task is hella flaky because it depends on the internals of the IHostedService - try yielding a bunch of times | ||
// to hope that it's done requesting application shutdown at this point | ||
for (int i = 0; i < 10; i++) | ||
{ | ||
await Task.Delay(50); | ||
await Task.Yield(); | ||
} | ||
|
||
// due to https://github.com/dotnet/aspnetcore/issues/25857 we can't test if the process is closed directly | ||
applicationEnder.ShutDownRequested.Should().BeTrue(); | ||
} | ||
|
||
[Fact] | ||
public async Task PeriodicTask_ShouldContinueRunningTasks_IfFailureModeIsSetToRetry() | ||
{ | ||
// Arrange | ||
var applicationEnder = new ApplicationEnderMock(); | ||
var stateHolder = new SingletonStateHolder(); | ||
|
||
var factory = this._factory.WithWebHostBuilder(builder => | ||
{ | ||
builder.ConfigureTestServices(services => | ||
{ | ||
services.AddTransient<IApplicationEnder>(s => applicationEnder); | ||
services.AddPeriodicTask<IncrementingThenCrashingPeriodicTask>(PeriodicTaskFailureMode.RetryLater, TimeSpan.FromMilliseconds(50)); | ||
services.AddSingleton<SingletonStateHolder>(s => stateHolder); | ||
}); | ||
}); | ||
|
||
var client = factory.CreateClient(); | ||
// Act & assert - we crash here after each invocation, but we truck on. The stateHolder should keep being incremented | ||
|
||
// Task is hella flaky because it depends on the internals of the IHostedService - try yielding a bunch of times | ||
// to hope that it's done requesting application shutdown at this point | ||
for (int i = 0; i < 10; i++) | ||
{ | ||
await Task.Delay(100); // 1s ms all in all | ||
await Task.Yield(); | ||
} | ||
|
||
stateHolder.Count.Should().BeGreaterThan(5); | ||
|
||
// due to https://github.com/dotnet/aspnetcore/issues/25857 we can't test if the process is closed directly | ||
applicationEnder.ShutDownRequested.Should().BeFalse(); | ||
} | ||
} | ||
} |