Exemple #1
0
        async public Task SaveDefinition_GivenNoYamlWasProvidedButFileNameWas_ReturnsBadRequest()
        {
            //Arrange
            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            ILogger logger = CreateLogger();

            DefinitionsService service = CreateDefinitionsService(logger);

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

            //Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>();

            logger
            .Received(1)
            .Error(Arg.Is($"Null or empty yaml provided for file: {yamlFile}"));
        }
Exemple #2
0
        async public Task GetDatasetDefinitions_GivenDefinitionsRequestedButContainsResults_ReturnsArray()
        {
            //Arrange
            HttpRequest request = Substitute.For <HttpRequest>();

            IEnumerable <DatasetDefinition> definitions = new[]
            {
                new DatasetDefinition(), new DatasetDefinition()
            };

            IDatasetRepository repository = CreateDataSetsRepository();

            repository
            .GetDatasetDefinitions()
            .Returns(definitions);

            DefinitionsService service = CreateDefinitionsService(datasetsRepository: repository);

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

            //Assert
            result
            .Should()
            .BeOfType <OkObjectResult>();

            OkObjectResult objResult = (OkObjectResult)result;

            IEnumerable <DatasetDefinition> objValue = (IEnumerable <DatasetDefinition>)objResult.Value;

            objValue
            .Count()
            .Should()
            .Be(2);
        }
Exemple #3
0
        public async Task GetDatasetSchemaSasUrl_GivenNullOrEmptyDefinitionName_ReturnsBadRequest()
        {
            //Arrange
            DatasetSchemaSasUrlRequestModel model = new DatasetSchemaSasUrlRequestModel();
            string json = JsonConvert.SerializeObject(model);

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

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

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            DefinitionsService definitionsService = CreateDefinitionsService(logger);

            //Act
            IActionResult result = await definitionsService.GetDatasetSchemaSasUrl(request);

            //Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>()
            .Which
            .Value
            .Should()
            .Be("No dataset schema name was provided");

            logger
            .Received(1)
            .Warning(Arg.Is("No dataset schema name was provided"));
        }
Exemple #4
0
        public async Task GetDatasetSchemaSasUrl_GivenNullRequestModel_ReturnsBadRequest()
        {
            //Arrange
            HttpRequest request = Substitute.For <HttpRequest>();

            ILogger logger = CreateLogger();

            DefinitionsService definitionsService = CreateDefinitionsService(logger);

            //Act
            IActionResult result = await definitionsService.GetDatasetSchemaSasUrl(request);

            //Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>()
            .Which
            .Value
            .Should()
            .Be("No dataset schema request model was provided");

            logger
            .Received(1)
            .Warning(Arg.Is("No dataset schema request model was provided"));
        }
Exemple #5
0
        async public Task SaveDefinition_GivenValidYamlButSavingToDatabaseThrowsException_ReturnsInternalServerError()
        {
            //Arrange
            string yaml = CreateRawDefinition();

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

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            IDatasetRepository dataSetsRepository = CreateDataSetsRepository();

            dataSetsRepository
            .When(x => x.SaveDefinition(Arg.Any <DatasetDefinition>()))
            .Do(x => { throw new Exception(); });

            DatasetDefinitionChanges datasetDefinitionChanges = new DatasetDefinitionChanges();

            IDefinitionChangesDetectionService definitionChangesDetectionService = CreateChangesDetectionService();

            definitionChangesDetectionService
            .DetectChanges(Arg.Any <DatasetDefinition>(), Arg.Any <DatasetDefinition>())
            .Returns(datasetDefinitionChanges);

            DefinitionsService service = CreateDefinitionsService(logger, dataSetsRepository, definitionChangesDetectionService: definitionChangesDetectionService);

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

            //Assert
            result
            .Should()
            .BeOfType <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be("Exception occurred writing to yaml file: 12345.yaml to cosmos db");

            logger
            .Received(1)
            .Error(Arg.Any <Exception>(), Arg.Is($"Exception occurred writing to yaml file: {yamlFile} to cosmos db"));
        }
