Example #1
0
        public async Task IsCalculationNameValid_WhenCalculationDoesNotExist_ThenReturnsOkResult()
        {
            // Arrange
            string specificationId = "spec1";

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(specificationId))
            .Returns(new SpecificationSummary {
                Id = specificationId
            });

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

            calculationsRepository
            .GetCalculationsBySpecificationId(Arg.Is(specificationId))
            .Returns(new List <Models.Calcs.Calculation>());

            CalculationService service = CreateCalculationService(specificationRepository: specificationRepository, calculationsRepository: calculationsRepository);

            // Act
            IActionResult result = await service.IsCalculationNameValid(specificationId, "calc1", null);

            // Assert
            result
            .Should()
            .BeOfType <OkResult>();
        }
        public void CreateCalculation_CreatingCalculationButAssociatedCalculationSpecificationNotFound_ThrowsException()
        {
            //Arrange
            Calculation calculation = CreateCalculation();

            IEnumerable <Calculation> calculations = new[]
            {
                calculation
            };
            string json = JsonConvert.SerializeObject(calculation);

            IEnumerable <Models.Specs.Calculation> calculationSpecifications = new[]
            {
                new Models.Specs.Calculation
                {
                    Id = "any-id"
                }
            };

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties.Add("user-id", UserId);
            message.UserProperties.Add("user-name", Username);

            ILogger logger = CreateLogger();

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary()
            {
                Id   = calculation.SpecificationId,
                Name = "Test Spec Name",
            };

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId))
            .Returns(specificationSummary);

            specificationRepository
            .GetCalculationSpecificationsForSpecification(Arg.Is(calculation.SpecificationId))
            .Returns(calculationSpecifications);

            CalculationService service = CreateCalculationService(logger: logger, searchRepository: searchRepository, specificationRepository: specificationRepository);

            //Act
            Func <Task> test = async() => await service.CreateCalculation(message);

            //Assert
            test
            .Should().ThrowExactly <RetriableException>()
            .WithMessage($"A calculation specification was not found for calculation specification id '{calculation.CalculationSpecification.Id}'");
        }
Example #3
0
        public async Task GetEffectivePermissionsForUser_WhenNotFoundInCacheButSpecificationNotFound_ThenPreconditionFailedResultReturned()
        {
            // Arrange
            ICacheProvider cacheProvider = CreateCacheProvider();
            EffectiveSpecificationPermission cachedPermission = null;

            cacheProvider
            .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId))
            .Returns(cachedPermission);

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            SpecificationSummary specificationSummary = null;

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(SpecificationId))
            .Returns(specificationSummary);

            FundingStreamPermissionService service = CreateService(
                specificationRepository: specificationRepository,
                cacheProvider: cacheProvider);


            // Act
            IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId, null);

            // Assert
            result
            .Should()
            .BeOfType <PreconditionFailedResult>()
            .Which
            .Value
            .Should()
            .Be("Specification not found");

            await cacheProvider
            .Received(1)
            .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId));

            await cacheProvider
            .Received(0)
            .SetHashValue(
                Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"),
                Arg.Is(SpecificationId),
                Arg.Any <EffectiveSpecificationPermission>());
        }
Example #4
0
        public async Task IsCalculationNameValid_WhenSameCalculation_ThenReturnsOkResult()
        {
            // Arrange
            string specificationId = "spec1";
            string calcName        = "calc1";
            string calcSpecId      = "calc-spec-id-1";

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(specificationId))
            .Returns(new SpecificationSummary {
                Id = specificationId
            });

            List <Models.Calcs.Calculation> existingCalcs = new List <Models.Calcs.Calculation>
            {
                new Models.Calcs.Calculation
                {
                    Name                     = calcName,
                    SourceCodeName           = calcName,
                    Id                       = "calc-1",
                    CalculationSpecification = new Common.Models.Reference {
                        Id = calcSpecId
                    }
                }
            };

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

            calculationsRepository
            .GetCalculationsBySpecificationId(Arg.Is(specificationId))
            .Returns(existingCalcs);

            CalculationService service = CreateCalculationService(specificationRepository: specificationRepository, calculationsRepository: calculationsRepository);

            // Act
            IActionResult result = await service.IsCalculationNameValid(specificationId, calcName, calcSpecId);

            // Assert
            result
            .Should()
            .BeOfType <OkResult>();
        }
