Example #1
0
        public void EditSpecification_GivenProviderVersionChangesAndRegenerateScopedProvidersFails_ExceptionThrown()
        {
            //Arrange
            var existingFundingStreams = _specification.Current.FundingStreams;
            SpecificationEditModel specificationEditModel = new SpecificationEditModel
            {
                FundingPeriodId = "fp10",
                Name            = "new spec name"
            };

            PolicyModels.FundingStream fundingStream = new PolicyModels.FundingStream
            {
                Id = existingFundingStreams.First().Id
            };
            Models.Specs.SpecificationVersion newSpecVersion = _specification.Current.Clone() as Models.Specs.SpecificationVersion;
            newSpecVersion.Name             = specificationEditModel.Name;
            newSpecVersion.FundingPeriod.Id = specificationEditModel.FundingPeriodId;
            newSpecVersion.FundingStreams   = new[] { new Reference {
                                                          Id = "fs11"
                                                      } };
            newSpecVersion.ProviderVersionId = "Provider version 2";

            _providersApiClient.RegenerateProviderSummariesForSpecification(_specification.Id, true)
            .Returns(new ApiResponse <bool>(HttpStatusCode.BadRequest));

            var service = CreateSpecificationsService(newSpecVersion);

            //Act
            Func <Task> invocation = async() => await service.EditSpecification(SpecificationId, specificationEditModel, null, null);

            //Arrange
            invocation.Should()
            .Throw <RetriableException>()
            .WithMessage($"Unable to re-generate scoped providers while editing specification '{_specification.Id}' with status code: {HttpStatusCode.BadRequest}");
        }
Example #2
0
        public async Task EditSpecification_GivenFailsToUpdateCosmosWithBadRequest_ReturnsBadRequest()
        {
            //Arrange
            IEnumerable <Reference> existingFundingStreams = _specification.Current.FundingStreams;
            SpecificationEditModel  specificationEditModel = new SpecificationEditModel
            {
                FundingPeriodId   = "fp10",
                ProviderVersionId = _specification.Current.ProviderVersionId
            };

            PolicyModels.FundingStream fundingStream = new PolicyModels.FundingStream
            {
                Id   = existingFundingStreams.First().Id,
                Name = existingFundingStreams.First().Name
            };
            ApiResponse <PolicyModels.FundingStream> fundingStreamResponse =
                new ApiResponse <PolicyModels.FundingStream>(HttpStatusCode.OK, fundingStream);

            _specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(_specification);
            _policiesApiClient
            .GetFundingPeriodById(Arg.Is(_fundingPeriod.Id))
            .Returns(_fundingPeriodResponse);
            _policiesApiClient
            .GetFundingStreamById(Arg.Is(fundingStream.Id))
            .Returns(fundingStreamResponse);
            _specificationsRepository
            .UpdateSpecification(Arg.Any <Specification>())
            .Returns(HttpStatusCode.BadRequest);

            AndGetFundingConfiguration(
                _specification.Current.FundingStreams.FirstOrDefault().Id,
                specificationEditModel.FundingPeriodId);

            SpecificationsService service = CreateService(mapper: _mapper, logs: _logger, specificationsRepository: _specificationsRepository, policiesApiClient: _policiesApiClient);

            //Act
            IActionResult result = await service.EditSpecification(SpecificationId, specificationEditModel, null, null);

            //Assert
            result
            .Should()
            .BeOfType <StatusCodeResult>()
            .Which
            .StatusCode
            .Should()
            .Be(400);
        }
        private void ThenFundingStreamResultMatches(IEnumerable <PoliciesApiModels.FundingStream> fundingStreams)
        {
            fundingStreams
            .Count()
            .Should()
            .Be(1);

            fundingStreams
            .FirstOrDefault()
            .Should()
            .NotBeNull();

            PoliciesApiModels.FundingStream fundingStream = fundingStreams.FirstOrDefault();

            fundingStream
            .Id
            .Should()
            .Be(_fundingStreamId);

            fundingStream
            .Name
            .Should()
            .Be(_fundingStreamName);
        }