Exemple #6
0
        public async Task GetDatasetSchemaSasUrl_GivenModelAndDatasetNameContainsSlashes_ReplacesSlashesWithUnderscoreAndReturnsUrl()
        {
            // Arrange
            DatasetSchemaSasUrlRequestModel model = new DatasetSchemaSasUrlRequestModel
            {
                DatasetDefinitionId = "12345"
            };

            string json = JsonConvert.SerializeObject(model);

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

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

            request
            .Body
            .Returns(stream);

            IBlobClient blobClient = CreateBlobClient();

            DatasetDefinition datasetDefinition = new DatasetDefinition()
            {
                Id   = "12345",
                Name = "TEST/SLASH Definition",
            };

            IDatasetRepository datasetRepository = CreateDataSetsRepository();

            datasetRepository
            .GetDatasetDefinition(Arg.Is(model.DatasetDefinitionId))
            .Returns(datasetDefinition);

            DefinitionsService definitionsService = CreateDefinitionsService(
                datasetsRepository: datasetRepository,
                blobClient: blobClient);

            // Act
            IActionResult result = await definitionsService.GetDatasetSchemaSasUrl(request);

            // Assert
            result
            .Should()
            .BeOfType <OkObjectResult>();

            blobClient
            .Received(1)
            .GetBlobSasUrl(Arg.Is("schemas/TEST_SLASH Definition.xlsx"), Arg.Any <DateTimeOffset>(), Arg.Any <SharedAccessBlobPermissions>());
        }
Exemple #7
0
        async public Task SaveDefinition_GivenNoYamlWasProvidedWithNoFileName_ReturnsBadRequest()
        {
            //Arrange
            HttpRequest request = Substitute.For <HttpRequest>();

            ILogger logger = CreateLogger();

            DefinitionsService service = CreateDefinitionsService(logger);

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

            //Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>();

            logger
            .Received(1)
            .Error(Arg.Is($"Null or empty yaml provided for file: File name not provided"));
        }
Exemple #8
0
        async public Task SaveDefinition_GivenNoYamlWasProvidedButIsInvalid_ReturnsBadRequest()
        {
            //Arrange
            string yaml = "invalid yaml";

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

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            DefinitionsService service = CreateDefinitionsService(logger);

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

            //Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>();

            logger
            .Received(1)
            .Error(Arg.Any <Exception>(), Arg.Is($"Invalid yaml was provided for file: {yamlFile}"));
        }