Example #5
0
        public async Task IsCalculationNameValid_WhenSpecificationDoesNotExist_ThenReturnsNotFoundResult()
        {
            // Arrange
            string specificationId = "spec1";

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(specificationId))
            .Returns((SpecificationSummary)null);

            CalculationService service = CreateCalculationService(specificationRepository: specificationRepository);

            // Act
            IActionResult result = await service.IsCalculationNameValid(specificationId, "calc1", null);

            // Assert
            result
            .Should()
            .BeOfType <NotFoundResult>();
        }
        public async Task EditCalculationStatus_GivenNewStatusOfUpdated_UpdatesSearchReturnsOK()
        {
            //Arrange
            EditStatusModel CalculationEditStatusModel = new EditStatusModel
            {
                PublishStatus = PublishStatus.Updated
            };

            string json = JsonConvert.SerializeObject(CalculationEditStatusModel);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpContext context = Substitute.For <HttpContext>();

            HttpRequest request = Substitute.For <HttpRequest>();

            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "calculationId", new StringValues(CalculationId) },
            });

            request
            .Query
            .Returns(queryStringValues);
            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            ILogger logger = CreateLogger();

            Calculation calculation = CreateCalculation();

            calculation.Current.PublishStatus = PublishStatus.Approved;

            CalculationVersion calculationVersion = calculation.Current.Clone() as CalculationVersion;

            calculationVersion.PublishStatus = PublishStatus.Updated;

            ICalculationsRepository CalculationsRepository = CreateCalculationsRepository();

            CalculationsRepository
            .GetCalculationById(Arg.Is(CalculationId))
            .Returns(calculation);

            CalculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);


            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary();

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId))
            .Returns(specificationSummary);

            IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository();

            versionRepository
            .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>())
            .Returns(calculationVersion);

            Build build = new Build
            {
                SourceFiles = new List <SourceFile> {
                    new SourceFile()
                }
            };

            BuildProject buildProject = new BuildProject();

            IBuildProjectsService buildProjectsService = CreateBuildProjectsService();

            buildProjectsService
            .GetBuildProjectForSpecificationId(Arg.Is(calculation.SpecificationId))
            .Returns(buildProject);

            ISourceCodeService sourceCodeService = CreateSourceCodeService();

            sourceCodeService
            .Compile(Arg.Any <BuildProject>(), Arg.Any <IEnumerable <Models.Calcs.Calculation> >(), Arg.Any <CompilerOptions>())
            .Returns(build);

            CalculationService service = CreateCalculationService(
                logger: logger, calculationsRepository: CalculationsRepository, searchRepository: searchRepository,
                specificationRepository: specificationRepository, calculationVersionRepository: versionRepository,
                sourceCodeService: sourceCodeService, buildProjectsService: buildProjectsService);

            //Act
            IActionResult result = await service.UpdateCalculationStatus(request);

            //Arrange
            result
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should()
            .BeOfType <PublishStatusResultModel>()
            .Which
            .PublishStatus
            .Should()
            .Be(PublishStatus.Updated);

            calculation
            .Current
            .PublishStatus
            .Should()
            .Be(PublishStatus.Updated);

            await
            searchRepository
            .Received(1)
            .Index(Arg.Is <IEnumerable <CalculationIndex> >(m => m.First().Status == "Updated"));
        }
        public async Task EditCalculationStatus_GivenCalculationIsApprovedButNewStatusIsDraft_UpdatesSearchReturnsOK()
        {
            //Arrange
            EditStatusModel CalculationEditStatusModel = new EditStatusModel
            {
                PublishStatus = PublishStatus.Draft
            };

            string json = JsonConvert.SerializeObject(CalculationEditStatusModel);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpContext context = Substitute.For <HttpContext>();

            HttpRequest request = Substitute.For <HttpRequest>();

            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "calculationId", new StringValues(CalculationId) },
            });

            request
            .Query
            .Returns(queryStringValues);
            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            ILogger logger = CreateLogger();

            Calculation calculation = CreateCalculation();

            calculation.Current.PublishStatus = PublishStatus.Approved;

            ICalculationsRepository CalculationsRepository = CreateCalculationsRepository();

            CalculationsRepository
            .GetCalculationById(Arg.Is(CalculationId))
            .Returns(calculation);

            CalculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);


            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary();

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId))
            .Returns(specificationSummary);

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            CalculationService service = CreateCalculationService(
                logger: logger, calculationsRepository: CalculationsRepository, searchRepository: searchRepository, specificationRepository: specificationRepository);

            //Act
            IActionResult result = await service.UpdateCalculationStatus(request);

            //Arrange
            result
            .Should()
            .BeOfType <BadRequestObjectResult>()
            .Which
            .Value
            .Should()
            .Be("Publish status can't be changed to Draft from Updated or Approved");

            calculation
            .Current
            .PublishStatus
            .Should()
            .Be(PublishStatus.Approved);

            await
            searchRepository
            .Received(0)
            .Index(Arg.Any <IEnumerable <CalculationIndex> >());
        }
        public async Task EditCalculationStatus_GivenNewStatusButUpdatingDbReturnsBadRequest_ReturnsStatusCode400()
        {
            //Arrange
            EditStatusModel CalculationEditStatusModel = new EditStatusModel
            {
                PublishStatus = PublishStatus.Approved
            };

            string json = JsonConvert.SerializeObject(CalculationEditStatusModel);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpContext context = Substitute.For <HttpContext>();

            HttpRequest request = Substitute.For <HttpRequest>();

            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "calculationId", new StringValues(CalculationId) },
            });

            request
            .Query
            .Returns(queryStringValues);
            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            ILogger logger = CreateLogger();

            Calculation calculation = CreateCalculation();

            ICalculationsRepository CalculationsRepository = CreateCalculationsRepository();

            CalculationsRepository
            .GetCalculationById(Arg.Is(CalculationId))
            .Returns(calculation);

            CalculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.BadRequest);

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary();

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId))
            .Returns(specificationSummary);

            CalculationService service = CreateCalculationService(
                logger: logger, calculationsRepository: CalculationsRepository, specificationRepository: specificationRepository);

            //Act
            IActionResult result = await service.UpdateCalculationStatus(request);

            //Arrange
            result
            .Should()
            .BeAssignableTo <StatusCodeResult>()
            .Which
            .StatusCode
            .Should()
            .Be(400);
        }
        public async Task ResetCalculationForFieldDefinitionChanges_GivenCalculationRequiresReset_UpdatesCalculationsAndDeletesAssembly()
        {
            //Arrange
            const string specificationId = "spec-id";

            IEnumerable <DatasetSpecificationRelationshipViewModel> relationships = new[]
            {
                new DatasetSpecificationRelationshipViewModel
                {
                    Name = "Test Name"
                }
            };

            IEnumerable <string> currentFieldDefinitionNames = new[]
            {
                "Test Field"
            };

            ILogger logger = CreateLogger();

            CalculationVersion calculationVersion = new CalculationVersion
            {
                SourceCode = "return Datasets.TestName.TestField",
                Date       = DateTimeOffset.Now
            };

            IEnumerable <Calculation> calculations = new[]
            {
                new Calculation
                {
                    Current                  = calculationVersion,
                    SpecificationId          = specificationId,
                    CalculationSpecification = new Reference("calc-spac-id", "calc spec name"),
                    FundingPeriod            = new Reference("fp1", "fp 1"),
                    FundingStream            = new Reference("fs1", "fs 1"),
                    Policies                 = new List <Reference> {
                        new Reference {
                            Id = "policy-1", Name = "policy 1"
                        }
                    }
                }
            };

            IEnumerable <Models.Specs.Calculation> calculationSpecifications = new[]
            {
                new Models.Specs.Calculation
                {
                    Id = "calc-spec-id"
                }
            };

            BuildProject buildProject = new BuildProject();

            Build build = new Build
            {
                SourceFiles = new List <SourceFile>()
            };

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary();

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

            calculationsRepository
            .GetCalculationsBySpecificationId(Arg.Is(specificationId))
            .Returns(calculations);
            calculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetCalculationSpecificationsForSpecification(Arg.Is(specificationId))
            .Returns(calculationSpecifications);

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(specificationId))
            .Returns(specificationSummary);

            IBuildProjectsService buildProjectsService = CreateBuildProjectsService();

            buildProjectsService
            .GetBuildProjectForSpecificationId(Arg.Is(specificationId))
            .Returns(buildProject);

            ISourceCodeService sourceCodeService = CreateSourceCodeService();

            sourceCodeService
            .Compile(Arg.Is(buildProject), Arg.Any <IEnumerable <Calculation> >(), Arg.Any <CompilerOptions>())
            .Returns(build);

            IVersionRepository <CalculationVersion> calculationVersionRepository = CreateCalculationVersionRepository();

            calculationVersionRepository
            .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>())
            .Returns(calculationVersion);

            ICacheProvider cacheProvider = CreateCacheProvider();

            CalculationService calculationService = CreateCalculationService(
                logger: logger,
                calculationsRepository: calculationsRepository,
                specificationRepository: specificationRepository,
                buildProjectsService: buildProjectsService,
                sourceCodeService: sourceCodeService,
                calculationVersionRepository: calculationVersionRepository,
                cacheProvider: cacheProvider);

            //Act
            await calculationService.ResetCalculationForFieldDefinitionChanges(relationships, specificationId, currentFieldDefinitionNames);

            //Assert
            await
            sourceCodeService
            .Received(1)
            .DeleteAssembly(Arg.Is(specificationId));

            await
            cacheProvider
            .Received(1)
            .RemoveAsync <List <DatasetSchemaRelationshipModel> >(Arg.Is($"{CacheKeys.DatasetRelationshipFieldsForSpecification}{specificationId}"));
        }
        public async Task CreateCalculation_GivenValidCalculation_ButFailedToSave_DoesNotUpdateSearch()
        {
            //Arrange
            Calculation calculation = CreateCalculation();

            IEnumerable <Calculation> calculations = new[]
            {
                calculation
            };

            IEnumerable <Models.Specs.Calculation> calculationSpecifications = new[]
            {
                new Models.Specs.Calculation
                {
                    Id = calculation.CalculationSpecification.Id
                }
            };

            string json = JsonConvert.SerializeObject(calculation);

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties.Add("user-id", UserId);
            message.UserProperties.Add("user-name", Username);

            ICalculationsRepository repository = CreateCalculationsRepository();

            repository
            .CreateDraftCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.BadRequest);

            repository
            .GetCalculationsBySpecificationId(Arg.Is("any-spec-id"))
            .Returns(calculations);

            ILogger logger = CreateLogger();

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary()
            {
                Id   = calculation.SpecificationId,
                Name = "Test Spec Name",
            };

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId))
            .Returns(specificationSummary);

            specificationRepository
            .GetCalculationSpecificationsForSpecification(Arg.Is(calculation.SpecificationId))
            .Returns(calculationSpecifications);

            CalculationService service = CreateCalculationService(calculationsRepository: repository, logger: logger, searchRepository: searchRepository, specificationRepository: specificationRepository);

            //Act
            await service.CreateCalculation(message);

            //Assert
            logger
            .Received(1)
            .Error($"There was problem creating a new calculation with id {calculation.Id} in Cosmos Db with status code 400");

            await
            repository
            .Received(1)
            .CreateDraftCalculation(Arg.Is <Calculation>(m =>
                                                         m.Id == CalculationId &&
                                                         m.Current.PublishStatus == PublishStatus.Draft &&
                                                         m.Current.Author.Id == UserId &&
                                                         m.Current.Author.Name == Username &&
                                                         m.Current.Date.Date == DateTimeOffset.Now.Date &&
                                                         m.Current.Version == 1 &&
                                                         m.Current.DecimalPlaces == 6
                                                         ));

            await
            searchRepository
            .DidNotReceive()
            .Index(Arg.Any <List <CalculationIndex> >());
        }
        public async Task CreateCalculation_GivenValidCalculationWithNullFundingStream_AndSavesLogs()
        {
            //Arrange
            Calculation calculation = CreateCalculation();

            calculation.FundingStream = null;

            IEnumerable <Calculation> calculations = new[]
            {
                calculation
            };

            IEnumerable <Models.Specs.Calculation> calculationSpecifications = new[]
            {
                new Models.Specs.Calculation
                {
                    Id = calculation.CalculationSpecification.Id
                }
            };

            string json = JsonConvert.SerializeObject(calculation);

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties.Add("user-id", UserId);
            message.UserProperties.Add("user-name", Username);

            ICalculationsRepository repository = CreateCalculationsRepository();

            repository
            .CreateDraftCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.Created);

            repository
            .GetCalculationsBySpecificationId(Arg.Is("any-spec-id"))
            .Returns(calculations);

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary()
            {
                Id   = calculation.SpecificationId,
                Name = "Test Spec Name",
            };

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId))
            .Returns(specificationSummary);

            specificationRepository
            .GetCalculationSpecificationsForSpecification(Arg.Is(calculation.SpecificationId))
            .Returns(calculationSpecifications);

            ILogger logger = CreateLogger();

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            Build build = new Build
            {
                SourceFiles = new List <SourceFile> {
                    new SourceFile()
                }
            };

            ISourceCodeService sourceCodeService = CreateSourceCodeService();

            sourceCodeService
            .Compile(Arg.Any <BuildProject>(), Arg.Any <IEnumerable <Models.Calcs.Calculation> >(), Arg.Any <CompilerOptions>())
            .Returns(build);

            CalculationService service = CreateCalculationService(
                calculationsRepository: repository,
                logger: logger, searchRepository:
                searchRepository,
                specificationRepository: specificationRepository,
                sourceCodeService: sourceCodeService);

            //Act
            await service.CreateCalculation(message);

            //Assert
            logger
            .Received(1)
            .Information($"Calculation with id: {calculation.Id} was successfully saved to Cosmos Db");

            await
            repository
            .Received(1)
            .CreateDraftCalculation(Arg.Is <Calculation>(m =>
                                                         m.Id == CalculationId &&
                                                         m.Current.PublishStatus == PublishStatus.Draft &&
                                                         m.Current.Author.Id == UserId &&
                                                         m.Current.Author.Name == Username &&
                                                         m.Current.Date.Date == DateTimeOffset.Now.Date &&
                                                         m.Current.Version == 1 &&
                                                         m.Current.DecimalPlaces == 6
                                                         ));

            await
            searchRepository
            .Received(1)
            .Index(Arg.Is <List <CalculationIndex> >(
                       m => m.First().Id == CalculationId &&
                       m.First().Name == "Test Calc Name" &&
                       m.First().CalculationSpecificationId == "any-calc-id" &&
                       m.First().CalculationSpecificationName == "Test Calc Name" &&
                       m.First().SpecificationId == "any-spec-id" &&
                       m.First().SpecificationName == "Test Spec Name" &&
                       m.First().FundingPeriodId == "18/19" &&
                       m.First().FundingPeriodName == "2018/2019" &&
                       m.First().FundingStreamId == string.Empty &&
                       m.First().FundingStreamName == "No funding stream set" &&
                       m.First().AllocationLineId == "test-alloc-id" &&
                       m.First().AllocationLineName == "test-alloc-name" &&
                       m.First().PolicySpecificationIds.First() == "policy-id" &&
                       m.First().PolicySpecificationNames.First() == "policy-name"
                       ));
        }
