2022-12-01 17:48:35 +05:00
|
|
|
|
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;
|
2022-12-02 10:57:27 +05:00
|
|
|
|
private readonly TimeSpan period = TimeSpan.FromSeconds(10);
|
|
|
|
|
private readonly Func<string, IServiceProvider, CancellationToken, Task> someAction = (string id, IServiceProvider scope, CancellationToken token) => Task.CompletedTask;
|
2022-12-01 17:48:35 +05:00
|
|
|
|
|
|
|
|
|
public BackgroundWorkerServiceTest()
|
|
|
|
|
{
|
|
|
|
|
var mockServiceScope = new Mock<IServiceScope>();
|
|
|
|
|
mockServiceScopeFactory = new Mock<IServiceScopeFactory>();
|
|
|
|
|
mockServiceProvider = new Mock<IServiceProvider>();
|
|
|
|
|
|
|
|
|
|
mockServiceScope.SetReturnsDefault(mockServiceProvider.Object);
|
|
|
|
|
mockServiceProvider.SetReturnsDefault(mockServiceScopeFactory.Object);
|
2022-12-02 10:57:27 +05:00
|
|
|
|
mockServiceProvider.Setup(s => s.GetService(It.IsAny<Type>()))
|
2022-12-01 17:48:35 +05:00
|
|
|
|
.Returns(mockServiceScopeFactory.Object);
|
|
|
|
|
mockServiceScopeFactory.SetReturnsDefault(mockServiceScope.Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task Push_makes_new_scope_after_start()
|
|
|
|
|
{
|
|
|
|
|
mockServiceScopeFactory.Invocations.Clear();
|
|
|
|
|
|
2022-12-02 10:57:27 +05:00
|
|
|
|
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
|
|
|
|
|
var work = new WorkBase("", (_, _, _) => Task.CompletedTask);
|
2022-12-01 17:48:35 +05:00
|
|
|
|
backgroundService.Push(work);
|
|
|
|
|
await backgroundService.StartAsync(CancellationToken.None);
|
|
|
|
|
await Task.Delay(10);
|
|
|
|
|
|
|
|
|
|
mockServiceScopeFactory.Verify(f => f.CreateScope());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
2022-12-02 10:57:27 +05:00
|
|
|
|
public async Task Makes_primary_work_done()
|
2022-12-01 17:48:35 +05:00
|
|
|
|
{
|
|
|
|
|
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]
|
2022-12-02 10:57:27 +05:00
|
|
|
|
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()
|
2022-12-01 17:48:35 +05:00
|
|
|
|
{
|
|
|
|
|
var backgroundService = new BackgroundWorkerService(mockServiceProvider.Object);
|
|
|
|
|
var workDone = false;
|
|
|
|
|
var work = new WorkPeriodic("", (_, _, _) =>
|
|
|
|
|
{
|
|
|
|
|
workDone = true;
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
},
|
|
|
|
|
TimeSpan.FromMilliseconds(10));
|
|
|
|
|
backgroundService.Push(work);
|
2022-12-02 10:57:27 +05:00
|
|
|
|
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));
|
|
|
|
|
work.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");
|
|
|
|
|
|
2022-12-01 17:48:35 +05:00
|
|
|
|
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;
|
2022-12-02 10:57:27 +05:00
|
|
|
|
var work = new WorkBase("", async (_, _, _) => await Task.Delay(1000000));
|
2022-12-01 17:48:35 +05:00
|
|
|
|
work.Timeout = TimeSpan.FromMilliseconds(1);
|
|
|
|
|
work.OnErrorAsync = async (id, ex, token) =>
|
|
|
|
|
{
|
|
|
|
|
workCanceled = ex is System.TimeoutException;
|
|
|
|
|
await Task.CompletedTask;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
backgroundService.Push(work);
|
|
|
|
|
await backgroundService.StartAsync(CancellationToken.None);
|
2022-12-02 10:57:27 +05:00
|
|
|
|
await Task.Delay(20 * 4);
|
2022-12-01 17:48:35 +05:00
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2022-12-02 10:57:27 +05:00
|
|
|
|
|
|
|
|
|
[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));
|
|
|
|
|
}
|
2022-12-01 17:48:35 +05:00
|
|
|
|
}
|
|
|
|
|
}
|