public async Task MergeSpecificationInformationMergesCreatesNewMissingProviderWithResultsForSpecificationsForSpecificProviderIdsWhenSupplied()
        {
            string jobId      = NewRandomString();
            string providerId = NewRandomString();

            SpecificationInformation             specificationInformation = NewSpecificationInformation();
            MergeSpecificationInformationRequest mergeRequest             = NewMergeSpecificationInformationRequest(_ => _.WithSpecificationInformation(specificationInformation)
                                                                                                                    .WithProviderIds(providerId));

            DateTimeOffset expectedFundingPeriodEndDate = NewRandomDateTime();

            GivenTheFundingPeriodEndDate(specificationInformation.FundingPeriodId, expectedFundingPeriodEndDate);

            Message message = NewMessage(_ => _.WithUserProperty(JobId, jobId)
                                         .WithUserProperty(ProviderId, providerId)
                                         .WithMessageBody(mergeRequest.AsJsonBytes()));

            await WhenTheSpecificationInformationIsMerged(message);

            ThenTheJobTrackingWasStarted(jobId);

            SpecificationInformation expectedSpecificationInformation = specificationInformation.DeepCopy();

            expectedSpecificationInformation.FundingPeriodEnd = expectedFundingPeriodEndDate;

            AndTheProviderWithResultsForSpecificationsWasUpserted(_ => _.Id == providerId &&
                                                                  HasEquivalentSpecificationInformation(_, expectedSpecificationInformation));
            AndTheJobTrackingWasCompleted(jobId);
        }
        public async Task MergeSpecificationInformationMergesForSpecificProviderIdsWhenSupplied()
        {
            string providerOneId = NewRandomString();
            string providerTwoId = NewRandomString();
            string jobId         = NewRandomString();

            string newFundingStreamIdOne = NewRandomString();
            string newFundingStreamIdTwo = NewRandomString();

            SpecificationInformation specificationInformation = NewSpecificationInformation(_ =>
                                                                                            _.WithFundingStreamIds(newFundingStreamIdOne, newFundingStreamIdTwo));
            MergeSpecificationInformationRequest mergeRequest = NewMergeSpecificationInformationRequest(_ => _.WithSpecificationInformation(specificationInformation)
                                                                                                        .WithProviderIds(providerOneId, providerTwoId));

            SpecificationInformation informationWithoutFundingStreams = specificationInformation.DeepCopy();

            informationWithoutFundingStreams.FundingStreamIds = null;

            ProviderWithResultsForSpecifications providerWithResultsForSpecificationsOne = NewProviderWithResultsForSpecifications(_ =>
                                                                                                                                   _.WithSpecifications(informationWithoutFundingStreams));
            ProviderWithResultsForSpecifications providerWithResultsForSpecificationsTwo = NewProviderWithResultsForSpecifications(_ =>
                                                                                                                                   _.WithSpecifications(informationWithoutFundingStreams));

            GivenTheProviderWithResultsForSpecificationsByProviderId(providerWithResultsForSpecificationsOne, providerOneId);
            GivenTheProviderWithResultsForSpecificationsByProviderId(providerWithResultsForSpecificationsTwo, providerTwoId);

            Message message = NewMessage(_ => _.WithUserProperty(JobId, jobId)
                                         .WithMessageBody(mergeRequest.AsJsonBytes()));

            await WhenTheSpecificationInformationIsMerged(message);

            ThenTheJobTrackingWasStarted(jobId);
            AndTheProviderWithResultsForSpecificationsWereUpserted(providerWithResultsForSpecificationsOne);
            AndTheProviderWithResultsForSpecificationsWereUpserted(providerWithResultsForSpecificationsTwo);

            specificationInformation.IsDirty = true;

            providerWithResultsForSpecificationsOne
            .Specifications
            .Should()
            .BeEquivalentTo(specificationInformation);

            providerWithResultsForSpecificationsTwo
            .Specifications
            .Should()
            .BeEquivalentTo(specificationInformation);

            AndTheJobTrackingWasCompleted(jobId);
        }
        public async Task MergeSpecificationInformationMergesForAllProviderWhenProviderIdNotSupplied()
        {
            string jobId           = NewRandomString();
            string specificationId = NewRandomString();

            SpecificationInformation             specificationInformation = NewSpecificationInformation(_ => _.WithId(specificationId));
            MergeSpecificationInformationRequest mergeRequest             = NewMergeSpecificationInformationRequest(_ => _.WithSpecificationInformation(specificationInformation));

            ProviderWithResultsForSpecifications providerOne   = NewProviderWithResultsForSpecifications();
            ProviderWithResultsForSpecifications providerTwo   = NewProviderWithResultsForSpecifications();
            ProviderWithResultsForSpecifications providerThree = NewProviderWithResultsForSpecifications();
            ProviderWithResultsForSpecifications providerFour  = NewProviderWithResultsForSpecifications();
            ProviderWithResultsForSpecifications providerFive  = NewProviderWithResultsForSpecifications();
            ProviderWithResultsForSpecifications providerSix   = NewProviderWithResultsForSpecifications();
            ProviderWithResultsForSpecifications providerSeven = NewProviderWithResultsForSpecifications();
            ProviderResult providerResultEight = NewProviderResult();
            ProviderWithResultsForSpecifications providerEight = NewProviderWithResultsForSpecifications(providerInformation: new ProviderInformation {
                Id = providerResultEight.Provider.Id
            });
            ProviderResult providerResultNine = NewProviderResult();
            ProviderWithResultsForSpecifications providerNine = NewProviderWithResultsForSpecifications(providerInformation: new ProviderInformation {
                Id = providerResultNine.Provider.Id
            });

            DateTimeOffset expectedFundingPeriodEndDate = NewRandomDateTime();

            GivenTheFundingPeriodEndDate(specificationInformation.FundingPeriodId, expectedFundingPeriodEndDate);
            AndTheProviderWithResultsForSpecifications(specificationId,
                                                       NewFeedIterator(AsArray(providerOne, providerTwo),
                                                                       AsArray(providerThree, providerFour),
                                                                       AsArray(providerFive, providerSix),
                                                                       AsArray(providerSeven, providerEight)));

            AndTheProviderResultsForSpecification(specificationId, new[] { providerResultEight, providerResultNine });

            Message message = NewMessage(_ => _.WithUserProperty(JobId, jobId)
                                         .WithMessageBody(mergeRequest.AsJsonBytes()));

            await WhenTheSpecificationInformationIsMerged(message);

            ThenTheJobTrackingWasStarted(jobId);

            SpecificationInformation expectedSpecificationInformation = specificationInformation.DeepCopy();

            expectedSpecificationInformation.FundingPeriodEnd = expectedFundingPeriodEndDate;

            AndTheProviderWithResultsForSpecificationsWereUpserted(providerOne,
                                                                   providerTwo);
            AndTheProviderWithResultsForSpecificationsWereUpserted(providerThree,
                                                                   providerFour);
            AndTheProviderWithResultsForSpecificationsWereUpserted(providerFive,
                                                                   providerSix);
            AndTheProviderWithResultsForSpecificationsWereUpserted(providerSeven,
                                                                   providerEight);

            //only upserts dirty records
            AndTheProviderWithResultsForSpecificationsWereNotUpserted(providerNine);

            expectedSpecificationInformation.IsDirty = true;

            AndTheProviderWithResultsForSpecificationsHaveTheEquivalentSpecificationInformation(expectedSpecificationInformation,
                                                                                                providerOne,
                                                                                                providerTwo,
                                                                                                providerThree,
                                                                                                providerFour,
                                                                                                providerFive,
                                                                                                providerSix,
                                                                                                providerSeven);

            AndTheJobTrackingWasCompleted(jobId);
        }