Example #12
0
        public async Task GetEffectivePermissionsForUser_WhenNotFoundInCacheResultsAreQueriedWithMultipleFundingStreamAndNoPermissionsAreInRepository_ThenOkResultReturnedWithNoPermissions()
        {
            // Arrange
            IUserRepository          userRepository          = CreateUserRepository();
            ISpecificationRepository specificationRepository = CreateSpecificationRepository();
            ICacheProvider           cacheProvider           = CreateCacheProvider();
            IMapper mapper = CreateMappingConfiguration();

            EffectiveSpecificationPermission cachedPermission = null;

            cacheProvider
            .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId))
            .Returns(cachedPermission);

            SpecificationSummary specificationSummary = new SpecificationSummary()
            {
                Id             = SpecificationId,
                FundingStreams = new List <Reference>()
                {
                    new Reference("fs1", "Funding Stream 1"),
                    new Reference("fs2", "Funding Stream 2")
                }
            };

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(SpecificationId))
            .Returns(specificationSummary);

            FundingStreamPermission fs1Permission = null;

            userRepository
            .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs1"))
            .Returns(fs1Permission);

            FundingStreamPermission fs2Permission = null;

            userRepository
            .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs2"))
            .Returns(fs2Permission);

            FundingStreamPermissionService service = CreateService(userRepository, specificationRepository, cacheProvider: cacheProvider, mapper: mapper);


            // Act
            IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId, null);

            // Assert
            result
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should()
            .BeEquivalentTo(new EffectiveSpecificationPermission()
            {
                UserId                     = UserId,
                SpecificationId            = SpecificationId,
                CanApproveFunding          = false,
                CanCreateSpecification     = false,
                CanMapDatasets             = false,
                CanChooseFunding           = false,
                CanEditCalculations        = false,
                CanEditSpecification       = false,
                CanPublishFunding          = false,
                CanAdministerFundingStream = false,
                CanApproveSpecification    = false,
                CanCreateQaTests           = false,
                CanEditQaTests             = false,
                CanRefreshFunding          = false,
            });

            await cacheProvider
            .Received(1)
            .SetHashValue(
                Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"),
                Arg.Is(SpecificationId),
                Arg.Is <EffectiveSpecificationPermission>(p =>
                                                          !p.CanApproveFunding &&
                                                          !p.CanChooseFunding &&
                                                          !p.CanCreateSpecification &&
                                                          !p.CanEditCalculations &&
                                                          !p.CanEditSpecification &&
                                                          !p.CanMapDatasets &&
                                                          !p.CanPublishFunding &&
                                                          !p.CanAdministerFundingStream &&
                                                          !p.CanApproveSpecification &&
                                                          !p.CanCreateQaTests &&
                                                          !p.CanEditQaTests &&
                                                          !p.CanRefreshFunding &&
                                                          p.SpecificationId == SpecificationId &&
                                                          p.UserId == UserId
                                                          ));
        }
