Esempio n. 1
0
        public void Test_FileCopierHost_HappyPath()
        {
            GlobalOptions globals = new GlobalOptionsFactory().Load();

            globals.FileSystemOptions.FileSystemRoot = "root";
            globals.FileSystemOptions.ExtractRoot    = "exroot";

            using var tester = new MicroserviceTester(globals.RabbitOptions, globals.FileCopierOptions);

            string outputQueueName = globals.FileCopierOptions.CopyStatusProducerOptions.ExchangeName.Replace("Exchange", "Queue");

            tester.CreateExchange(
                globals.FileCopierOptions.CopyStatusProducerOptions.ExchangeName,
                outputQueueName,
                false,
                globals.FileCopierOptions.NoVerifyRoutingKey);

            var mockFileSystem = new MockFileSystem();

            mockFileSystem.AddDirectory(globals.FileSystemOptions.FileSystemRoot);
            mockFileSystem.AddDirectory(globals.FileSystemOptions.ExtractRoot);
            mockFileSystem.AddFile(mockFileSystem.Path.Combine(globals.FileSystemOptions.FileSystemRoot, "file.dcm"), MockFileData.NullObject);

            var host = new FileCopierHost(globals, mockFileSystem);

            tester.StopOnDispose.Add(host);
            host.Start();

            var message = new ExtractFileMessage
            {
                ExtractionJobIdentifier  = Guid.NewGuid(),
                JobSubmittedAt           = DateTime.UtcNow,
                ProjectNumber            = "1234",
                ExtractionDirectory      = "1234/foo",
                DicomFilePath            = "file.dcm",
                IsIdentifiableExtraction = true,
                OutputPath = "output.dcm",
            };

            tester.SendMessage(globals.FileCopierOptions, message);

            using IConnection conn = tester.Factory.CreateConnection();
            using IModel model     = conn.CreateModel();
            var consumer = new EventingBasicConsumer(model);
            ExtractedFileStatusMessage statusMessage = null;

            consumer.Received += (_, ea) => statusMessage = JsonConvert.DeserializeObject <ExtractedFileStatusMessage>(Encoding.UTF8.GetString(ea.Body.ToArray()));
            model.BasicConsume(outputQueueName, true, "", consumer);

            new TestTimelineAwaiter().Await(() => statusMessage != null);
            Assert.AreEqual(ExtractedFileStatus.Copied, statusMessage.Status);
        }
Esempio n. 2
0
        public void ProcessMessage(
            [NotNull] ExtractFileMessage message,
            [NotNull] IMessageHeader header)
        {
            string fullSrc = _fileSystem.Path.Combine(_fileSystemRoot, message.DicomFilePath);

            ExtractedFileStatusMessage statusMessage;

            if (!_fileSystem.File.Exists(fullSrc))
            {
                statusMessage = new ExtractedFileStatusMessage(message)
                {
                    DicomFilePath = message.DicomFilePath,
                    Status        = ExtractedFileStatus.FileMissing,
                    StatusMessage = $"Could not find '{fullSrc}'"
                };
                _ = _copyStatusProducerModel.SendMessage(statusMessage, header, _options.NoVerifyRoutingKey);
                return;
            }

            string fullDest = _fileSystem.Path.Combine(_extractionRoot, message.ExtractionDirectory, message.OutputPath);

            if (_fileSystem.File.Exists(fullDest))
            {
                _logger.Warn($"Output file '{fullDest}' already exists. Will overwrite.");
            }

            IDirectoryInfo parent = _fileSystem.Directory.GetParent(fullDest);

            if (!parent.Exists)
            {
                _logger.Debug($"Creating directory '{parent}'");
                parent.Create();
            }

            _logger.Debug($"Copying source file to '{message.OutputPath}'");
            _fileSystem.File.Copy(fullSrc, fullDest, overwrite: true);

            statusMessage = new ExtractedFileStatusMessage(message)
            {
                DicomFilePath  = message.DicomFilePath,
                Status         = ExtractedFileStatus.Copied,
                OutputFilePath = message.OutputPath,
            };
            _ = _copyStatusProducerModel.SendMessage(statusMessage, header, _options.NoVerifyRoutingKey);
        }
Esempio n. 3
0
        private static BasicDeliverEventArgs GetMockDeliverArgs(ExtractFileMessage message)
        {
            var mockDeliverArgs = Mock.Of <BasicDeliverEventArgs>(MockBehavior.Strict);

            mockDeliverArgs.DeliveryTag     = 1;
            mockDeliverArgs.Body            = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));
            mockDeliverArgs.BasicProperties = new BasicProperties {
                Headers = new Dictionary <string, object>()
            };
            var header = new MessageHeader();

            header.Populate(mockDeliverArgs.BasicProperties.Headers);
            // Have to convert these to bytes since RabbitMQ normally does that when sending
            mockDeliverArgs.BasicProperties.Headers["MessageGuid"]            = Encoding.UTF8.GetBytes(header.MessageGuid.ToString());
            mockDeliverArgs.BasicProperties.Headers["ProducerExecutableName"] = Encoding.UTF8.GetBytes(header.ProducerExecutableName);
            mockDeliverArgs.BasicProperties.Headers["Parents"] = Encoding.UTF8.GetBytes(string.Join("->", header.Parents));
            return(mockDeliverArgs);
        }
