From a2fd900cf17afda5d98ec68b722b7c23b6ea9589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 27 Nov 2023 17:47:27 +0500 Subject: [PATCH] =?UTF-8?q?=D0=A2=D0=B5=D1=81=D1=82=D1=8B=20=D1=84=D0=BE?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D1=8B=D1=85=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/BackgroundWorkertest.cs | 113 ------------- AsbCloudWebApi.Tests/Services/WorkTest.cs | 150 ----------------- .../Background/BackgroundWorkerTest.cs | 119 ++++++++++++++ .../PeriodicBackgroundWorkerTest.cs | 20 +-- .../UnitTests/Background/WorkTest.cs | 152 ++++++++++++++++++ 5 files changed, 281 insertions(+), 273 deletions(-) delete mode 100644 AsbCloudWebApi.Tests/Services/BackgroundWorkertest.cs delete mode 100644 AsbCloudWebApi.Tests/Services/WorkTest.cs create mode 100644 AsbCloudWebApi.Tests/UnitTests/Background/BackgroundWorkerTest.cs rename AsbCloudWebApi.Tests/{Services => UnitTests/Background}/PeriodicBackgroundWorkerTest.cs (88%) create mode 100644 AsbCloudWebApi.Tests/UnitTests/Background/WorkTest.cs diff --git a/AsbCloudWebApi.Tests/Services/BackgroundWorkertest.cs b/AsbCloudWebApi.Tests/Services/BackgroundWorkertest.cs deleted file mode 100644 index 0f54dddf..00000000 --- a/AsbCloudWebApi.Tests/Services/BackgroundWorkertest.cs +++ /dev/null @@ -1,113 +0,0 @@ -using AsbCloudInfrastructure.Background; -using Microsoft.Extensions.DependencyInjection; -using NSubstitute; -using System; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Xunit; - -namespace AsbCloudWebApi.Tests.Services; - -public class BackgroundWorkerTest -{ - private IServiceProvider provider; - private BackgroundWorker service; - - public BackgroundWorkerTest() - { - provider = Substitute.For(); - var serviceScope = Substitute.For(); - var serviceScopeFactory = Substitute.For(); - serviceScopeFactory.CreateScope().Returns(serviceScope); - ((ISupportRequiredService)provider).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactory); - - service = new BackgroundWorker(provider); - typeof(BackgroundWorker) - .GetField("minDelay", BindingFlags.NonPublic | BindingFlags.Instance) - .SetValue(service, TimeSpan.FromMilliseconds(1)); - } - - [Fact] - public async Task Enqueue_n_works() - { - var workCount = 10; - var result = 0; - Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) - { - result++; - return Task.Delay(1); - } - - //act - for (int i = 0; i < workCount; i++) - { - var work = Work.CreateByDelegate(i.ToString(), workAction); - service.Enqueue(work); - } - - await service.ExecuteTask; - - //assert - Assert.Equal(workCount, result); - } - - [Fact] - public async Task Enqueue_continues_after_exceptions() - { - var expectadResult = 42; - var result = 0; - - Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) - { - result = expectadResult; - return Task.CompletedTask; - } - var goodWork = Work.CreateByDelegate("", workAction); - - Task failAction(string id, IServiceProvider services, Action callback, CancellationToken token) - => throw new Exception(); - - var badWork = Work.CreateByDelegate("", failAction); - badWork.OnErrorAsync = (id, exception, token) => throw new Exception(); - - //act - service.Enqueue(badWork); - service.Enqueue(goodWork); - - await service.ExecuteTask; - - //assert - Assert.Equal(expectadResult, result); - Assert.Equal(1, service.Felled.Count); - Assert.Equal(1, service.Done.Count); - } - - [Fact] - public async Task TryRemove() - { - var workCount = 5; - var result = 0; - Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) - { - result++; - return Task.Delay(10); - } - - //act - for (int i = 0; i < workCount; i++) - { - var work = Work.CreateByDelegate(i.ToString(), workAction); - service.Enqueue(work); - } - - var removed = service.TryRemoveFromQueue((workCount - 1).ToString()); - - await service.ExecuteTask; - - //assert - Assert.True(removed); - Assert.Equal(workCount - 1, result); - Assert.Equal(workCount - 1, service.Done.Count); - } -} diff --git a/AsbCloudWebApi.Tests/Services/WorkTest.cs b/AsbCloudWebApi.Tests/Services/WorkTest.cs deleted file mode 100644 index 4f144d98..00000000 --- a/AsbCloudWebApi.Tests/Services/WorkTest.cs +++ /dev/null @@ -1,150 +0,0 @@ -using AsbCloudInfrastructure.Background; -using Microsoft.Extensions.DependencyInjection; -using NSubstitute; -using System; -using System.Threading; -using System.Threading.Tasks; -using Xunit; - -namespace AsbCloudWebApi.Tests.Services -{ - public class WorkTest - { - private IServiceProvider provider; - - public WorkTest() - { - provider = Substitute.For(); - var serviceScope = Substitute.For(); - var serviceScopeFactory = Substitute.For(); - serviceScopeFactory.CreateScope().Returns(serviceScope); - ((ISupportRequiredService)provider).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactory); - } - - [Fact] - public async Task Work_done_with_success() - { - 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(provider, 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] - public async Task Work_calls_callback() - { - var expectedState = "42"; - var expectedProgress = 42d; - - var timeout = TimeSpan.FromMilliseconds(40); - - 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(provider, 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] - public async Task Work_fails_with_info() - { - var expectedState = "41"; - var 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(provider, 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() - { - 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(provider, 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(0, work.CountErrors); - Assert.Null(work.LastComplete); - Assert.Null(work.LastError); - } - } -} diff --git a/AsbCloudWebApi.Tests/UnitTests/Background/BackgroundWorkerTest.cs b/AsbCloudWebApi.Tests/UnitTests/Background/BackgroundWorkerTest.cs new file mode 100644 index 00000000..aaafe317 --- /dev/null +++ b/AsbCloudWebApi.Tests/UnitTests/Background/BackgroundWorkerTest.cs @@ -0,0 +1,119 @@ +using System; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using AsbCloudInfrastructure.Background; +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; +using Xunit; + +namespace AsbCloudWebApi.Tests.UnitTests.Background; + +public class BackgroundWorkerTest +{ + private readonly IServiceProvider serviceProviderMock = Substitute.For(); + private readonly IServiceScope serviceScopeMock = Substitute.For(); + private readonly IServiceScopeFactory serviceScopeFactoryMock = Substitute.For(); + + private readonly BackgroundWorker backgroundWorker; + + public BackgroundWorkerTest() + { + serviceScopeFactoryMock.CreateScope().Returns(serviceScopeMock); + ((ISupportRequiredService)serviceProviderMock).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactoryMock); + + backgroundWorker = new BackgroundWorker(serviceProviderMock); + typeof(BackgroundWorker) + .GetField("minDelay", BindingFlags.NonPublic | BindingFlags.Instance) + ?.SetValue(backgroundWorker, TimeSpan.FromMilliseconds(1)); + } + + [Fact] + public async Task Enqueue_ShouldReturn_WorkCount() + { + //arrange + const int workCount = 10; + var result = 0; + + Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) + { + result++; + return Task.Delay(1); + } + + //act + for (int i = 0; i < workCount; i++) + { + var work = Work.CreateByDelegate(i.ToString(), workAction); + backgroundWorker.Enqueue(work); + } + + await backgroundWorker.ExecuteTask; + + //assert + Assert.Equal(workCount, result); + } + + [Fact] + public async Task Enqueue_Continues_AfterExceptions() + { + //arrange + const int expectadResult = 42; + var result = 0; + + Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) + { + result = expectadResult; + return Task.CompletedTask; + } + + var goodWork = Work.CreateByDelegate("", workAction); + + Task failAction(string id, IServiceProvider services, Action callback, CancellationToken token) + => throw new Exception(); + + var badWork = Work.CreateByDelegate("", failAction); + badWork.OnErrorAsync = (id, exception, token) => throw new Exception(); + + //act + backgroundWorker.Enqueue(badWork); + backgroundWorker.Enqueue(goodWork); + + await backgroundWorker.ExecuteTask; + + //assert + Assert.Equal(expectadResult, result); + Assert.Equal(1, backgroundWorker.Felled.Count); + Assert.Equal(1, backgroundWorker.Done.Count); + } + + [Fact] + public async Task TryRemoveFromQueue_ShouldReturn_True() + { + //arrange + const int workCount = 5; + var result = 0; + + Task workAction(string id, IServiceProvider services, Action callback, CancellationToken token) + { + result++; + return Task.Delay(10); + } + + //act + for (int i = 0; i < workCount; i++) + { + var work = Work.CreateByDelegate(i.ToString(), workAction); + backgroundWorker.Enqueue(work); + } + + var removed = backgroundWorker.TryRemoveFromQueue((workCount - 1).ToString()); + + await backgroundWorker.ExecuteTask; + + //assert + Assert.True(removed); + Assert.Equal(workCount - 1, result); + Assert.Equal(workCount - 1, backgroundWorker.Done.Count); + } +} \ No newline at end of file diff --git a/AsbCloudWebApi.Tests/Services/PeriodicBackgroundWorkerTest.cs b/AsbCloudWebApi.Tests/UnitTests/Background/PeriodicBackgroundWorkerTest.cs similarity index 88% rename from AsbCloudWebApi.Tests/Services/PeriodicBackgroundWorkerTest.cs rename to AsbCloudWebApi.Tests/UnitTests/Background/PeriodicBackgroundWorkerTest.cs index d0c16285..13c5f142 100644 --- a/AsbCloudWebApi.Tests/Services/PeriodicBackgroundWorkerTest.cs +++ b/AsbCloudWebApi.Tests/UnitTests/Background/PeriodicBackgroundWorkerTest.cs @@ -1,16 +1,16 @@ -using AsbCloudInfrastructure.Background; -using DocumentFormat.OpenXml.Drawing.Charts; -using Microsoft.Extensions.DependencyInjection; -using NSubstitute; -using System; +using System; using System.Diagnostics; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using AsbCloudInfrastructure.Background; +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; using Xunit; -namespace AsbCloudWebApi.Tests.Services; +namespace AsbCloudWebApi.Tests.UnitTests.Background; +//TODO: нужно поправить тесты, иногда они не проходят public class PeriodicBackgroundWorkerTest { private IServiceProvider provider; @@ -35,10 +35,10 @@ public class PeriodicBackgroundWorkerTest } [Fact] - public async Task WorkRunsTwice() + public async Task WorkRunsTwice_ShouldReturn_WorkCount() { - var workCount = 2; - var periodMs = 100d; + const int workCount = 2; + const double periodMs = 100d; var period = TimeSpan.FromMilliseconds(periodMs); @@ -64,7 +64,7 @@ public class PeriodicBackgroundWorkerTest [Fact] - public async Task Enqueue_continues_after_exceptions() + public async Task Enqueue_Continues_AfterExceptions() { var expectadResult = 42; var result = 0; diff --git a/AsbCloudWebApi.Tests/UnitTests/Background/WorkTest.cs b/AsbCloudWebApi.Tests/UnitTests/Background/WorkTest.cs new file mode 100644 index 00000000..40665b60 --- /dev/null +++ b/AsbCloudWebApi.Tests/UnitTests/Background/WorkTest.cs @@ -0,0 +1,152 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using AsbCloudInfrastructure.Background; +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; +using Xunit; + +namespace AsbCloudWebApi.Tests.UnitTests.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] + 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] + public async Task ExecutionWork_Invokes_Callback() + { + //arrange + const string expectedState = "42"; + const double expectedProgress = 42d; + + var timeout = TimeSpan.FromMilliseconds(40); + + 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] + 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(0, work.CountErrors); + Assert.Null(work.LastComplete); + Assert.Null(work.LastError); + } +} \ No newline at end of file