DD.WellWorkover.Cloud/AsbCloudWebApi.Tests/ServicesTests/BackgroundWorkerServiceTest.cs
2022-12-02 14:45:20 +05:00

245 lines
8.3 KiB
C#

using Microsoft.Extensions.DependencyInjection;
using Moq;
using System;
using AsbCloudInfrastructure.Services.Background;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace AsbCloudWebApi.Tests.ServicesTests
{
public class BackgroundWorkerServiceTest
{
private readonly Mock<IServiceProvider> mockServiceProvider;
private readonly Mock<IServiceScopeFactory> mockServiceScopeFactory;
private readonly Func<string, IServiceProvider, CancellationToken, Task> someAction = (string id, IServiceProvider scope, CancellationToken token) => Task.CompletedTask;
public BackgroundWorkerServiceTest()
{
var mockServiceScope = new Mock<IServiceScope>();
mockServiceScopeFactory = new Mock<IServiceScopeFactory>();
mockServiceProvider = new Mock<IServiceProvider>();
mockServiceScope.SetReturnsDefault(mockServiceProvider.Object);
mockServiceProvider.SetReturnsDefault(mockServiceScopeFactory.Object);
mockServiceProvider.Setup(s => s.GetService(It.IsAny<Type>()))
.Returns(mockServiceScopeFactory.Object);
mockServiceScopeFactory.SetReturnsDefault(mockServiceScope.Object);
}
[Fact]
public void Contains_returns_true()
{
mockServiceScopeFactory.Invocations.Clear();
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
const string work1Id = "long name 1";
const string work2Id = "long name 2";
var work1 = new WorkBase(work1Id, someAction);
var work2 = new WorkPeriodic(work2Id, someAction, TimeSpan.Zero);
backgroundService.Push(work1);
backgroundService.Push(work2);
Assert.True(backgroundService.Contains(work1Id));
Assert.True(backgroundService.Contains(work2Id));
Assert.False(backgroundService.Contains(work2Id + work1Id));
Assert.False(backgroundService.Contains(string.Empty));
}
[Fact]
public async Task Push_makes_new_scope_after_start()
{
mockServiceScopeFactory.Invocations.Clear();
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
var work = new WorkBase("", someAction);
backgroundService.Push(work);
await backgroundService.StartAsync(CancellationToken.None);
await Task.Delay(10);
mockServiceScopeFactory.Verify(f => f.CreateScope());
}
[Fact]
public async Task Makes_primary_work_done()
{
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
var workDone = false;
var work = new WorkBase("", (_, _, _) =>
{
workDone = true;
return Task.CompletedTask;
});
backgroundService.Push(work);
await backgroundService.StartAsync(CancellationToken.None);
await Task.Delay(10);
Assert.True(workDone);
}
[Fact]
public async Task Sets_ExecutionTime_after_work_done()
{
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
var work = new WorkBase("", someAction);
backgroundService.Push(work);
await backgroundService.StartAsync(CancellationToken.None);
await Task.Delay(10);
Assert.True(work.ExecutionTime > TimeSpan.Zero);
}
[Fact]
public async Task Makes_periodic_work_done()
{
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
var workDone = false;
var work = new WorkPeriodic("", (_, _, _) =>
{
workDone = true;
return Task.CompletedTask;
},
TimeSpan.FromMilliseconds(10));
backgroundService.Push(work);
await backgroundService.StartAsync(CancellationToken.None);
await Task.Delay(20);
Assert.True(workDone);
}
[Fact]
public async Task Does_not_start_periodic_work()
{
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
var workDone = false;
var work = new WorkPeriodic("", (_, _, _) =>
{
workDone = true;
return Task.CompletedTask;
},
TimeSpan.FromSeconds(30))
{
LastStart = DateTime.Now
};
backgroundService.Push(work);
await backgroundService.StartAsync(CancellationToken.None);
await Task.Delay(20);
Assert.False(workDone);
}
[Fact]
public async Task Follows_work_priority()
{
var order = 0;
var work1Order = -1;
var work2Order = -1;
var work1 = new WorkPeriodic("1", (_, _, _) =>
{
work1Order = order++;
return Task.CompletedTask;
},
TimeSpan.FromMilliseconds(1)
);
var work2 = new WorkBase("2", (_, _, _) =>
{
work2Order = order++;
return Task.CompletedTask;
});
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
backgroundService.Push(work2);
backgroundService.Push(work1);
await backgroundService.StartAsync(CancellationToken.None);
await Task.Delay(2_100);
Assert.True(work2Order < work1Order);
}
[Fact]
public async Task Runs_second_after_delete_first()
{
var workDone = false;
var work1 = new WorkBase("1", someAction);
var work2 = new WorkPeriodic("2", (_, _, _) =>
{
workDone = true;
return Task.CompletedTask;
}, TimeSpan.FromMilliseconds(1));
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
backgroundService.Push(work1);
backgroundService.Push(work2);
backgroundService.Delete("1");
await backgroundService.StartAsync(CancellationToken.None);
await Task.Delay(10);
Assert.True(workDone);
}
[Fact]
public async Task Aborts_long_work()
{
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
var workCanceled = false;
var work = new WorkBase("", async (_, _, token) => await Task.Delay(1000000, token))
{
Timeout = TimeSpan.FromMilliseconds(1),
OnErrorAsync = async (id, ex, token) =>
{
workCanceled = ex is System.TimeoutException;
await Task.CompletedTask;
}
};
backgroundService.Push(work);
await backgroundService.StartAsync(CancellationToken.None);
await Task.Delay(20 * 4);
Assert.True(workCanceled);
}
[Fact]
public async Task Execution_continues_after_work_exception()
{
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
var work2done = false;
var work1 = new WorkBase("1", (_, _, _) => throw new Exception());
var work2 = new WorkBase("2", (_, _, _) =>
{
work2done = true;
return Task.CompletedTask;
});
backgroundService.Push(work1);
backgroundService.Push(work2);
await backgroundService.StartAsync(CancellationToken.None);
await Task.Delay(2_100);
Assert.True(work2done);
}
[Fact]
public void Push_not_unique_id_should_throw()
{
var work1 = new WorkPeriodic("1", someAction, TimeSpan.FromSeconds(30));
var work2 = new WorkBase("1", someAction);
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
backgroundService.Push(work1);
Assert.Throws<ArgumentException>(
() => backgroundService.Push(work2));
}
}
}