Exemple #9
0
        public async Task SaveDefinition_GivenValidYamlAndSearchDoesContainsExistingItemWithNoUpdates_ThenDatasetDefinitionSavedInCosmosAndSearchNotUpdatedAndReturnsOK()
        {
            //Arrange
            string yaml         = CreateRawDefinition();
            string definitionId = "9183";

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

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            HttpStatusCode statusCode = HttpStatusCode.Created;

            IDatasetRepository datasetsRepository = CreateDataSetsRepository();

            datasetsRepository
            .SaveDefinition(Arg.Any <DatasetDefinition>())
            .Returns(statusCode);

            DatasetDefinitionIndex existingIndex = new DatasetDefinitionIndex()
            {
                Description        = "14/15 description",
                Id                 = "9183",
                LastUpdatedDate    = new DateTimeOffset(2018, 6, 19, 14, 10, 2, TimeSpan.Zero),
                ModelHash          = "DFBD0E1ACD29CEBCF5AD45674688D3780D916294C4DF878074AFD01B67BF129C",
                Name               = "14/15",
                ProviderIdentifier = "None",
            };

            ISearchRepository <DatasetDefinitionIndex> searchRepository = CreateDatasetDefinitionSearchRepository();

            searchRepository
            .SearchById(Arg.Is(definitionId))
            .Returns(existingIndex);

            byte[] excelAsBytes = new byte[100];

            IExcelWriter <DatasetDefinition> excelWriter = CreateExcelWriter();

            excelWriter
            .Write(Arg.Any <DatasetDefinition>())
            .Returns(excelAsBytes);

            ICloudBlob blob = Substitute.For <ICloudBlob>();

            IBlobClient blobClient = CreateBlobClient();

            blobClient
            .GetBlockBlobReference(Arg.Any <string>())
            .Returns(blob);

            DatasetDefinitionChanges datasetDefinitionChanges = new DatasetDefinitionChanges();

            IDefinitionChangesDetectionService definitionChangesDetectionService = CreateChangesDetectionService();

            definitionChangesDetectionService
            .DetectChanges(Arg.Any <DatasetDefinition>(), Arg.Any <DatasetDefinition>())
            .Returns(datasetDefinitionChanges);

            DefinitionsService service = CreateDefinitionsService(logger, datasetsRepository, searchRepository, excelWriter: excelWriter, blobClient: blobClient, definitionChangesDetectionService: definitionChangesDetectionService);

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

            //Assert
            result
            .Should()
            .BeOfType <OkResult>();

            await searchRepository
            .Received(1)
            .SearchById(Arg.Is(definitionId));

            await searchRepository
            .Received(0)
            .Index(Arg.Any <IEnumerable <DatasetDefinitionIndex> >());

            await datasetsRepository
            .Received(1)
            .SaveDefinition(Arg.Is <DatasetDefinition>(
                                i => i.Description == "14/15 description" &&
                                i.Id == "9183" &&
                                i.Name == "14/15"
                                ));

            logger
            .Received(1)
            .Information(Arg.Is($"Successfully saved file: {yamlFile} to cosmos db"));
        }
Exemple #10
0
        async public Task SaveDefinition_GivenValidYamlAndSearchDoesNotContainExistingItem_ThenSaveWasSuccesfulAndReturnsOK()
        {
            //Arrange
            string yaml         = CreateRawDefinition();
            string definitionId = "9183";

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

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            HttpStatusCode statusCode = HttpStatusCode.Created;

            IDatasetRepository datasetsRepository = CreateDataSetsRepository();

            datasetsRepository
            .SaveDefinition(Arg.Any <DatasetDefinition>())
            .Returns(statusCode);

            ISearchRepository <DatasetDefinitionIndex> searchRepository = CreateDatasetDefinitionSearchRepository();

            searchRepository
            .SearchById(Arg.Is(definitionId))
            .Returns((DatasetDefinitionIndex)null);

            byte[] excelAsBytes = new byte[100];

            IExcelWriter <DatasetDefinition> excelWriter = CreateExcelWriter();

            excelWriter
            .Write(Arg.Any <DatasetDefinition>())
            .Returns(excelAsBytes);

            ICloudBlob blob = Substitute.For <ICloudBlob>();

            IBlobClient blobClient = CreateBlobClient();

            blobClient
            .GetBlockBlobReference(Arg.Any <string>())
            .Returns(blob);

            DatasetDefinitionChanges datasetDefinitionChanges = new DatasetDefinitionChanges();

            IDefinitionChangesDetectionService definitionChangesDetectionService = CreateChangesDetectionService();

            definitionChangesDetectionService
            .DetectChanges(Arg.Any <DatasetDefinition>(), Arg.Any <DatasetDefinition>())
            .Returns(datasetDefinitionChanges);

            DefinitionsService service = CreateDefinitionsService(logger, datasetsRepository, searchRepository,
                                                                  excelWriter: excelWriter, blobClient: blobClient, definitionChangesDetectionService: definitionChangesDetectionService);

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

            //Assert
            result
            .Should()
            .BeOfType <OkResult>();

            await searchRepository
            .Received(1)
            .SearchById(Arg.Is(definitionId));

            await searchRepository
            .Received(1)
            .Index(Arg.Is <IEnumerable <DatasetDefinitionIndex> >(
                       i => i.First().Description == "14/15 description" &&
                       i.First().Id == "9183" &&
                       !string.IsNullOrWhiteSpace(i.First().ModelHash) &&
                       i.First().Name == "14/15" &&
                       i.First().ProviderIdentifier == "None"
                       ));

            await datasetsRepository
            .Received(1)
            .SaveDefinition(Arg.Is <DatasetDefinition>(
                                i => i.Description == "14/15 description" &&
                                i.Id == "9183" &&
                                i.Name == "14/15"
                                ));

            logger
            .Received(1)
            .Information(Arg.Is($"Successfully saved file: {yamlFile} to cosmos db"));
        }
