using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using AsbCloudInfrastructure.Background; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Xunit; namespace AsbCloudInfrastructure.Tests.Background; public class WorkTest { private readonly IServiceProvider serviceProviderMock = Substitute.For(); private readonly IServiceScope serviceScopeMock = Substitute.For(); private readonly IServiceScopeFactory serviceScopeFactoryMock = Substitute.For(); public WorkTest() { serviceScopeFactoryMock.CreateScope().Returns(serviceScopeMock); ((ISupportRequiredService)serviceProviderMock).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactoryMock); } [Fact, MethodImpl(MethodImplOptions.NoOptimization)] public async Task Start_ShouldReturn_Success() { //arrange Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) => Task.CompletedTask; var work = Work.CreateByDelegate("", workAction); //act var begin = DateTime.Now; await work.Start(serviceProviderMock, CancellationToken.None); var done = DateTime.Now; var executionTime = done - begin; //assert Assert.Equal(1, work.CountComplete); Assert.Equal(1, work.CountStart); Assert.Equal(0, work.CountErrors); Assert.Null(work.CurrentState); Assert.Null(work.LastError); var lastState = work.LastComplete; Assert.NotNull(lastState); Assert.InRange(lastState.Start, begin, done - 0.5 * executionTime); Assert.InRange(lastState.End, done - 0.5 * executionTime, done); Assert.InRange(lastState.ExecutionTime, TimeSpan.Zero, executionTime); } [Fact, MethodImpl(MethodImplOptions.NoOptimization)] public async Task ExecutionWork_Invokes_Callback() { //arrange const string expectedState = "42"; const double expectedProgress = 42d; var timeout = TimeSpan.FromMilliseconds(80); Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) { callback.Invoke(expectedState, expectedProgress); return Task.Delay(timeout); } var work = Work.CreateByDelegate("", workAction); //act var begin = DateTime.Now; _ = work.Start(serviceProviderMock, CancellationToken.None); await Task.Delay(timeout / 3); //assert Assert.Equal(0, work.CountComplete); Assert.Equal(1, work.CountStart); Assert.Equal(0, work.CountErrors); Assert.NotNull(work.CurrentState); Assert.Null(work.LastComplete); Assert.Null(work.LastError); var currentState = work.CurrentState; Assert.NotNull(currentState); Assert.InRange(currentState.Start, begin, begin + timeout); Assert.InRange(currentState.StateUpdate, begin, begin + timeout); Assert.Equal(expectedState, currentState.State); Assert.Equal(expectedProgress, currentState.Progress); } [Fact, MethodImpl(MethodImplOptions.NoOptimization)] public async Task ExecutionWork_ShouldReturn_FailsWithInfo() { //arrange const string expectedState = "41"; const string expectedErrorText = "42"; var minWorkTime = TimeSpan.FromMilliseconds(10); async Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) { await Task.Delay(minWorkTime); callback(expectedState, 0); throw new Exception(expectedErrorText); } var work = Work.CreateByDelegate("", workAction); //act var begin = DateTime.Now; await work.Start(serviceProviderMock, CancellationToken.None); //assert Assert.Equal(0, work.CountComplete); Assert.Equal(1, work.CountStart); Assert.Equal(1, work.CountErrors); Assert.Null(work.CurrentState); Assert.Null(work.LastComplete); var error = work.LastError; Assert.NotNull(error); Assert.InRange(error.Start, begin, DateTime.Now); Assert.InRange(error.End, begin, DateTime.Now); Assert.InRange(error.ExecutionTime, minWorkTime, DateTime.Now - begin); Assert.Contains(expectedErrorText, error.ErrorText, StringComparison.InvariantCultureIgnoreCase); Assert.Equal(expectedState, error.State); } [Fact] public async Task Stop_ShouldReturn_Success() { //arrange var workTime = TimeSpan.FromMilliseconds(1_000); Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) => Task.Delay(workTime, token); var work = Work.CreateByDelegate("", workAction); //act var begin = DateTime.Now; _ = work.Start(serviceProviderMock, CancellationToken.None); await Task.Delay(10); work.Stop(); await Task.Delay(10); //assert Assert.Equal(0, work.CountComplete); Assert.Equal(1, work.CountStart); Assert.Equal(1, work.CountErrors); Assert.Null(work.LastComplete); Assert.NotNull(work.LastError); } }