Example #13
0
        public async Task RunTests(Message message)
        {
            Stopwatch runTestsStopWatch = Stopwatch.StartNew();

            string specificationId = message.UserProperties["specificationId"].ToString();

            if (string.IsNullOrWhiteSpace(specificationId))
            {
                _logger.Error("Null or empty specification id provided");
                return;
            }

            BuildProject buildProject = await _builProjectsRepositoryPolicy.ExecuteAsync(() => _buildProjectRepository.GetBuildProjectBySpecificationId(specificationId));

            if (buildProject == null)
            {
                _logger.Error("A null build project was provided to UpdateAllocations");

                throw new ArgumentNullException(nameof(buildProject));
            }

            string cacheKey = message.UserProperties["providerResultsCacheKey"].ToString();

            if (string.IsNullOrWhiteSpace(cacheKey))
            {
                _logger.Error("Null or empty cache key provided");
                return;
            }

            Stopwatch providerResultsQueryStopwatch      = Stopwatch.StartNew();
            IEnumerable <ProviderResult> providerResults = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetAsync <List <ProviderResult> >($"{CacheKeys.ProviderResultBatch}{cacheKey}"));

            providerResultsQueryStopwatch.Stop();

            if (providerResults.IsNullOrEmpty())
            {
                _logger.Error($"No provider results found in cache for key: {cacheKey}");
                return;
            }

            await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.RemoveAsync <List <ProviderResult> >($"{CacheKeys.ProviderResultBatch}{cacheKey}"));

            Stopwatch testScenariosStopwatch         = Stopwatch.StartNew();
            IEnumerable <TestScenario> testScenarios = await _scenariosRepositoryPolicy.ExecuteAsync(() => _scenariosRepository.GetTestScenariosBySpecificationId(specificationId));

            testScenariosStopwatch.Stop();

            if (testScenarios.IsNullOrEmpty())
            {
                _logger.Warning($"No test scenarios found for specification id: {specificationId}");
                return;
            }

            Stopwatch            specificationLookupStopwatch = Stopwatch.StartNew();
            SpecificationSummary specification = await _specificationRepositoryPolicy.ExecuteAsync(() => _specificationRepository.GetSpecificationSummaryById(specificationId));

            specificationLookupStopwatch.Stop();

            if (specification == null)
            {
                _logger.Error($"No specification found for specification id: {specificationId}");
                return;
            }

            IEnumerable <string> providerIds = providerResults.Select(m => m.Provider.Id);

            Stopwatch providerSourceDatasetsStopwatch          = Stopwatch.StartNew();
            IEnumerable <ProviderSourceDataset> sourceDatasets = await _providerSourceDatasetsRepositoryPolicy.ExecuteAsync(() =>
                                                                                                                            _providerSourceDatasetsRepository.GetProviderSourceDatasetsByProviderIdsAndSpecificationId(providerIds, specificationId));

            providerSourceDatasetsStopwatch.Stop();

            if (sourceDatasets.IsNullOrEmpty())
            {
                _logger.Error($"No source datasets found for specification id: {specificationId}");
                return;
            }

            byte[] assembly = await _calculationsRepository.GetAssemblyBySpecificationId(specificationId);

            if (assembly.IsNullOrEmpty())
            {
                _logger.Error($"No assemblyfor specification id: {specificationId}");
                return;
            }

            buildProject.Build.Assembly = assembly;

            Stopwatch existingTestResultsStopwatch = Stopwatch.StartNew();
            IEnumerable <TestScenarioResult> testScenarioResults = await _testResultsRepositoryPolicy.ExecuteAsync(() => _testResultsRepository.GetCurrentTestResults(providerIds, specificationId));

            existingTestResultsStopwatch.Stop();

            Stopwatch runTestsStopwatch = Stopwatch.StartNew();
            IEnumerable <TestScenarioResult> results = await _testEngine.RunTests(testScenarios, providerResults, sourceDatasets, testScenarioResults.ToList(), specification, buildProject);

            runTestsStopwatch.Stop();

            Stopwatch saveResultsStopwatch = new Stopwatch();

            if (results.Any())
            {
                saveResultsStopwatch.Start();
                HttpStatusCode status = await _testResultsService.SaveTestProviderResults(results, providerResults);

                saveResultsStopwatch.Stop();

                if (!status.IsSuccess())
                {
                    _logger.Error($"Failed to save test results with status code: {status.ToString()}");
                }
            }

            runTestsStopWatch.Stop();

            IDictionary <string, double> metrics = new Dictionary <string, double>()
            {
                { "tests-run-totalMs", runTestsStopWatch.ElapsedMilliseconds },
                { "tests-run-testScenarioQueryMs", testScenariosStopwatch.ElapsedMilliseconds },
                { "tests-run-numberOfTestScenarios", testScenarios.Count() },
                { "tests-run-providersResultsQueryMs", providerResultsQueryStopwatch.ElapsedMilliseconds },
                { "tests-run-totalProvidersProcessed", providerIds.Count() },
                { "tests-run-specificationQueryMs", specificationLookupStopwatch.ElapsedMilliseconds },
                { "tests-run-providerSourceDatasetsQueryMs", providerSourceDatasetsStopwatch.ElapsedMilliseconds },
                { "tests-run-existingTestsQueryMs", existingTestResultsStopwatch.ElapsedMilliseconds },
                { "tests-run-existingTestScenarioResultsTotal", testScenarioResults.Count() },
                { "tests-run-runTestsMs", runTestsStopwatch.ElapsedMilliseconds },
            };

            if (results.Any())
            {
                metrics.Add("tests-run-saveTestResultsMs", saveResultsStopwatch.ElapsedMilliseconds);
                metrics.Add("tests-run-numberOfSavedResults", results.Count());
            }

            _telemetry.TrackEvent("RunTests",
                                  new Dictionary <string, string>()
            {
                { "specificationId", specificationId },
                { "buildProjectId", buildProject.Id },
                { "cacheKey", cacheKey },
            },
                                  metrics
                                  );
        }