Exemple #11
0
        async public Task SaveDefinition_GivenValidYamlButFailsToUploadToBlobStorage_ReturnsInvalidServerError()
        {
            //Arrange
            string yaml         = CreateRawDefinition();
            string definitionId = "9183";

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

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            HttpStatusCode statusCode = HttpStatusCode.Created;

            IDatasetRepository datasetsRepository = CreateDataSetsRepository();

            datasetsRepository
            .SaveDefinition(Arg.Any <DatasetDefinition>())
            .Returns(statusCode);

            ISearchRepository <DatasetDefinitionIndex> searchRepository = CreateDatasetDefinitionSearchRepository();

            searchRepository
            .SearchById(Arg.Is(definitionId))
            .Returns((DatasetDefinitionIndex)null);

            byte[] excelAsBytes = new byte[100];

            IExcelWriter <DatasetDefinition> excelWriter = CreateExcelWriter();

            excelWriter
            .Write(Arg.Any <DatasetDefinition>())
            .Returns(excelAsBytes);

            ICloudBlob blob = Substitute.For <ICloudBlob>();

            blob
            .When(x => x.UploadFromStreamAsync(Arg.Any <Stream>()))
            .Do(x => { throw new Exception($"Failed to upload 14/15 blob storage"); });

            IBlobClient blobClient = CreateBlobClient();

            blobClient
            .GetBlockBlobReference(Arg.Is("schemas/14_15.xlsx"))
            .Returns(blob);

            DatasetDefinitionChanges datasetDefinitionChanges = new DatasetDefinitionChanges();

            IDefinitionChangesDetectionService definitionChangesDetectionService = CreateChangesDetectionService();

            definitionChangesDetectionService
            .DetectChanges(Arg.Any <DatasetDefinition>(), Arg.Any <DatasetDefinition>())
            .Returns(datasetDefinitionChanges);

            DefinitionsService service = CreateDefinitionsService(logger, datasetsRepository, searchRepository,
                                                                  excelWriter: excelWriter, blobClient: blobClient, definitionChangesDetectionService: definitionChangesDetectionService);

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

            //Assert
            result
            .Should()
            .BeOfType <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be($"Failed to upload 14/15 blob storage");
        }
Exemple #12
0
        async public Task SaveDefinition_GivenValidYamlButFailsToGenerateExcelFile_ReturnsInvalidServerError()
        {
            //Arrange
            string yaml         = CreateRawDefinition();
            string definitionId = "9183";

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

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            HttpStatusCode statusCode = HttpStatusCode.Created;

            IDatasetRepository datasetsRepository = CreateDataSetsRepository();

            datasetsRepository
            .SaveDefinition(Arg.Any <DatasetDefinition>())
            .Returns(statusCode);

            ISearchRepository <DatasetDefinitionIndex> searchRepository = CreateDatasetDefinitionSearchRepository();

            searchRepository
            .SearchById(Arg.Is(definitionId))
            .Returns((DatasetDefinitionIndex)null);

            byte[] excelAsBytes = new byte[0];

            IExcelWriter <DatasetDefinition> excelWriter = CreateExcelWriter();

            excelWriter
            .Write(Arg.Any <DatasetDefinition>())
            .Returns(excelAsBytes);

            DatasetDefinitionChanges datasetDefinitionChanges = new DatasetDefinitionChanges();

            IDefinitionChangesDetectionService definitionChangesDetectionService = CreateChangesDetectionService();

            definitionChangesDetectionService
            .DetectChanges(Arg.Any <DatasetDefinition>(), Arg.Any <DatasetDefinition>())
            .Returns(datasetDefinitionChanges);

            DefinitionsService service = CreateDefinitionsService(logger, datasetsRepository, searchRepository, excelWriter: excelWriter, definitionChangesDetectionService: definitionChangesDetectionService);

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

            //Assert
            result
            .Should()
            .BeOfType <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be($"Failed to generate excel file for 14/15");

            logger
            .Received(1)
            .Error(Arg.Is($"Failed to generate excel file for 14/15"));
        }