Esempio n. 4
0
        public void SetUp()
        {
            _message = new ExtractFileMessage
            {
                JobSubmittedAt           = DateTime.UtcNow,
                ExtractionJobIdentifier  = Guid.NewGuid(),
                ProjectNumber            = "1234",
                ExtractionDirectory      = "foo",
                DicomFilePath            = "foo.dcm",
                IsIdentifiableExtraction = true,
                OutputPath = "bar",
            };
            _mockModel = new Mock <IModel>(MockBehavior.Strict);
            _mockModel.Setup(x => x.IsClosed).Returns(false);
            _mockModel.Setup(x => x.BasicAck(It.IsAny <ulong>(), It.IsAny <bool>()));
            _mockModel.Setup(x => x.BasicNack(It.IsAny <ulong>(), It.IsAny <bool>(), It.IsAny <bool>()));

            _mockFileCopier = new Mock <IFileCopier>(MockBehavior.Strict);
            _mockFileCopier.Setup(x => x.ProcessMessage(It.IsAny <ExtractFileMessage>(), It.IsAny <IMessageHeader>()));
        }
Esempio n. 5
0
        protected override void ProcessMessageImpl(IMessageHeader header, ExtractionRequestMessage request, ulong tag)
        {
            Logger.Info($"Received message: {request}");

            _auditor.AuditExtractionRequest(request);

            if (!request.ExtractionDirectory.StartsWith(request.ProjectNumber))
            {
                Logger.Debug("ExtractionDirectory did not start with the project number, doing ErrorAndNack");
                ErrorAndNack(header, tag, "", new InvalidEnumArgumentException("ExtractionDirectory"));
            }

            string extractionDirectory   = request.ExtractionDirectory.TrimEnd('/', '\\');
            string extractFileRoutingKey = request.IsIdentifiableExtraction ? _options.ExtractIdentRoutingKey : _options.ExtractAnonRoutingKey;

            foreach (ExtractImageCollection matchedFiles in _fulfiller.GetAllMatchingFiles(request, _auditor))
            {
                Logger.Info($"Accepted {matchedFiles.Accepted.Count} and rejected {matchedFiles.Rejected.Count} files for KeyValue {matchedFiles.KeyValue}");

                var infoMessage = new ExtractFileCollectionInfoMessage(request);

                foreach (QueryToExecuteResult accepted in matchedFiles.Accepted)
                {
                    var extractFileMessage = new ExtractFileMessage(request)
                    {
                        // Path to the original file
                        DicomFilePath = accepted.FilePathValue.TrimStart('/', '\\'),
                        // Extraction directory relative to the extract root
                        ExtractionDirectory = extractionDirectory,
                        // Output path for the anonymised file, relative to the extraction directory
                        OutputPath = _resolver.GetOutputPath(accepted, request).Replace('\\', '/')
                    };

                    Logger.Debug($"DicomFilePath={extractFileMessage.DicomFilePath}, OutputPath={extractFileMessage.OutputPath}");

                    // Send the extract file message
                    var sentHeader = (MessageHeader)_fileMessageProducer.SendMessage(extractFileMessage, header, extractFileRoutingKey);

                    // Record that we sent it
                    infoMessage.ExtractFileMessagesDispatched.Add(sentHeader, extractFileMessage.OutputPath);
                }

                // Wait for confirms from the batched messages
                Logger.Debug($"All file messages sent for {request.ExtractionJobIdentifier}, calling WaitForConfirms");
                _fileMessageProducer.WaitForConfirms();

                // For all the rejected messages log why (in the info message)
                foreach (QueryToExecuteResult rejectedResults in matchedFiles.Rejected)
                {
                    if (!infoMessage.RejectionReasons.ContainsKey(rejectedResults.RejectReason))
                    {
                        infoMessage.RejectionReasons.Add(rejectedResults.RejectReason, 0);
                    }

                    infoMessage.RejectionReasons[rejectedResults.RejectReason]++;
                }

                _auditor.AuditExtractFiles(request, matchedFiles);

                infoMessage.KeyValue = matchedFiles.KeyValue;
                _fileMessageInfoProducer.SendMessage(infoMessage, header);

                if (_fileMessageInfoProducer.GetType() == typeof(BatchProducerModel))
                {
                    _fileMessageInfoProducer.WaitForConfirms();
                }

                Logger.Info($"All messages sent and acknowledged for {matchedFiles.KeyValue}");
            }

            Logger.Info("Finished processing message");
            Ack(header, tag);
        }