Example #14
0
        public async Task UpdateCalculationCodeOnCalculationSpecificationChange_WhenNoCalculationsFoundReferencingCalculationToBeUpdated_ThenNoCalculationsUpdated()
        {
            // Arrange
            ICalculationsRepository  calculationsRepository           = CreateCalculationsRepository();
            ISpecificationRepository specificationRepository          = CreateSpecificationRepository();
            IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository();
            ICalculationCodeReferenceUpdate         calculationCodeReferenceUpdate = FakeCalculationCodeReferenceUpdate();

            CalculationService service = CreateCalculationService(calculationsRepository: calculationsRepository,
                                                                  specificationRepository: specificationRepository,
                                                                  calculationVersionRepository: versionRepository,
                                                                  calculationCodeReferenceUpdate: calculationCodeReferenceUpdate);

            const string specificationId = "specId";
            const string calculationId   = "updatedCalc";

            Models.Specs.CalculationVersionComparisonModel comparison = new Models.Specs.CalculationVersionComparisonModel()
            {
                CalculationId = calculationId,
                Current       = new Models.Specs.Calculation
                {
                    Id              = "calcSpec1",
                    Name            = "Calculation to update",
                    CalculationType = Models.Specs.CalculationType.Funding,
                },
                Previous = new Models.Specs.Calculation
                {
                    Id              = "calcSpec1",
                    Name            = "Original Name",
                    CalculationType = Models.Specs.CalculationType.Funding,
                },
                SpecificationId = specificationId,
            };

            Reference user = new Reference("userId", "User Name");

            List <Calculation> calculations = new List <Calculation>()
            {
                new Calculation
                {
                    Id                       = calculationId,
                    Name                     = "Calculation to Update",
                    SpecificationId          = specificationId,
                    FundingPeriod            = new Reference("fp1", "Funding Period"),
                    CalculationSpecification = new Reference("calcSpec1", "Calculation to Update"),
                    CalculationType          = CalculationType.Funding,
                    Description              = "Calculation Description",
                    BuildProjectId           = "bpC1",
                    Policies                 = new List <Reference>(),
                    Current                  = new CalculationVersion
                    {
                        SourceCode    = "Return 10",
                        DecimalPlaces = 6,
                    }
                },
                new Calculation
                {
                    Id                       = "referenceCalc",
                    Name                     = "Calling Calculation To Update",
                    SpecificationId          = specificationId,
                    FundingPeriod            = new Reference("fp1", "Funding Period"),
                    CalculationSpecification = new Reference("calcSpec1", "Calculation to Update"),
                    CalculationType          = CalculationType.Funding,
                    Description              = "Calculation Description",
                    BuildProjectId           = "bpC1",
                    Policies                 = new List <Reference>(),
                    Current                  = new CalculationVersion
                    {
                        SourceCode    = "Return 50",
                        DecimalPlaces = 6,
                    }
                }
            };

            calculationsRepository
            .GetCalculationsBySpecificationId(Arg.Is(specificationId))
            .Returns(calculations);

            calculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);

            calculationsRepository
            .GetCalculationById(Arg.Is(calculations[0].Id))
            .Returns(calculations[0]);

            Models.Specs.SpecificationSummary specification = new Models.Specs.SpecificationSummary()
            {
                Id   = specificationId,
                Name = "Specification Name",
            };

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(specificationId))
            .Returns(specification);

            CalculationVersion calculationVersion = new CalculationVersion
            {
                SourceCode = "Return CalculationToUpdate()",
                Version    = 2
            };

            versionRepository
            .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>())
            .Returns(calculationVersion);

            // Act
            IEnumerable <Calculation> updatedCalculations = await service.UpdateCalculationCodeOnCalculationSpecificationChange(comparison, user);

            // Assert
            updatedCalculations
            .Should()
            .HaveCount(0);

            calculationCodeReferenceUpdate
            .Received(calculations.Count)
            .ReplaceSourceCodeReferences(Arg.Any <string>(),
                                         VisualBasicTypeGenerator.GenerateIdentifier(comparison.Previous.Name),
                                         VisualBasicTypeGenerator.GenerateIdentifier(comparison.Current.Name));

            foreach (Calculation calculation in calculations)
            {
                calculationCodeReferenceUpdate
                .Received(1)
                .ReplaceSourceCodeReferences(calculation.Current.SourceCode,
                                             VisualBasicTypeGenerator.GenerateIdentifier(comparison.Previous.Name),
                                             VisualBasicTypeGenerator.GenerateIdentifier(comparison.Current.Name));
            }
        }
        public async Task <IActionResult> GetEffectivePermissionsForUser(string userId, string specificationId, HttpRequest request)
        {
            if (string.IsNullOrWhiteSpace(userId))
            {
                return(new BadRequestObjectResult($"{nameof(userId)} is empty or null"));
            }

            if (string.IsNullOrWhiteSpace(specificationId))
            {
                return(new BadRequestObjectResult($"{nameof(specificationId)} is empty or null"));
            }

            EffectiveSpecificationPermission cachedPermissions = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetHashValue <EffectiveSpecificationPermission>($"{CacheKeys.EffectivePermissions}:{userId}", specificationId));

            if (cachedPermissions != null)
            {
                return(new OkObjectResult(cachedPermissions));
            }
            else
            {
                SpecificationSummary specification = await _specificationsRepositoryPolicy.ExecuteAsync(() => _specificationsRepository.GetSpecificationSummaryById(specificationId));

                if (specification == null)
                {
                    return(new PreconditionFailedResult("Specification not found"));
                }

                List <FundingStreamPermission> permissionsForUser = new List <FundingStreamPermission>();
                foreach (Reference fundingStream in specification.FundingStreams)
                {
                    FundingStreamPermission permission = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetFundingStreamPermission(userId, fundingStream.Id));

                    if (permission != null)
                    {
                        permissionsForUser.Add(permission);
                    }
                    else
                    {
                        // Add permission for this funding stream with no permissions - used further down to calculate permissions (required for pessimistic permissions)
                        permissionsForUser.Add(new FundingStreamPermission()
                        {
                            UserId                     = userId,
                            FundingStreamId            = fundingStream.Id,
                            CanApproveFunding          = false,
                            CanChooseFunding           = false,
                            CanCreateSpecification     = false,
                            CanEditCalculations        = false,
                            CanEditSpecification       = false,
                            CanMapDatasets             = false,
                            CanPublishFunding          = false,
                            CanAdministerFundingStream = false,
                            CanApproveSpecification    = false,
                            CanCreateQaTests           = false,
                            CanDeleteCalculations      = false,
                            CanDeleteSpecification     = false,
                            CanDeleteQaTests           = false,
                            CanEditQaTests             = false,
                            CanRefreshFunding          = false,
                        });
                    }
                }

                EffectiveSpecificationPermission specificationPermissions = GeneratePermissions(permissionsForUser, specificationId, userId);

                string userPermissionHashKey = $"{CacheKeys.EffectivePermissions}:{userId}";

                // Does the hash set for this user already exist - used to determine the timeout for the hash set below
                bool existingHashSetExists = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.HashSetExists(userPermissionHashKey));

                // Cache effective permissions for the specification / user
                await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashValue(userPermissionHashKey, specificationId, specificationPermissions));

                // If the hash set does not exist, then set an expiry for the whole hash set. This stops the users permissions being stored indefinitely
                if (!existingHashSetExists)
                {
                    await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashExpiry(userPermissionHashKey, DateTime.UtcNow.AddHours(12)));
                }

                return(new OkObjectResult(specificationPermissions));
            }
        }