mirror of
https://github.com/cyanfish/naps2.git
synced 2024-10-26 17:11:21 +03:00
Add a few more OcrRequestQueue tests
This commit is contained in:
parent
6c64d1cf20
commit
9ab618acee
@ -234,6 +234,52 @@ public class OcrRequestQueueTests : ContextualTexts
|
||||
_mockEngine.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CancelOnceWithTwoReferences()
|
||||
{
|
||||
var tempPath1 = CreateTempFile();
|
||||
var tempPath2 = CreateTempFile();
|
||||
_mockEngine.Setup(x => x.ProcessImage(tempPath1, _ocrParams, It.IsAny<CancellationToken>()))
|
||||
.Returns(() => Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(100);
|
||||
return _expectedResult;
|
||||
}));
|
||||
// Delay the workers so we can cancel before processing starts
|
||||
_ocrRequestQueue.WorkerAddedLatency = 50;
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var ocrResult1Task = DoEnqueueForeground(_image, tempPath1, _ocrParams, cts.Token);
|
||||
var ocrResult2Task = DoEnqueueForeground(_image, tempPath2, _ocrParams);
|
||||
cts.Cancel();
|
||||
|
||||
var ocrResult1 = await ocrResult1Task;
|
||||
var ocrResult2 = await ocrResult2Task;
|
||||
Assert.Null(ocrResult1);
|
||||
Assert.Equal(_expectedResult, ocrResult2);
|
||||
_mockEngine.Verify(x => x.ProcessImage(tempPath1, _ocrParams, It.IsAny<CancellationToken>()));
|
||||
_mockEngine.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CancelTwiceWithTwoReferences()
|
||||
{
|
||||
// Delay the workers so we can cancel before processing starts
|
||||
_ocrRequestQueue.WorkerAddedLatency = 50;
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var ocrResult1Task = DoEnqueueForeground(_image, _tempPath, _ocrParams, cts.Token);
|
||||
var ocrResult2Task = DoEnqueueForeground(_image, _tempPath, _ocrParams, cts.Token);
|
||||
cts.Cancel();
|
||||
|
||||
var ocrResult1 = await ocrResult1Task;
|
||||
var ocrResult2 = await ocrResult2Task;
|
||||
Assert.Null(ocrResult1);
|
||||
Assert.Null(ocrResult2);
|
||||
await Task.Delay(100);
|
||||
_mockEngine.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ForegroundPrioritized()
|
||||
{
|
||||
@ -264,6 +310,47 @@ public class OcrRequestQueueTests : ContextualTexts
|
||||
int completedCount = tasks.Count(x => x.IsCompleted);
|
||||
Assert.Equal(1000, completedCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HasCachedResult()
|
||||
{
|
||||
_mockEngine.Setup(x => x.ProcessImage(_tempPath, _ocrParams, It.IsAny<CancellationToken>()))
|
||||
.Returns(_expectedResultTask);
|
||||
|
||||
await DoEnqueueForeground(_image, _tempPath, _ocrParams);
|
||||
|
||||
var ocrParams2 = new OcrParams("fra", OcrMode.Fast, 10);
|
||||
|
||||
Assert.True(_ocrRequestQueue.HasCachedResult(_mockEngine.Object, _image, _ocrParams));
|
||||
Assert.False(_ocrRequestQueue.HasCachedResult(_mockEngine.Object, _image, ocrParams2));
|
||||
Assert.False(_ocrRequestQueue.HasCachedResult(_mockEngine.Object, CreateScannedImage(), _ocrParams));
|
||||
Assert.False(_ocrRequestQueue.HasCachedResult(new Mock<IOcrEngine>().Object, _image, _ocrParams));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HasCachedResult_WhileProcessing()
|
||||
{
|
||||
_mockEngine.Setup(x => x.ProcessImage(_tempPath, _ocrParams, It.IsAny<CancellationToken>()))
|
||||
.Returns(_expectedResultTask);
|
||||
|
||||
_ocrRequestQueue.WorkerAddedLatency = 50;
|
||||
DoEnqueueForeground(_image, _tempPath, _ocrParams).AssertNoAwait();
|
||||
|
||||
Assert.False(_ocrRequestQueue.HasCachedResult(_mockEngine.Object, _image, _ocrParams));
|
||||
await Task.Delay(100);
|
||||
Assert.True(_ocrRequestQueue.HasCachedResult(_mockEngine.Object, _image, _ocrParams));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HasCachedResult_WithError()
|
||||
{
|
||||
_mockEngine.Setup(x => x.ProcessImage(_tempPath, _ocrParams, It.IsAny<CancellationToken>()))
|
||||
.Throws<Exception>();
|
||||
|
||||
await DoEnqueueForeground(_image, _tempPath, _ocrParams);
|
||||
|
||||
Assert.False(_ocrRequestQueue.HasCachedResult(_mockEngine.Object, _image, _ocrParams));
|
||||
}
|
||||
|
||||
private List<Task<OcrResult>> EnqueueMany(OcrPriority priority, int count)
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace NAPS2.Ocr;
|
||||
|
||||
// TODO: Might need to use configureawait(false) everywhere, or at least on non-worker threads...
|
||||
/// <summary>
|
||||
/// Allows OCR requests to be queued and prioritized. Results are cached so that requests with the same set of
|
||||
/// parameters (image, engine, language code, etc.) don't do duplicate work.
|
||||
@ -18,6 +19,11 @@ public class OcrRequestQueue
|
||||
/// in parallel.
|
||||
/// </summary>
|
||||
public int WorkerCount { get; init; } = Environment.ProcessorCount;
|
||||
|
||||
/// <summary>
|
||||
/// For testing. Adds a delay to the worker tasks to process requests.
|
||||
/// </summary>
|
||||
public int WorkerAddedLatency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if a previous queued request with the provided parameters has already completed and produced a
|
||||
@ -63,11 +69,11 @@ public class OcrRequestQueue
|
||||
_queueWaitHandle.Release();
|
||||
// If no worker threads are running, start them
|
||||
EnsureWorkerThreads();
|
||||
var result = await req.CompletedTask;
|
||||
await Task.WhenAny(req.CompletedTask, cancelToken.WaitHandle.WaitOneAsync());
|
||||
// If no requests are pending, stop the worker threads
|
||||
EnsureWorkerThreads();
|
||||
// May return null if cancelled
|
||||
return result;
|
||||
// Return null if canceled
|
||||
return req.CompletedTask.IsCompleted ? req.CompletedTask.Result : null;
|
||||
}
|
||||
|
||||
private void EnsureWorkerThreads()
|
||||
@ -96,6 +102,10 @@ public class OcrRequestQueue
|
||||
{
|
||||
try
|
||||
{
|
||||
if (WorkerAddedLatency > 0)
|
||||
{
|
||||
await Task.Delay(WorkerAddedLatency);
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
// Wait for a queued ocr request to become available
|
||||
|
Loading…
Reference in New Issue
Block a user