Example #4
0
        private async Task <IActionResult> SaveDatasetDefinition(DatasetDefinition definition, string correlationId, Reference user)
        {
            DatasetDefinitionChanges datasetDefinitionChanges = new DatasetDefinitionChanges();

            DatasetDefinition existingDefinition = await _datasetsRepositoryPolicy.ExecuteAsync(() => _datasetsRepository.GetDatasetDefinition(definition.Id));

            IEnumerable <string> relationships = null;

            if (existingDefinition != null)
            {
                datasetDefinitionChanges = _definitionChangesDetectionService.DetectChanges(definition, existingDefinition);

                relationships = await _datasetsRepositoryPolicy.ExecuteAsync(() => _datasetsRepository.GetDistinctRelationshipSpecificationIdsForDatasetDefinitionId(datasetDefinitionChanges.Id));

                IEnumerable <FieldDefinitionChanges> fieldDefinitionChanges = datasetDefinitionChanges.TableDefinitionChanges.SelectMany(m => m.FieldChanges);

                if (!relationships.IsNullOrEmpty() && !fieldDefinitionChanges.IsNullOrEmpty())
                {
                    if (fieldDefinitionChanges.Any(m => m.ChangeTypes.Any(c => c == FieldDefinitionChangeType.RemovedField)))
                    {
                        return(new BadRequestObjectResult("Unable to remove a field as there are currently relationships setup against this schema"));
                    }

                    if (fieldDefinitionChanges.Any(m => m.ChangeTypes.Any(c => c == FieldDefinitionChangeType.IdentifierType)))
                    {
                        return(new BadRequestObjectResult("Unable to change provider identifier as there are currently relationships setup against this schema"));
                    }
                }
            }

            try
            {
                HttpStatusCode result = await _datasetsRepositoryPolicy.ExecuteAsync(() => _datasetsRepository.SaveDefinition(definition));

                if (!result.IsSuccess())
                {
                    int statusCode = (int)result;

                    _logger.Error($"Failed to save dataset definition - {definition.Name} to cosmos db with status {statusCode}");

                    return(new StatusCodeResult(statusCode));
                }

                IEnumerable <PoliciesApiModels.FundingStream> fundingStreams = await _policyRepository.GetFundingStreams();

                PoliciesApiModels.FundingStream fundingStream = fundingStreams.SingleOrDefault(_ => _.Id == definition.FundingStreamId);

                await IndexDatasetDefinition(definition, fundingStream);
            }
            catch (Exception exception)
            {
                string errorMessage = $"Exception occurred writing dataset definition - {definition.Name} to cosmos db";
                _logger.Error(exception, errorMessage);
                return(new InternalServerErrorResult(errorMessage));
            }

            byte[] excelAsBytes = _excelWriter.Write(definition);

            if (excelAsBytes == null || excelAsBytes.Length == 0)
            {
                string errorMessage = $"Failed to generate excel file for {definition.Name}";
                _logger.Error(errorMessage);
                return(new InternalServerErrorResult(errorMessage));
            }

            try
            {
                await SaveToBlobStorage(excelAsBytes, definition.Name);
            }
            catch (Exception ex)
            {
                return(new InternalServerErrorResult(ex.Message));
            }

            _logger.Information($"Successfully saved dataset definition - {definition.Name} to cosmos db");

            if (existingDefinition != null && datasetDefinitionChanges.HasChanges)
            {
                if (!relationships.IsNullOrEmpty())
                {
                    Task <ApiResponse <CalcJob> >[] updateCodeContextJobs =
                        relationships.Select(specificationId => _calculationsResilience.ExecuteAsync(() =>
                                                                                                     _calculations.QueueCodeContextUpdate(specificationId))).ToArray();

                    await TaskHelper.WhenAllAndThrow(updateCodeContextJobs);
                }

                IDictionary <string, string> properties = MessageExtensions.BuildMessageProperties(correlationId, user);

                await _messengerService.SendToTopic(ServiceBusConstants.TopicNames.DataDefinitionChanges, datasetDefinitionChanges, properties);
            }

            return(new OkResult());
        }
Example #5
0
        private async Task <IEnumerable <IndexError> > IndexDatasetDefinition(DatasetDefinition definition, PoliciesApiModels.FundingStream fundingStream)
        {
            // Calculate hash for model to see if there are changes
            string modelJson = JsonConvert.SerializeObject(definition);
            string hashCode  = "";

            using (SHA256 sha256Generator = SHA256Managed.Create())
            {
                byte[] modelBytes = UTF8Encoding.UTF8.GetBytes(modelJson);
                foreach (byte hashByte in sha256Generator.ComputeHash(modelBytes))
                {
                    hashCode += string.Format("{0:X2}", hashByte);
                }
            }

            DatasetDefinitionIndex datasetDefinitionIndex = new DatasetDefinitionIndex()
            {
                Id                 = definition.Id,
                Name               = definition.Name,
                Description        = definition.Description,
                LastUpdatedDate    = DateTimeOffset.Now,
                ProviderIdentifier = definition.TableDefinitions.FirstOrDefault()?.FieldDefinitions?.Where(f => f.IdentifierFieldType.HasValue)?.Select(f => Enum.GetName(typeof(IdentifierFieldType), f.IdentifierFieldType.Value)).FirstOrDefault(),
                ModelHash          = hashCode,
                FundingStreamId    = fundingStream.Id,
                FundingStreamName  = fundingStream.Name
            };

            if (string.IsNullOrWhiteSpace(datasetDefinitionIndex.ProviderIdentifier))
            {
                datasetDefinitionIndex.ProviderIdentifier = "None";
            }

            bool updateIndex = true;

            // Only update index if metadata or model has changed, this is to preserve the LastUpdateDate
            DatasetDefinitionIndex existingIndex = await _datasetDefinitionSearchRepositoryPolicy.ExecuteAsync(() =>
                                                                                                               _datasetDefinitionSearchRepository.SearchById(definition.Id));

            if (existingIndex != null)
            {
                if (existingIndex.ModelHash == hashCode &&
                    existingIndex.Description == definition.Description &&
                    existingIndex.Name == definition.Name &&
                    existingIndex.ProviderIdentifier == datasetDefinitionIndex.ProviderIdentifier)
                {
                    updateIndex = false;
                }
            }

            if (updateIndex)
            {
                return(await _datasetDefinitionSearchRepositoryPolicy.ExecuteAsync(() =>
                                                                                   _datasetDefinitionSearchRepository.Index(new DatasetDefinitionIndex[] { datasetDefinitionIndex })));
            }

            return(Enumerable.Empty <IndexError>());
        }