Exemple #13
0
        async public Task SaveDefinition_GivenValidYamlButFailedToSaveToDatabase_ReturnsStatusCode()
        {
            //Arrange
            string yaml = CreateRawDefinition();

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

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            HttpStatusCode failedCode = HttpStatusCode.BadGateway;

            IDatasetRepository dataSetsRepository = CreateDataSetsRepository();

            dataSetsRepository
            .SaveDefinition(Arg.Any <DatasetDefinition>())
            .Returns(failedCode);

            DatasetDefinitionChanges datasetDefinitionChanges = new DatasetDefinitionChanges();

            IDefinitionChangesDetectionService definitionChangesDetectionService = CreateChangesDetectionService();

            definitionChangesDetectionService
            .DetectChanges(Arg.Any <DatasetDefinition>(), Arg.Any <DatasetDefinition>())
            .Returns(datasetDefinitionChanges);

            DefinitionsService service = CreateDefinitionsService(logger, dataSetsRepository, definitionChangesDetectionService: definitionChangesDetectionService);

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

            //Assert
            result
            .Should()
            .BeOfType <StatusCodeResult>();

            StatusCodeResult statusCodeResult = (StatusCodeResult)result;

            statusCodeResult
            .StatusCode
            .Should()
            .Be(502);

            logger
            .Received(1)
            .Error(Arg.Is($"Failed to save yaml file: {yamlFile} to cosmos db with status 502"));
        }
Exemple #14
0
        async public Task SaveDefinition_GivenUpdatedYamlWithChangedIdentifierTypeFieldButAlreadyUsedInRelationship_ReturnsBadRequest()
        {
            //Arrange
            IEnumerable <string> specificationIds = new[] { "spec-1" };
            string definitionId = "9183";
            string yaml         = CreateRawDefinition();

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

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            IDatasetRepository datasetRepository = CreateDataSetsRepository();

            datasetRepository
            .GetDistinctRelationshipSpecificationIdsForDatasetDefinitionId(Arg.Is(definitionId))
            .Returns(specificationIds);
            datasetRepository
            .GetDatasetDefinition(Arg.Is(definitionId))
            .Returns(new DatasetDefinition());

            DatasetDefinitionChanges datasetDefinitionChanges = new DatasetDefinitionChanges
            {
                Id = definitionId,
            };

            FieldDefinitionChanges fieldDefinitionChanges = new FieldDefinitionChanges();

            fieldDefinitionChanges.ChangeTypes.Add(FieldDefinitionChangeType.IdentifierType);

            TableDefinitionChanges tableDefinitionChanges = new TableDefinitionChanges();

            tableDefinitionChanges.FieldChanges.Add(fieldDefinitionChanges);

            datasetDefinitionChanges.TableDefinitionChanges.Add(tableDefinitionChanges);

            IDefinitionChangesDetectionService definitionChangesDetectionService = CreateChangesDetectionService();

            definitionChangesDetectionService
            .DetectChanges(Arg.Any <DatasetDefinition>(), Arg.Any <DatasetDefinition>())
            .Returns(datasetDefinitionChanges);

            DefinitionsService service = CreateDefinitionsService(logger, definitionChangesDetectionService: definitionChangesDetectionService, datasetsRepository: datasetRepository);

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

            //Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>()
            .Which
            .Value
            .Should()
            .Be("Unable to change provider identifier as there are currently relationships setup against this schema");
        }
