Esempio n. 1
0
        public ProviderResultsRepository(
            ICosmosRepository cosmosRepository,
            ILogger logger,
            IProviderResultCalculationsHashProvider calculationsHashProvider,
            ICalculatorResiliencePolicies calculatorResiliencePolicies,
            IResultsApiClient resultsApiClient,
            IJobManagement jobManagement)
        {
            Guard.ArgumentNotNull(cosmosRepository, nameof(cosmosRepository));
            Guard.ArgumentNotNull(logger, nameof(logger));
            Guard.ArgumentNotNull(calculationsHashProvider, nameof(calculationsHashProvider));
            Guard.ArgumentNotNull(calculatorResiliencePolicies, nameof(calculatorResiliencePolicies));
            Guard.ArgumentNotNull(resultsApiClient, nameof(resultsApiClient));
            Guard.ArgumentNotNull(calculatorResiliencePolicies.ResultsApiClient, nameof(calculatorResiliencePolicies.ResultsApiClient));
            Guard.ArgumentNotNull(jobManagement, nameof(jobManagement));

            _cosmosRepository = cosmosRepository;
            _logger           = logger;

            _calculationsHashProvider       = calculationsHashProvider;
            _resultsApiClient               = resultsApiClient;
            _resultsApiClientPolicy         = calculatorResiliencePolicies.ResultsApiClient;
            _calculationResultsCosmosPolicy = calculatorResiliencePolicies.CalculationResultsRepository;
            _jobManagement = jobManagement;
        }
        private static IProviderResultCalculationsHashProvider CreateCalcHashProvider()
        {
            IProviderResultCalculationsHashProvider calculationsHashProvider = Substitute.For <IProviderResultCalculationsHashProvider>();

            calculationsHashProvider.TryUpdateCalculationResultHash(Arg.Any <ProviderResult>(), Arg.Any <int>(), Arg.Any <int>())
            .Returns(true);

            return(calculationsHashProvider);
        }
        private ProviderResultsRepository CreateProviderResultsRepository(
            ICosmosRepository cosmosRepository = null,
            ILogger logger = null,
            IProviderResultCalculationsHashProvider calculationsHashProvider = null,
            ICalculatorResiliencePolicies calculatorResiliencePolicies       = null,
            IJobManagement jobManagement = null) =>
        new ProviderResultsRepository(
            cosmosRepository ?? CreateCosmosRepository(),
            logger ?? CreateLogger(),

            calculationsHashProvider ?? CreateCalcHashProvider(),
            calculatorResiliencePolicies ?? CreateCalculatorResiliencePolicies(),
            _resultsApiClient,
            jobManagement ?? CreateJobManagement());
        public async Task SaveProviderResults_WhenExcludedResultsButResultsNotChanged_ThenResultsNotSavedToCosmos()
        {
            // Arrange
            ICosmosRepository cosmosRepository = CreateCosmosRepository();
            IProviderResultCalculationsHashProvider hashProvider = Substitute.For <IProviderResultCalculationsHashProvider>();

            ProviderResultsRepository repo = CreateProviderResultsRepository(cosmosRepository, calculationsHashProvider: hashProvider);

            SpecificationSummary specificationSummary = new SpecificationSummary
            {
                Id            = NewRandomString(),
                Name          = NewRandomString(),
                FundingPeriod = new Reference
                {
                    Id = NewRandomString()
                },
                LastEditedDate = new RandomDateTime()
            };

            IEnumerable <ProviderResult> results = new List <ProviderResult>
            {
                new ProviderResult
                {
                    CalculationResults = new List <CalculationResult>
                    {
                        new CalculationResult
                        {
                            Calculation = new Reference {
                                Id = "calc1", Name = "calculation one"
                            },
                            CalculationType = CalculationType.Template,
                            Value           = null
                        }
                    },
                    Id       = Guid.NewGuid().ToString(),
                    Provider = new ProviderSummary
                    {
                        Id                  = "prov1",
                        Name                = "Provider 1",
                        ProviderType        = "TYpe 1",
                        ProviderSubType     = "Sub type 1",
                        Authority           = "Authority",
                        UKPRN               = "ukprn123",
                        URN                 = "urn123",
                        EstablishmentNumber = "en123",
                        UPIN                = "upin123",
                        DateOpened          = DateTime.Now
                    },
                    SpecificationId = "spec1"
                }
            };

            // Act
            await repo.SaveProviderResults(results, specificationSummary, 1, 1, _user, _correlationId, _jobId);

            // Assert
            await cosmosRepository.Received(0).BulkUpsertAsync(Arg.Is <IEnumerable <KeyValuePair <string, ProviderResult> > >(r => r.Count() == 1),
                                                               Arg.Any <int>(),
                                                               Arg.Any <bool>(),
                                                               Arg.Is <bool>(false));
        }
        public void RegisterComponents(IServiceCollection builder)
        {
            builder.AddScoped <ICalculationEngineService, CalculationEngineService>();
            builder.AddScoped <ICalculationEngine, CalculationEngine>();
            builder.AddScoped <IAllocationFactory, AllocationFactory>();
            builder.AddScoped <IJobManagement, JobManagement>();
            builder.AddSingleton <IProviderSourceDatasetVersionKeyProvider, ProviderSourceDatasetVersionKeyProvider>();
            builder.AddSingleton <IFileSystemAccess, FileSystemAccess>();

            builder.AddSingleton <IAssemblyService, AssemblyService>();
            builder.AddSingleton <ICalculationAggregationService, CalculationAggregationService>();
            builder.AddScoped <ICalculationEnginePreviewService, CalculationEnginePreviewService>();

            builder.AddSingleton <IFileSystemCacheSettings, FileSystemCacheSettings>();
            builder.AddSingleton <IFileSystemCache, FileSystemCache>();

            builder.AddSingleton <IProviderSourceDatasetsRepository, ProviderSourceDatasetsRepository>((ctx) =>
            {
                CosmosDbSettings providerSourceDatasetsCosmosSettings = new CosmosDbSettings();

                Configuration.Bind("CosmosDbSettings", providerSourceDatasetsCosmosSettings);

                providerSourceDatasetsCosmosSettings.ContainerName = "providerdatasets";

                CosmosRepository calcsCosmosRepository = new CosmosRepository(providerSourceDatasetsCosmosSettings, new CosmosClientOptions()
                {
                    ConnectionMode = ConnectionMode.Direct,
                    RequestTimeout = new TimeSpan(0, 0, 15),
                    MaxRequestsPerTcpConnection  = 8,
                    MaxTcpConnectionsPerEndpoint = 4,
                    ConsistencyLevel             = ConsistencyLevel.Eventual,
                    AllowBulkExecution           = true,
                });

                ICalculatorResiliencePolicies calculatorResiliencePolicies = ctx.GetService <ICalculatorResiliencePolicies>();

                return(new ProviderSourceDatasetsRepository(calcsCosmosRepository, calculatorResiliencePolicies));
            });

            builder.AddSingleton <IProviderResultCalculationsHashProvider, ProviderResultCalculationsHashProvider>();

            builder.AddSingleton <IProviderResultsRepository, ProviderResultsRepository>((ctx) =>
            {
                CosmosDbSettings calcResultsDbSettings = new CosmosDbSettings();

                Configuration.Bind("CosmosDbSettings", calcResultsDbSettings);

                calcResultsDbSettings.ContainerName = "calculationresults";

                CosmosRepository calcsCosmosRepostory = new CosmosRepository(calcResultsDbSettings, new CosmosClientOptions()
                {
                    ConnectionMode = ConnectionMode.Direct,
                    RequestTimeout = new TimeSpan(0, 0, 15),
                    MaxRequestsPerTcpConnection  = 8,
                    MaxTcpConnectionsPerEndpoint = 2,
                    // MaxRetryWaitTimeOnRateLimitedRequests = new TimeSpan(0, 0, 30),
                    AllowBulkExecution = true,
                });

                ILogger logger = ctx.GetService <ILogger>();

                IProviderResultCalculationsHashProvider calculationsHashProvider = ctx.GetService <IProviderResultCalculationsHashProvider>();

                ICalculatorResiliencePolicies calculatorResiliencePolicies = ctx.GetService <ICalculatorResiliencePolicies>();

                IResultsApiClient resultsApiClient = ctx.GetService <IResultsApiClient>();

                IJobManagement jobManagement = ctx.GetService <IJobManagement>();

                return(new ProviderResultsRepository(
                           calcsCosmosRepostory,
                           logger,
                           calculationsHashProvider,
                           calculatorResiliencePolicies,
                           resultsApiClient,
                           jobManagement));
            });

            builder
            .AddSingleton <IBlobContainerRepository, BlobContainerRepository>();

            builder
            .AddSingleton <ICalculationsRepository, CalculationsRepository>();

            builder
            .AddSingleton <IDatasetAggregationsRepository, DatasetAggregationsRepository>();

            builder
            .AddSingleton <ICancellationTokenProvider, InactiveCancellationTokenProvider>();

            MapperConfiguration calculationsConfig = new MapperConfiguration(c =>
            {
                c.AddProfile <CalculationsMappingProfile>();
                c.AddProfile <CalcEngineMappingProfile>();
            });

            builder
            .AddSingleton(calculationsConfig.CreateMapper());

            builder.AddSingleton <IUserProfileProvider, UserProfileProvider>();

            builder.AddCalculationsInterServiceClient(Configuration, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddSpecificationsInterServiceClient(Configuration, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddJobsInterServiceClient(Configuration, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddPoliciesInterServiceClient(Configuration, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddResultsInterServiceClient(Configuration, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddDatasetsInterServiceClient(Configuration, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddProvidersInterServiceClient(Configuration, handlerLifetime: Timeout.InfiniteTimeSpan);

            builder.AddEngineSettings(Configuration);

            builder.AddServiceBus(Configuration, "calcengine");

            builder.AddCaching(Configuration);

            builder.AddApplicationInsightsTelemetry();
            builder.AddApplicationInsightsTelemetryClient(Configuration, "CalculateFunding.Api.CalcEngine");
            builder.AddApplicationInsightsServiceName(Configuration, "CalculateFunding.Api.CalcEngine");

            builder.AddLogging("CalculateFunding.Api.CalcEngine");

            builder.AddTelemetry();

            builder.AddSearch(Configuration);
            builder
            .AddSingleton <ISearchRepository <ProviderCalculationResultsIndex>, SearchRepository <ProviderCalculationResultsIndex> >();

            builder.AddFeatureToggling(Configuration);

            PolicySettings policySettings = ServiceCollectionExtensions.GetPolicySettings(Configuration);
            CalculatorResiliencePolicies calcResiliencePolicies = CreateResiliencePolicies(policySettings);

            builder.AddSingleton <ICalculatorResiliencePolicies>(calcResiliencePolicies);
            builder.AddSingleton <IJobManagementResiliencePolicies>((ctx) => new JobManagementResiliencePolicies()
            {
                JobsApiClient = calcResiliencePolicies.JobsApiClient
            });

            builder.AddSingleton <IValidator <ICalculatorResiliencePolicies>, CalculatorResiliencePoliciesValidator>();
            builder.AddSingleton <ICalculationEngineServiceValidator, CalculationEngineServiceValidator>();
            builder.AddSingleton <ISpecificationAssemblyProvider, SpecificationAssemblyProvider>();
            builder.AddSingleton <IBlobClient>(ctx =>
            {
                BlobStorageOptions options = new BlobStorageOptions();

                Configuration.Bind("AzureStorageSettings", options);

                options.ContainerName = "source";

                IBlobContainerRepository blobContainerRepository = new BlobContainerRepository(options);
                return(new BlobClient(blobContainerRepository));
            });

            builder.AddApiKeyMiddlewareSettings((IConfigurationRoot)Configuration);

            builder.AddHttpContextAccessor();

            builder.AddHealthCheckMiddleware();

            if (Configuration.IsSwaggerEnabled())
            {
                builder.ConfigureSwaggerServices(title: "CalcEngine Microservice API", version: "v1");
            }
        }
        private static IServiceProvider Register(IServiceCollection builder, IConfigurationRoot config)
        {
            builder.AddSingleton <IUserProfileProvider, UserProfileProvider>();


            builder.AddSingleton <IConfiguration>(config);
            builder.AddCaching(config);

            // These registrations of the functions themselves are just for the DebugQueue. Ideally we don't want these registered in production
            if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
            {
                builder.AddScoped <OnCalcsGenerateAllocationResults>();
                builder.AddScoped <OnCalculationGenerateFailure>();
            }

            builder.AddScoped <ICalculationEngineService, CalculationEngineService>();
            builder.AddScoped <ICalculationEngine, CalculationEngine>();
            builder.AddScoped <IAllocationFactory, AllocationFactory>();
            builder.AddScoped <IDeadletterService, DeadletterService>();
            builder.AddScoped <IJobManagement, JobManagement>();
            builder.AddSingleton <IProviderSourceDatasetVersionKeyProvider, ProviderSourceDatasetVersionKeyProvider>();
            builder.AddSingleton <IFileSystemAccess, FileSystemAccess>();

            builder.AddSingleton <IAssemblyService, AssemblyService>();
            builder.AddSingleton <ICalculationAggregationService, CalculationAggregationService>();
            builder.AddScoped <ICalculationEnginePreviewService, CalculationEnginePreviewService>();

            builder.AddSingleton <IFileSystemCacheSettings, FileSystemCacheSettings>();
            builder.AddSingleton <IFileSystemCache, FileSystemCache>();

            builder.AddSingleton <IProviderSourceDatasetsRepository, ProviderSourceDatasetsRepository>((ctx) =>
            {
                CosmosDbSettings providerSourceDatasetsCosmosSettings = new CosmosDbSettings();

                config.Bind("CosmosDbSettings", providerSourceDatasetsCosmosSettings);

                providerSourceDatasetsCosmosSettings.ContainerName = "providerdatasets";

                CosmosRepository calcsCosmosRepository = new CosmosRepository(providerSourceDatasetsCosmosSettings, new CosmosClientOptions()
                {
                    ConnectionMode = ConnectionMode.Direct,
                    RequestTimeout = new TimeSpan(0, 0, 15),
                    MaxRequestsPerTcpConnection  = 8,
                    MaxTcpConnectionsPerEndpoint = 4,
                    ConsistencyLevel             = ConsistencyLevel.Eventual,
                    AllowBulkExecution           = true,
                    // MaxRetryAttemptsOnRateLimitedRequests = 1,
                    // MaxRetryWaitTimeOnRateLimitedRequests = new TimeSpan(0, 0, 30),
                });

                ICalculatorResiliencePolicies calculatorResiliencePolicies = ctx.GetService <ICalculatorResiliencePolicies>();

                return(new ProviderSourceDatasetsRepository(calcsCosmosRepository, calculatorResiliencePolicies));
            });

            builder.AddSingleton <IProviderResultCalculationsHashProvider, ProviderResultCalculationsHashProvider>();

            builder.AddSingleton <IProviderResultsRepository, ProviderResultsRepository>((ctx) =>
            {
                CosmosDbSettings calcResultsDbSettings = new CosmosDbSettings();

                config.Bind("CosmosDbSettings", calcResultsDbSettings);

                calcResultsDbSettings.ContainerName = "calculationresults";

                CosmosRepository calcsCosmosRepostory = new CosmosRepository(calcResultsDbSettings, new CosmosClientOptions()
                {
                    ConnectionMode = ConnectionMode.Direct,
                    RequestTimeout = new TimeSpan(0, 0, 15),
                    MaxRequestsPerTcpConnection  = 8,
                    MaxTcpConnectionsPerEndpoint = 2,
                    // MaxRetryWaitTimeOnRateLimitedRequests = new TimeSpan(0, 0, 30),
                    AllowBulkExecution = true,
                });

                ILogger logger = ctx.GetService <ILogger>();

                IProviderResultCalculationsHashProvider calculationsHashProvider = ctx.GetService <IProviderResultCalculationsHashProvider>();

                ICalculatorResiliencePolicies calculatorResiliencePolicies = ctx.GetService <ICalculatorResiliencePolicies>();

                IResultsApiClient resultsApiClient = ctx.GetService <IResultsApiClient>();

                IJobManagement jobManagement = ctx.GetService <IJobManagement>();

                return(new ProviderResultsRepository(
                           calcsCosmosRepostory,
                           logger,
                           calculationsHashProvider,
                           calculatorResiliencePolicies,
                           resultsApiClient,
                           jobManagement));
            });

            builder.AddSingleton <ISourceFileRepository, SourceFileRepository>((ctx) =>
            {
                BlobStorageOptions blobStorageOptions = new BlobStorageOptions();

                config.Bind("AzureStorageSettings", blobStorageOptions);

                blobStorageOptions.ContainerName = "source";

                IBlobContainerRepository blobContainerRepository = new BlobContainerRepository(blobStorageOptions);
                return(new SourceFileRepository(blobContainerRepository));
            });

            builder
            .AddSingleton <Services.CalcEngine.Interfaces.ICalculationsRepository, Services.CalcEngine.CalculationsRepository>();

            builder
            .AddSingleton <IDatasetAggregationsRepository, DatasetAggregationsRepository>();

            builder
            .AddSingleton <ICancellationTokenProvider, InactiveCancellationTokenProvider>();

            builder
            .AddSingleton <ISourceCodeService, SourceCodeService>();

            MapperConfiguration calculationsConfig = new MapperConfiguration(c =>
            {
                c.AddProfile <CalculationsMappingProfile>();
                c.AddProfile <CalcEngineMappingProfile>();
            });

            builder
            .AddSingleton(calculationsConfig.CreateMapper());

            builder.AddScoped <IUserProfileProvider, UserProfileProvider>();

            builder.AddCalculationsInterServiceClient(config, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddSpecificationsInterServiceClient(config, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddJobsInterServiceClient(config, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddPoliciesInterServiceClient(config, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddResultsInterServiceClient(config, handlerLifetime: Timeout.InfiniteTimeSpan);
            builder.AddDatasetsInterServiceClient(config, handlerLifetime: Timeout.InfiniteTimeSpan);

            builder.AddEngineSettings(config);

            builder.AddServiceBus(config, "calcengine");

            builder.AddCaching(config);

            builder.AddApplicationInsightsTelemetryClient(config, "CalculateFunding.Functions.CalcEngine");
            builder.AddApplicationInsightsServiceName(config, "CalculateFunding.Functions.CalcEngine");

            builder.AddLogging("CalculateFunding.Functions.CalcEngine", config);

            builder.AddTelemetry();

            builder.AddSearch(config);
            builder
            .AddSingleton <ISearchRepository <ProviderCalculationResultsIndex>, SearchRepository <ProviderCalculationResultsIndex> >();

            builder.AddFeatureToggling(config);

            PolicySettings policySettings = ServiceCollectionExtensions.GetPolicySettings(config);
            CalculatorResiliencePolicies calcResiliencePolicies = CreateResiliencePolicies(policySettings);

            builder.AddSingleton <ICalculatorResiliencePolicies>(calcResiliencePolicies);
            builder.AddSingleton <IJobManagementResiliencePolicies>((ctx) => new JobManagementResiliencePolicies()
            {
                JobsApiClient = calcResiliencePolicies.JobsApiClient
            });

            builder.AddSingleton <IValidator <ICalculatorResiliencePolicies>, CalculatorResiliencePoliciesValidator>();
            builder.AddSingleton <ICalculationEngineServiceValidator, CalculationEngineServiceValidator>();
            builder.AddSingleton <ISpecificationAssemblyProvider, SpecificationAssemblyProvider>();
            builder.AddSingleton <IBlobClient>(ctx =>
            {
                BlobStorageOptions options = new BlobStorageOptions();

                config.Bind("AzureStorageSettings", options);

                options.ContainerName = "source";

                IBlobContainerRepository blobContainerRepository = new BlobContainerRepository(options);
                return(new BlobClient(blobContainerRepository));
            });

            ServicePointManager.DefaultConnectionLimit = 200;

            return(builder.BuildServiceProvider());
        }