From 5391dc2956387f764f563330a749c133e269d115 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Sat, 11 Mar 2023 08:26:40 +0800 Subject: [PATCH 1/5] gh-347 Remove incomplete payloads on timeout Signed-off-by: Victor Chang --- .../Services/Connectors/PayloadAssembler.cs | 4 ++-- .../Services/Storage/ObjectUploadService.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/InformaticsGateway/Services/Connectors/PayloadAssembler.cs b/src/InformaticsGateway/Services/Connectors/PayloadAssembler.cs index 38aed2197..d50ba4b81 100644 --- a/src/InformaticsGateway/Services/Connectors/PayloadAssembler.cs +++ b/src/InformaticsGateway/Services/Connectors/PayloadAssembler.cs @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 MONAI Consortium + * Copyright 2021-2023 MONAI Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -149,7 +149,7 @@ private async void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e) _logger.BucketRemoveError(key); } } - else if (payload.AnyUploadFailures()) + else { _payloads.TryRemove(key, out _); _logger.PayloadRemovedWithFailureUploads(key); diff --git a/src/InformaticsGateway/Services/Storage/ObjectUploadService.cs b/src/InformaticsGateway/Services/Storage/ObjectUploadService.cs index b7d539047..0399770ac 100644 --- a/src/InformaticsGateway/Services/Storage/ObjectUploadService.cs +++ b/src/InformaticsGateway/Services/Storage/ObjectUploadService.cs @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 MONAI Consortium + * Copyright 2021-2023 MONAI Consortium * Copyright 2019-2021 NVIDIA Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -103,7 +103,7 @@ private async Task StartWorker(int thread, CancellationToken cancellationToken) { try { - var item = await _uplaodQueue.Dequeue(cancellationToken); + var item = await _uplaodQueue.Dequeue(cancellationToken).ConfigureAwait(false); await ProcessObject(item).ConfigureAwait(false); } catch (OperationCanceledException ex) From c762f1c66a39ebbae94694816d078bbd981f3588 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Sat, 11 Mar 2023 08:39:16 +0800 Subject: [PATCH 2/5] gh-347 Update unit test Signed-off-by: Victor Chang --- .../Test/Services/Connectors/PayloadAssemblerTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/InformaticsGateway/Test/Services/Connectors/PayloadAssemblerTest.cs b/src/InformaticsGateway/Test/Services/Connectors/PayloadAssemblerTest.cs index 82a62c62d..163c1e5f6 100644 --- a/src/InformaticsGateway/Test/Services/Connectors/PayloadAssemblerTest.cs +++ b/src/InformaticsGateway/Test/Services/Connectors/PayloadAssemblerTest.cs @@ -116,18 +116,18 @@ public async Task GivenAPayloadAssembler_WhenDisposed_ExpectResourceToBeCleanedU } [RetryFact(10, 200)] - public async Task GivenAPayloadThatHasNotCompleteUploads_WhenProcessedByTimedEvent_ExpectToBeAddedToQueue() + public async Task GivenAPayloadThatHasNotCompleteUploads_WhenProcessedByTimedEvent_ExpectToBeRemovedFromQueue() { var payloadAssembler = new PayloadAssembler(_options, _logger.Object, _serviceScopeFactory.Object); var file = new TestStorageInfo(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "file1", ".txt"); - file.File.SetUploaded("bucket"); await payloadAssembler.Queue("A", file, 1); await Task.Delay(1001); payloadAssembler.Dispose(); - _repository.Verify(p => p.UpdateAsync(It.Is(p => p.State == Payload.PayloadState.Move), It.IsAny()), Times.Once()); + _repository.Verify(p => p.UpdateAsync(It.Is(p => p.State == Payload.PayloadState.Move), It.IsAny()), Times.Never()); + _logger.VerifyLoggingMessageBeginsWith("Payload deleted due to upload failure(s)", LogLevel.Error, Times.Once()); } [RetryFact(10, 200)] From f35421872b5943beba732db4ab318556d4cb4f36 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Sat, 11 Mar 2023 14:22:33 +0800 Subject: [PATCH 3/5] gh-347 Update integration tests Signed-off-by: Victor Chang --- src/Api/MonaiApplicationEntity.cs | 3 +- src/Api/Storage/Payload.cs | 2 +- src/Configuration/DicomWebConfiguration.cs | 5 +-- .../Logging/Log.3000.PayloadAssembler.cs | 4 +-- .../Services/Connectors/PayloadAssembler.cs | 5 +-- .../Services/Connectors/PayloadExtensions.cs | 6 ++-- .../Services/Http/InferenceController.cs | 3 +- .../Services/Storage/ObjectUploadService.cs | 1 + src/InformaticsGateway/appsettings.json | 2 +- tests/Integration.Test/Common/Hl7DataSink.cs | 7 +++- .../Features/DicomDimseScp.feature | 34 +++++++++---------- .../Features/DicomWebStow.feature | 6 ++-- .../StepDefinitions/FhirDefinitions.cs | 4 +-- .../HealthLevel7Definitions.cs | 4 +-- tests/Integration.Test/appsettings.json | 5 ++- tests/Integration.Test/study.json | 4 +-- 16 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/Api/MonaiApplicationEntity.cs b/src/Api/MonaiApplicationEntity.cs index f5878c029..9512ba64c 100644 --- a/src/Api/MonaiApplicationEntity.cs +++ b/src/Api/MonaiApplicationEntity.cs @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 MONAI Consortium + * Copyright 2021-2023 MONAI Consortium * Copyright 2019-2021 NVIDIA Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,6 @@ * limitations under the License. */ -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; diff --git a/src/Api/Storage/Payload.cs b/src/Api/Storage/Payload.cs index fb46d5ea4..279d3d7ab 100644 --- a/src/Api/Storage/Payload.cs +++ b/src/Api/Storage/Payload.cs @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 MONAI Consortium + * Copyright 2021-2023 MONAI Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/Configuration/DicomWebConfiguration.cs b/src/Configuration/DicomWebConfiguration.cs index f57a58ab7..4e5eed446 100644 --- a/src/Configuration/DicomWebConfiguration.cs +++ b/src/Configuration/DicomWebConfiguration.cs @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 MONAI Consortium + * Copyright 2021-2023 MONAI Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,7 +55,8 @@ public class DicomWebConfiguration /// single POST request, therefore, the timeout value may be insignificant unless the load of the /// network affects the upload speed. /// - public uint Timeout { get; set; } = 2; + [ConfigurationKeyName("timeout")] + public uint Timeout { get; set; } = 10; public DicomWebConfiguration() { diff --git a/src/InformaticsGateway/Logging/Log.3000.PayloadAssembler.cs b/src/InformaticsGateway/Logging/Log.3000.PayloadAssembler.cs index f57327565..678ba4245 100644 --- a/src/InformaticsGateway/Logging/Log.3000.PayloadAssembler.cs +++ b/src/InformaticsGateway/Logging/Log.3000.PayloadAssembler.cs @@ -54,7 +54,7 @@ public static partial class Log [LoggerMessage(EventId = 3012, Level = LogLevel.Information, Message = "Bucket {key} created with timeout {timeout}s.")] public static partial void BucketCreated(this ILogger logger, string key, uint timeout); - [LoggerMessage(EventId = 3014, Level = LogLevel.Error, Message = "Payload deleted due to upload failure(s) {key}.")] - public static partial void PayloadRemovedWithFailureUploads(this ILogger logger, string key); + [LoggerMessage(EventId = 3014, Level = LogLevel.Error, Message = "Payload ({key}) with {totalNumberOfFiles} files deleted due to {failures} upload failure(s).")] + public static partial void PayloadRemovedWithFailureUploads(this ILogger logger, string key, int totalNumberOfFiles, int failures); } } diff --git a/src/InformaticsGateway/Services/Connectors/PayloadAssembler.cs b/src/InformaticsGateway/Services/Connectors/PayloadAssembler.cs index d50ba4b81..92609997e 100644 --- a/src/InformaticsGateway/Services/Connectors/PayloadAssembler.cs +++ b/src/InformaticsGateway/Services/Connectors/PayloadAssembler.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Ardalis.GuardClauses; @@ -149,10 +150,10 @@ private async void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e) _logger.BucketRemoveError(key); } } - else + else if (payload.IsUploadCompletedWithFailures()) { _payloads.TryRemove(key, out _); - _logger.PayloadRemovedWithFailureUploads(key); + _logger.PayloadRemovedWithFailureUploads(key, payload.Count, payload.Files.Count(p => p.IsUploadFailed)); } } } diff --git a/src/InformaticsGateway/Services/Connectors/PayloadExtensions.cs b/src/InformaticsGateway/Services/Connectors/PayloadExtensions.cs index 921d0f1a8..b6ac12e4e 100644 --- a/src/InformaticsGateway/Services/Connectors/PayloadExtensions.cs +++ b/src/InformaticsGateway/Services/Connectors/PayloadExtensions.cs @@ -1,5 +1,5 @@ /* - * Copyright 2022 MONAI Consortium + * Copyright 2022-2023 MONAI Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,9 +28,9 @@ public static bool IsUploadCompleted(this Payload payload) return payload.Files.All(p => p.IsUploaded); } - public static bool AnyUploadFailures(this Payload payload) + public static bool IsUploadCompletedWithFailures(this Payload payload) { - return payload.Files.Any(p => p.IsUploadFailed); + return payload.Files.Count(p => p.IsUploadFailed) + payload.Files.Count(p => p.IsUploaded) == payload.Count; ; } public static bool IsMoveCompleted(this Payload payload) diff --git a/src/InformaticsGateway/Services/Http/InferenceController.cs b/src/InformaticsGateway/Services/Http/InferenceController.cs index 05d8644bf..d0a588bb5 100644 --- a/src/InformaticsGateway/Services/Http/InferenceController.cs +++ b/src/InformaticsGateway/Services/Http/InferenceController.cs @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 MONAI Consortium + * Copyright 2021-2023 MONAI Consortium * Copyright 2019-2021 NVIDIA Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -90,7 +90,6 @@ public async Task NewInferenceRequest([FromBody] InferenceRequest using var _ = _logger.BeginScope(new LoggingDataDictionary { { "TransactionId", request.TransactionId } }); try { - if (await _inferenceRequestRepository.ExistsAsync(request.TransactionId, HttpContext.RequestAborted).ConfigureAwait(false)) { return Problem(title: "Conflict", statusCode: (int)HttpStatusCode.Conflict, detail: "An existing request with same transaction ID already exists."); diff --git a/src/InformaticsGateway/Services/Storage/ObjectUploadService.cs b/src/InformaticsGateway/Services/Storage/ObjectUploadService.cs index 0399770ac..f7a05aad4 100644 --- a/src/InformaticsGateway/Services/Storage/ObjectUploadService.cs +++ b/src/InformaticsGateway/Services/Storage/ObjectUploadService.cs @@ -164,6 +164,7 @@ private async Task ProcessObject(FileStorageMetadata blob) } catch (Exception ex) { + blob.SetFailed(); _logger.FailedToUploadFile(blob.Id, ex); } finally diff --git a/src/InformaticsGateway/appsettings.json b/src/InformaticsGateway/appsettings.json index f0087463a..0b825c562 100644 --- a/src/InformaticsGateway/appsettings.json +++ b/src/InformaticsGateway/appsettings.json @@ -112,4 +112,4 @@ "InformaticsGatewayServerEndpoint": "http://localhost:5000", "DockerImagePrefix": "ghcr.io/project-monai/monai-deploy-informatics-gateway" } -} +} \ No newline at end of file diff --git a/tests/Integration.Test/Common/Hl7DataSink.cs b/tests/Integration.Test/Common/Hl7DataSink.cs index 162ad4673..607d960f0 100644 --- a/tests/Integration.Test/Common/Hl7DataSink.cs +++ b/tests/Integration.Test/Common/Hl7DataSink.cs @@ -1,5 +1,5 @@ /* - * Copyright 2022 MONAI Consortium + * Copyright 2022-2023 MONAI Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,6 +14,7 @@ * limitations under the License. */ +using System.Diagnostics; using System.Net.Sockets; using System.Text; using Ardalis.GuardClauses; @@ -95,6 +96,8 @@ private async Task SendOneAsync(DataProvider dataProvider, params object[] args) private async Task SendBatchAsync(DataProvider dataProvider, params object[] args) { + var stopwatch = new Stopwatch(); + stopwatch.Start(); var messages = new List(); foreach (var file in dataProvider.HL7Specs.Files.Keys) { @@ -134,6 +137,8 @@ private async Task SendBatchAsync(DataProvider dataProvider, params object[] arg } } while (true); tcpClient.Close(); + stopwatch.Stop(); + _outputHelper.WriteLine($"Took {stopwatch.Elapsed.TotalSeconds}s to send {messages.Count} messages."); } } } diff --git a/tests/Integration.Test/Features/DicomDimseScp.feature b/tests/Integration.Test/Features/DicomDimseScp.feature index b14b93d4f..bbd92c14f 100644 --- a/tests/Integration.Test/Features/DicomDimseScp.feature +++ b/tests/Integration.Test/Features/DicomDimseScp.feature @@ -1,4 +1,4 @@ -# Copyright 2022 MONAI Consortium +# Copyright 2022-2023 MONAI Consortium # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -37,47 +37,47 @@ Feature: DICOM DIMSE SCP Services @messaging_workflow_request @messaging Scenario Outline: Respond to C-STORE-RQ and group data by Study Instance UID - Given a called AE Title named 'C-STORE-STUDY' that groups by '0020,000D' for 3 seconds + Given a called AE Title named '' that groups by '0020,000D' for seconds And a DICOM client configured with 300 seconds timeout And a DICOM client configured to send data over 1 associations and wait 0 between each association And studies - When a C-STORE-RQ is sent to 'Informatics Gateway' with AET 'C-STORE-STUDY' from 'TEST-RUNNER' + When a C-STORE-RQ is sent to 'Informatics Gateway' with AET '' from 'TEST-RUNNER' Then a successful response should be received And workflow requests sent to message broker And studies are uploaded to storage service Examples: - | modality | count | - | MR | 1 | - | CT | 1 | - | MG | 2 | - | US | 1 | + | modality | count | aet | timeout | + | MR | 1 | C-STORE-STUDY30 | 30 | + | CT | 1 | C-STORE-STUDY30 | 30 | + | MG | 2 | C-STORE-STUDY10 | 10 | + | US | 1 | C-STORE-STUDY10 | 10 | @messaging_workflow_request @messaging Scenario Outline: Respond to C-STORE-RQ and group data by Series Instance UID - Given a called AE Title named 'C-STORE-SERIES' that groups by '0020,000E' for 3 seconds + Given a called AE Title named '' that groups by '0020,000E' for seconds And a DICOM client configured with 300 seconds timeout And a DICOM client configured to send data over 1 associations and wait 0 between each association And studies with series per study - When a C-STORE-RQ is sent to 'Informatics Gateway' with AET 'C-STORE-SERIES' from 'TEST-RUNNER' + When a C-STORE-RQ is sent to 'Informatics Gateway' with AET '' from 'TEST-RUNNER' Then a successful response should be received And workflow requests sent to message broker And studies are uploaded to storage service Examples: - | modality | study_count | series_count | - | MR | 1 | 2 | - | CT | 1 | 2 | - | MG | 1 | 3 | - | US | 1 | 2 | + | modality | study_count | series_count | aet | timeout | + | MR | 1 | 2 | C-STORE-SER30 | 30 | + | CT | 1 | 2 | C-STORE-SER30 | 30 | + | MG | 1 | 3 | C-STORE-SER10 | 10 | + | US | 1 | 2 | C-STORE-SER10 | 10 | @messaging_workflow_request @messaging Scenario Outline: Respond to C-STORE-RQ and group data by Study Instance UID over multiple associations - Given a called AE Title named 'C-STORE-STUDY' that groups by '0020,000D' for 5 seconds + Given a called AE Title named 'C-STORE-MA' that groups by '0020,000D' for 10 seconds And a DICOM client configured with 300 seconds timeout And a DICOM client configured to send data over associations and wait between each association And studies with series per study - When C-STORE-RQ are sent to 'Informatics Gateway' with AET 'C-STORE-STUDY' from 'TEST-RUNNER' + When C-STORE-RQ are sent to 'Informatics Gateway' with AET 'C-STORE-MA' from 'TEST-RUNNER' Then a successful response should be received And workflow requests sent to message broker And studies are uploaded to storage service diff --git a/tests/Integration.Test/Features/DicomWebStow.feature b/tests/Integration.Test/Features/DicomWebStow.feature index bde7ec334..f49224294 100644 --- a/tests/Integration.Test/Features/DicomWebStow.feature +++ b/tests/Integration.Test/Features/DicomWebStow.feature @@ -1,4 +1,4 @@ -# Copyright 2022 MONAI Consortium +# Copyright 2022-2023 MONAI Consortium # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -39,8 +39,8 @@ Feature: DICOMweb STOW-RS Service And studies are uploaded to storage service Examples: | modality | count | - | CT | 2 | - | US | 1 | + | MR | 1 | + | MG | 2 | @messaging_workflow_request @messaging Scenario: Triggers a new workflow via DICOMWeb STOW-RS diff --git a/tests/Integration.Test/StepDefinitions/FhirDefinitions.cs b/tests/Integration.Test/StepDefinitions/FhirDefinitions.cs index d1122a070..468b6a682 100644 --- a/tests/Integration.Test/StepDefinitions/FhirDefinitions.cs +++ b/tests/Integration.Test/StepDefinitions/FhirDefinitions.cs @@ -1,5 +1,5 @@ /* - * Copyright 2022 MONAI Consortium + * Copyright 2022-2023 MONAI Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ public class FhirDefinitions internal enum FileFormat { Xml, Json }; - internal static readonly TimeSpan WaitTimeSpan = TimeSpan.FromMinutes(2); + internal static readonly TimeSpan WaitTimeSpan = TimeSpan.FromMinutes(3); private readonly InformaticsGatewayConfiguration _informaticsGatewayConfiguration; private readonly RabbitMqConsumer _receivedMessages; private readonly DataProvider _dataProvider; diff --git a/tests/Integration.Test/StepDefinitions/HealthLevel7Definitions.cs b/tests/Integration.Test/StepDefinitions/HealthLevel7Definitions.cs index 22ccde5f3..62b00d05d 100644 --- a/tests/Integration.Test/StepDefinitions/HealthLevel7Definitions.cs +++ b/tests/Integration.Test/StepDefinitions/HealthLevel7Definitions.cs @@ -1,5 +1,5 @@ /* - * Copyright 2022 MONAI Consortium + * Copyright 2022-2023 MONAI Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,7 +73,7 @@ public void ThenAcknowledgementAreReceived() [Then(@"a workflow requests sent to message broker")] public async Task ThenAWorkflowRequestIsSentToMessageBrokerAsync() { - (await _receivedMessages.WaitforAsync(_dataProvider.HL7Specs.Files.Count, WaitTimeSpan)).Should().BeTrue(); + (await _receivedMessages.WaitforAsync(1, WaitTimeSpan)).Should().BeTrue(); } [Then(@"messages are uploaded to storage service")] diff --git a/tests/Integration.Test/appsettings.json b/tests/Integration.Test/appsettings.json index 5a76bff99..fe254e737 100644 --- a/tests/Integration.Test/appsettings.json +++ b/tests/Integration.Test/appsettings.json @@ -20,6 +20,9 @@ "logDataPDUs": false } }, + "dicomWeb": { + "timeout": 10 + }, "messaging": { "publisherServiceAssemblyName": "Monai.Deploy.Messaging.RabbitMQ.RabbitMQMessagePublisherService, Monai.Deploy.Messaging.RabbitMQ", "publisherSettings": { @@ -83,4 +86,4 @@ "InformaticsGatewayServerEndpoint": "http://127.0.0.1:5000", "DockerImagePrefix": "ghcr.io/project-monai/monai-deploy-informatics-gateway" } -} +} \ No newline at end of file diff --git a/tests/Integration.Test/study.json b/tests/Integration.Test/study.json index 4e08cc3e0..cf0308fb7 100644 --- a/tests/Integration.Test/study.json +++ b/tests/Integration.Test/study.json @@ -10,8 +10,8 @@ "CT": { "SeriesMin": 1, "SeriesMax": 2, - "InstanceMin": 60, - "InstanceMax": 1000, + "InstanceMin": 50, + "InstanceMax": 300, "SizeMin": 0.5, "SizeMax": 1 }, From 46d62b13f249e2273cef003439d13600ce12fbf8 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Sat, 11 Mar 2023 19:27:23 +0800 Subject: [PATCH 4/5] gh-347 Fix unit test Signed-off-by: Victor Chang --- .../Test/Services/Connectors/PayloadAssemblerTest.cs | 11 ++++++++--- src/Shared/Test/TestStorageInfo.cs | 6 ++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/InformaticsGateway/Test/Services/Connectors/PayloadAssemblerTest.cs b/src/InformaticsGateway/Test/Services/Connectors/PayloadAssemblerTest.cs index 163c1e5f6..2de3a4b6f 100644 --- a/src/InformaticsGateway/Test/Services/Connectors/PayloadAssemblerTest.cs +++ b/src/InformaticsGateway/Test/Services/Connectors/PayloadAssemblerTest.cs @@ -120,14 +120,19 @@ public async Task GivenAPayloadThatHasNotCompleteUploads_WhenProcessedByTimedEve { var payloadAssembler = new PayloadAssembler(_options, _logger.Object, _serviceScopeFactory.Object); - var file = new TestStorageInfo(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "file1", ".txt"); + var file1 = new TestStorageInfo(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "file1", ".txt"); + var file2 = new TestStorageInfo(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "file1", ".txt"); - await payloadAssembler.Queue("A", file, 1); + await payloadAssembler.Queue("A", file1, 1); + await payloadAssembler.Queue("A", file2, 1); + + file1.SetFailed(); + file2.SetUploaded(); await Task.Delay(1001); payloadAssembler.Dispose(); _repository.Verify(p => p.UpdateAsync(It.Is(p => p.State == Payload.PayloadState.Move), It.IsAny()), Times.Never()); - _logger.VerifyLoggingMessageBeginsWith("Payload deleted due to upload failure(s)", LogLevel.Error, Times.Once()); + _logger.VerifyLoggingMessageBeginsWith($"Payload (A) with 2 files deleted due to 1 upload failure(s).", LogLevel.Error, Times.Once()); } [RetryFact(10, 200)] diff --git a/src/Shared/Test/TestStorageInfo.cs b/src/Shared/Test/TestStorageInfo.cs index 76627a8ef..96ab71bfc 100644 --- a/src/Shared/Test/TestStorageInfo.cs +++ b/src/Shared/Test/TestStorageInfo.cs @@ -15,6 +15,7 @@ */ using Monai.Deploy.InformaticsGateway.Api.Storage; +using Monai.Deploy.Messaging; namespace Monai.Deploy.InformaticsGateway.SharedTest; @@ -33,4 +34,9 @@ public TestStorageInfo(string correlationsId, string identifier, string filePath public override string DataTypeDirectoryName => "dir"; public override StorageObjectMetadata File { get; set; } + + public void SetUploaded() + { + File.SetUploaded("test"); + } } From fd37177cb9c6c7c546ff835740ecd9cfbab3a95c Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Sat, 11 Mar 2023 20:08:28 +0800 Subject: [PATCH 5/5] gh-347 Fix integration test Signed-off-by: Victor Chang --- .../Features/DicomDimseScp.feature | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/Integration.Test/Features/DicomDimseScp.feature b/tests/Integration.Test/Features/DicomDimseScp.feature index bbd92c14f..1c4116a16 100644 --- a/tests/Integration.Test/Features/DicomDimseScp.feature +++ b/tests/Integration.Test/Features/DicomDimseScp.feature @@ -48,10 +48,10 @@ Feature: DICOM DIMSE SCP Services Examples: | modality | count | aet | timeout | - | MR | 1 | C-STORE-STUDY30 | 30 | - | CT | 1 | C-STORE-STUDY30 | 30 | - | MG | 2 | C-STORE-STUDY10 | 10 | - | US | 1 | C-STORE-STUDY10 | 10 | + | MR | 1 | C-STORE-STUDY30 | 3 | + | CT | 1 | C-STORE-STUDY30 | 3 | + | MG | 2 | C-STORE-STUDY10 | 3 | + | US | 1 | C-STORE-STUDY10 | 3 | @messaging_workflow_request @messaging Scenario Outline: Respond to C-STORE-RQ and group data by Series Instance UID @@ -66,14 +66,14 @@ Feature: DICOM DIMSE SCP Services Examples: | modality | study_count | series_count | aet | timeout | - | MR | 1 | 2 | C-STORE-SER30 | 30 | - | CT | 1 | 2 | C-STORE-SER30 | 30 | - | MG | 1 | 3 | C-STORE-SER10 | 10 | - | US | 1 | 2 | C-STORE-SER10 | 10 | + | MR | 1 | 2 | C-STORE-SER30 | 3 | + | CT | 1 | 2 | C-STORE-SER30 | 3 | + | MG | 1 | 3 | C-STORE-SER10 | 3 | + | US | 1 | 2 | C-STORE-SER10 | 3 | @messaging_workflow_request @messaging Scenario Outline: Respond to C-STORE-RQ and group data by Study Instance UID over multiple associations - Given a called AE Title named 'C-STORE-MA' that groups by '0020,000D' for 10 seconds + Given a called AE Title named 'C-STORE-MA' that groups by '0020,000D' for 5 seconds And a DICOM client configured with 300 seconds timeout And a DICOM client configured to send data over associations and wait between each association And studies with series per study