Exemple #15
0
        public async Task GetDatasetSchemaSasUrl_GivenModelAndDatasetNameDoesNotContainSlashes_GetSasUrl()
        {
            //Arrange
            const string sasUrl = "https://wherever.naf?jhjhjhjhjhhjhjhjhjjhj";

            DatasetSchemaSasUrlRequestModel model = new DatasetSchemaSasUrlRequestModel
            {
                DatasetDefinitionId = "12345"
            };

            string json = JsonConvert.SerializeObject(model);

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

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

            request
            .Body
            .Returns(stream);

            IBlobClient blobClient = CreateBlobClient();

            blobClient
            .GetBlobSasUrl(Arg.Any <string>(), Arg.Any <DateTimeOffset>(), Arg.Any <SharedAccessBlobPermissions>())
            .Returns(sasUrl);

            DatasetDefinition datasetDefinition = new DatasetDefinition()
            {
                Id   = "12345",
                Name = "14 15",
            };

            IDatasetRepository datasetRepository = CreateDataSetsRepository();

            datasetRepository
            .GetDatasetDefinition(Arg.Is(model.DatasetDefinitionId))
            .Returns(datasetDefinition);

            DefinitionsService definitionsService = CreateDefinitionsService(
                datasetsRepository: datasetRepository,
                blobClient: blobClient);

            //Act
            IActionResult result = await definitionsService.GetDatasetSchemaSasUrl(request);

            //Assert
            result
            .Should()
            .BeOfType <OkObjectResult>();

            OkObjectResult okObjectResult = result as OkObjectResult;

            DatasetSchemaSasUrlResponseModel responseModel = okObjectResult.Value as DatasetSchemaSasUrlResponseModel;

            responseModel
            .SchemaUrl
            .Should()
            .Be(sasUrl);

            blobClient
            .Received(1)
            .GetBlobSasUrl(Arg.Is("schemas/14 15.xlsx"), Arg.Any <DateTimeOffset>(), Arg.Any <SharedAccessBlobPermissions>());
        }
Exemple #16
0
        public async Task SaveDefinition_GivenValidYamlAndDoesContainsExistingItemWithNoModelUpdates_ThenDoesNotAddMessageToTopicAndReturnsOK()
        {
            //Arrange
            string yaml         = CreateRawDefinition();
            string definitionId = "9183";

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

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("yaml-file", new StringValues(yamlFile));

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

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            HttpStatusCode statusCode = HttpStatusCode.Created;

            DatasetDefinition existingDatasetDefinition = new DatasetDefinition
            {
                Id = definitionId
            };

            IDatasetRepository datasetsRepository = CreateDataSetsRepository();

            datasetsRepository
            .SaveDefinition(Arg.Any <DatasetDefinition>())
            .Returns(statusCode);

            datasetsRepository
            .GetDatasetDefinition(Arg.Is(definitionId))
            .Returns(existingDatasetDefinition);

            byte[] excelAsBytes = new byte[100];

            IExcelWriter <DatasetDefinition> excelWriter = CreateExcelWriter();

            excelWriter
            .Write(Arg.Any <DatasetDefinition>())
            .Returns(excelAsBytes);

            ICloudBlob blob = Substitute.For <ICloudBlob>();

            IBlobClient blobClient = CreateBlobClient();

            blobClient
            .GetBlockBlobReference(Arg.Any <string>())
            .Returns(blob);

            DatasetDefinitionChanges datasetDefinitionChanges = new DatasetDefinitionChanges();

            IDefinitionChangesDetectionService definitionChangesDetectionService = CreateChangesDetectionService();

            definitionChangesDetectionService
            .DetectChanges(Arg.Any <DatasetDefinition>(), Arg.Is(existingDatasetDefinition))
            .Returns(datasetDefinitionChanges);

            IMessengerService messengerService = CreateMessengerService();

            DefinitionsService service = CreateDefinitionsService(
                logger,
                datasetsRepository,
                excelWriter: excelWriter,
                blobClient: blobClient,
                definitionChangesDetectionService: definitionChangesDetectionService,
                messengerService: messengerService);

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

            //Assert
            result
            .Should()
            .BeOfType <OkResult>();

            await
            messengerService
            .DidNotReceive()
            .SendToTopic(
                Arg.Is(ServiceBusConstants.TopicNames.DataDefinitionChanges),
                Arg.Any <DatasetDefinitionChanges>(),
                Arg.Any <IDictionary <string, string> >());
        }
Exemple #17
0
 public DefinitionsController(DefinitionsService service)
 {
     _service = service;
 }
Exemple #18
0
            public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
            {
                // (1) Make sure the API caller have provided a tenantId, and extract it
                try
                {
                    var cancellation = context.HttpContext.RequestAborted;
                    int tenantId     = _tenantIdAccessor.GetTenantId();

                    // Init the database connection...
                    // The client sometimes makes ambient API calls, not in response to user interaction
                    // Such calls should not update LastAccess of that user
                    bool silent = context.HttpContext.Request.Query["silent"].FirstOrDefault()?.ToString()?.ToLower() == "true";
                    await _appRepo.InitConnectionAsync(tenantId, setLastActive : !silent, cancellation);

                    // (2) Make sure the user is a member of this tenant
                    UserInfo userInfo = await _appRepo.GetUserInfoAsync(cancellation);

                    if (userInfo.UserId == null)
                    {
                        // If there is no user cut the pipeline short and return a Forbidden 403
                        context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);

                        // This indicates to the client to discard all cached information about this
                        // company since the user is no longer a member of it
                        context.HttpContext.Response.Headers.Add("x-settings-version", Constants.Unauthorized);
                        context.HttpContext.Response.Headers.Add("x-definitions-version", Constants.Unauthorized);
                        context.HttpContext.Response.Headers.Add("x-permissions-version", Constants.Unauthorized);
                        context.HttpContext.Response.Headers.Add("x-user-settings-version", Constants.Unauthorized);

                        return;
                    }

                    var userId        = userInfo.UserId.Value;
                    var externalId    = _externalUserAccessor.GetUserId();
                    var externalEmail = _externalUserAccessor.GetUserEmail();

                    // (3) If the user exists but new, set the External Id
                    if (userInfo.ExternalId == null)
                    {
                        // Update external Id in this tenant database
                        await _appRepo.Users__SetExternalIdByUserId(userId, externalId);

                        // Update external Id in the central Admin database too (To avoid an awkward situation
                        // where a user exists on the tenant but not on the Admin db, if they change their email in between)
                        var adminRepo = _serviceProvider.GetRequiredService <AdminRepository>();
                        await adminRepo.DirectoryUsers__SetExternalIdByEmail(externalEmail, externalId);
                    }

                    else if (userInfo.ExternalId != externalId)
                    {
                        // Note: there is the edge case of identity providers who allow email recycling. I.e. we can get the same email twice with
                        // two different external Ids. This issue is so unlikely to naturally occur and cause problems here that we are not going
                        // to handle it for now. It can however happen artificually if the application is re-configured to a new identity provider,
                        // or if someone messed with the identity database directly, but again out of scope for now.
                        context.Result = new BadRequestObjectResult("The sign-in email already exists but with a different external Id");
                        return;
                    }

                    // (4) If the user's email address has changed at the identity server, update it locally
                    else if (userInfo.Email != externalEmail)
                    {
                        await _appRepo.Users__SetEmailByUserId(userId, externalEmail);
                    }

                    // (5) Set the tenant info in the context, to make it accessible for model metadata providers
                    var tenantInfo = await _appRepo.GetTenantInfoAsync(cancellation);

                    _tenantInfoAccessor.SetInfo(tenantId, tenantInfo);

                    // (6) Ensure the freshness of the definitions and settings caches
                    {
                        var databaseVersion = tenantInfo.DefinitionsVersion;
                        var serverVersion   = _definitionsCache.GetDefinitionsIfCached(tenantId)?.Version;

                        if (serverVersion == null || serverVersion != databaseVersion)
                        {
                            // Update the cache
                            var definitions = await DefinitionsService.LoadDefinitionsForClient(_appRepo, cancellation);

                            if (!cancellation.IsCancellationRequested)
                            {
                                _definitionsCache.SetDefinitions(tenantId, definitions);
                            }
                        }
                    }
                    {
                        var databaseVersion = tenantInfo.SettingsVersion;
                        var serverVersion   = _settingsCache.GetSettingsIfCached(tenantId)?.Version;

                        if (serverVersion == null || serverVersion != databaseVersion)
                        {
                            // Update the cache
                            var settings = await GeneralSettingsService.LoadSettingsForClient(_appRepo, cancellation);

                            if (!cancellation.IsCancellationRequested)
                            {
                                _settingsCache.SetSettings(tenantId, settings);
                            }
                        }
                    }

                    // (7) If any version headers are supplied: examine their freshness
                    {
                        // Permissions
                        var clientVersion = context.HttpContext.Request.Headers["X-Permissions-Version"].FirstOrDefault();
                        if (!string.IsNullOrWhiteSpace(clientVersion))
                        {
                            var databaseVersion = userInfo.PermissionsVersion;
                            context.HttpContext.Response.Headers.Add("x-permissions-version",
                                                                     clientVersion == databaseVersion ? Constants.Fresh : Constants.Stale);
                        }
                    }

                    {
                        // User Settings
                        var clientVersion = context.HttpContext.Request.Headers["X-User-Settings-Version"].FirstOrDefault();
                        if (!string.IsNullOrWhiteSpace(clientVersion))
                        {
                            var databaseVersion = userInfo.UserSettingsVersion;
                            context.HttpContext.Response.Headers.Add("x-user-settings-version",
                                                                     clientVersion == databaseVersion ? Constants.Fresh : Constants.Stale);
                        }
                    }

                    {
                        // Definitions
                        var clientVersion = context.HttpContext.Request.Headers["X-Definitions-Version"].FirstOrDefault();
                        if (!string.IsNullOrWhiteSpace(clientVersion))
                        {
                            var databaseVersion = tenantInfo.DefinitionsVersion;
                            context.HttpContext.Response.Headers.Add("x-definitions-version",
                                                                     clientVersion == databaseVersion ? Constants.Fresh : Constants.Stale);
                        }
                    }
                    {
                        // Settings
                        var clientVersion = context.HttpContext.Request.Headers["X-Settings-Version"].FirstOrDefault();
                        if (!string.IsNullOrWhiteSpace(clientVersion))
                        {
                            var databaseVersion = tenantInfo.SettingsVersion;
                            context.HttpContext.Response.Headers.Add("x-settings-version",
                                                                     clientVersion == databaseVersion ? Constants.Fresh : Constants.Stale);
                        }
                    }

                    // Call the Action itself
                    await next();
                }
                catch (TaskCanceledException)
                {
                    context.Result = new OkResult();
                    return;
                }
                catch (MultitenancyException ex)
                {
                    // If the tenant Id is not provided cut the pipeline short and return a Bad Request 400
                    context.Result = new BadRequestObjectResult(ex.Message);
                    return;
                }
                catch (BadRequestException ex)
                {
                    // If the tenant Id is not provided cut the pipeline short and return a Bad Request 400
                    context.Result = new BadRequestObjectResult(ex.Message);
                    return;
                }
                catch (Exception ex)
                {
                    // TODO: Return to logging and 500 status code
                    context.Result = new BadRequestObjectResult(ex.GetType().Name + ": " + ex.Message);
                    //_logger.LogError(ex.Message);
                    //context.Result = new StatusCodeResult(StatusCodes.Status500InternalServerError);

                    return;
                }
            }