Ejemplo n.º 1
0
        public async Task CanCreateAndDeleteData()
        {
            var dataType  = "SqlUnitTestObject";
            var utcNow    = DateTime.UtcNow;
            var container = new GenericDataContainer(
                IdGenerator.FromGuid(),
                "jdoe",
                utcNow,
                "jdoe",
                utcNow,
                ApiVersion.Current,
                BsonDocument.Parse("{ Name : 'Jan', Address : { Street : 'Teglholm Tværvej', Number : 27 }}"));
            var         sut         = CreateMssqlRdDataStorage();
            StoreResult storeResult = null;

            Assert.That(async() => storeResult = await sut.StoreAsync(dataType, container, false), Throws.Nothing);
            Assert.That(storeResult.ModificationType, Is.EqualTo(DataModificationType.Created));
            var retrievedContainer = await sut.GetFromIdAsync(dataType, storeResult.Id);

            Assert.That(retrievedContainer.Submitter, Is.EqualTo(container.Submitter));
            Assert.That(retrievedContainer.SubmissionTimeUtc, Is.EqualTo(container.SubmissionTimeUtc).Within(TimeSpan.FromSeconds(1)));
            Assert.That(retrievedContainer.Data.GetValue("Name").AsString, Is.EqualTo(container.Data.GetValue("Name").AsString));

            // Cannot add document a second time
            Assert.That(async() => storeResult = await sut.StoreAsync(dataType, container, false), Throws.TypeOf <DocumentAlreadyExistsException>());

            // Can overwrite document
            Assert.That(async() => storeResult = await sut.StoreAsync(dataType, container, true), Throws.Nothing);
            Assert.That(storeResult.ModificationType, Is.EqualTo(DataModificationType.Replaced));

            var isDeleted = await sut.DeleteDataContainerAsync(dataType, storeResult.Id);

            Assert.That(isDeleted, Is.True);
        }
Ejemplo n.º 2
0
        public void RoundtripPreservesData()
        {
            var sut       = new BinaryDataObjectSplitter(nameof(DataBlob.Data));
            var id        = IdGenerator.FromGuid();
            var dataBlob  = new DataBlob(id, new byte[] { 0x42, 0x43, 0x44 }, "myFile.bin");
            var payload   = DataEncoder.Encode(JsonConvert.SerializeObject(dataBlob));
            var utcNow    = DateTime.UtcNow;
            var container = new GenericDataContainer(id, "jdoe", utcNow, "jdoe", utcNow, "1.5.9", payload);
            BinaryDataObjectSplitterResult result = null;

            Assert.That(() => result = sut.Split(container), Throws.Nothing);
            Assert.That(result, Is.Not.Null);
            Assert.That(result.BinaryData, Is.EqualTo(dataBlob.Data));
            var containerWithoutBinaryData = result.ContainerWithoutBinaryData;

            Assert.That(containerWithoutBinaryData.Id, Is.EqualTo(container.Id));
            Assert.That(containerWithoutBinaryData.Submitter, Is.EqualTo(container.Submitter));
            Assert.That(containerWithoutBinaryData.SubmissionTimeUtc, Is.EqualTo(container.SubmissionTimeUtc));
            Assert.That(containerWithoutBinaryData.ApiVersion, Is.EqualTo(container.ApiVersion));
            Assert.That(containerWithoutBinaryData.Data, Is.Not.Null);
            Assert.That(containerWithoutBinaryData.Data.GetValue(nameof(DataBlob.Data)), Is.EqualTo(BsonString.Empty));

            var reconstructedContainer = sut.Reassemble(containerWithoutBinaryData, result.BinaryData);

            Assert.That(reconstructedContainer.Id, Is.EqualTo(container.Id));
            Assert.That(reconstructedContainer.Submitter, Is.EqualTo(container.Submitter));
            Assert.That(reconstructedContainer.SubmissionTimeUtc, Is.EqualTo(container.SubmissionTimeUtc));
            Assert.That(reconstructedContainer.ApiVersion, Is.EqualTo(container.ApiVersion));
            Assert.That(reconstructedContainer.Data, Is.Not.Null);
            var reconstructedDataBlob = JsonConvert.DeserializeObject <DataBlob>(reconstructedContainer.Data.ToJson());

            Assert.That(reconstructedDataBlob.Id, Is.EqualTo(dataBlob.Id));
            Assert.That(reconstructedDataBlob.Filename, Is.EqualTo(dataBlob.Filename));
            Assert.That(reconstructedDataBlob.Data, Is.EqualTo(dataBlob.Data));
        }
        public async Task CanWriteReadAndDeleteContainer()
        {
            var sut       = CreateAzureBlobRdDataStorage(out var metadataStorage);
            var dataType  = nameof(DataBlob);
            var id        = "BlobStorageTestBlob";
            var dataBlob  = new DataBlob(id, new byte[] { 0x42, 0x43, 0x44 }, "myFile.bin");
            var payload   = DataEncoder.Encode(JsonConvert.SerializeObject(dataBlob));
            var submitter = "jdoe";
            var utcNow    = DateTime.UtcNow;
            var container = new GenericDataContainer(id, submitter, utcNow, submitter, utcNow, ApiVersion.Current, payload);

            if (await sut.ExistsAsync(dataType, id))
            {
                await sut.DeleteDataContainerAsync(dataType, id);
            }

            IdReservationResult idReservation = null;

            Assert.That(async() => idReservation = await sut.ReserveIdAsync(dataType, id, submitter), Throws.Nothing);
            Assert.That(idReservation.IsReserved, Is.True);

            Assert.That(() => sut.StoreAsync(dataType, container, true), Throws.Nothing);
            metadataStorage.Setup(x => x.GetFromIdAsync(dataType, id)).Returns(Task.FromResult(container));
            Assert.That(await sut.ExistsAsync(dataType, id), Is.True);

            GenericDataContainer retreivedContainer = null;

            Assert.That(async() => retreivedContainer = await sut.GetFromIdAsync(dataType, id), Throws.Nothing);
            Assert.That(retreivedContainer, Is.Not.Null);

            Assert.That(async() => await sut.DeleteDataContainerAsync(dataType, id), Throws.Nothing);
            metadataStorage.Setup(x => x.GetFromIdAsync(dataType, id)).Returns(Task.FromResult(default(GenericDataContainer)));
            Assert.That(await sut.ExistsAsync(dataType, id), Is.False);
        }
Ejemplo n.º 4
0
        public async Task CanCreateAndDeleteData()
        {
            var dataType = "SqlUnitTestObject";
            var utcNow = DateTime.UtcNow;
            var sut = CreateMssqlRdDataStorage(out _);
            var submitter = "jdoe";
            var container = new GenericDataContainer(
                "-1",
                submitter,
                utcNow,
                submitter,
                utcNow,
                ApiVersion.Current,
                BsonDocument.Parse("{ "
                                   + $"Id : '{IdGenerator.FromGuid()}', "
                                   + $"OriginalSubmitter: 'jdoe', "
                                   + $"CreatedTimeUtc: '{utcNow:yyyy-MM-dd HH:mm:ss}', "
                                   + $"Submitter: 'jdoe', "
                                   + $"SubmissionTimeUtc: '{utcNow:yyyy-MM-dd HH:mm:ss}', "
                                   + $"'Data#Name': 'Bertha' "
                                   + "}"));
            
            StoreResult storeResult = null;
            Assert.That(async () => storeResult = await sut.StoreAsync(dataType, container, true), Throws.Nothing);
            Assert.That(storeResult.ModificationType, Is.EqualTo(DataModificationType.Created));
            var retrievedContainer = await sut.GetFromIdAsync(dataType, storeResult.Id);
            Assert.That(retrievedContainer.Submitter, Is.EqualTo(container.Submitter));
            Assert.That(retrievedContainer.SubmissionTimeUtc, Is.EqualTo(container.SubmissionTimeUtc).Within(TimeSpan.FromSeconds(1)));
            Assert.That(retrievedContainer.Data.GetValue("Data.Name").AsString, Is.EqualTo(container.Data.GetValue("Data#Name").AsString));

            // Cannot add document a second time
            var idReplacedContainer = new GenericDataContainer(
                storeResult.Id,
                container.OriginalSubmitter,
                container.CreatedTimeUtc,
                container.Submitter,
                container.SubmissionTimeUtc,
                container.ApiVersion,
                container.Data);
            Assert.That(async () => storeResult = await sut.StoreAsync(dataType, idReplacedContainer, false), Throws.TypeOf<DocumentAlreadyExistsException>());

            // Can overwrite document
            Assert.That(async () => storeResult = await sut.StoreAsync(dataType, idReplacedContainer, true), Throws.Nothing);
            Assert.That(storeResult.ModificationType, Is.EqualTo(DataModificationType.Replaced));

            var isDeleted = await sut.DeleteDataContainerAsync(dataType, storeResult.Id);
            Assert.That(isDeleted, Is.True);
        }
Ejemplo n.º 5
0
        public void StatementFromContainerAsExpected()
        {
            var dataType       = "SqlUnitTestObject1";
            var createdTimeUtc = DateTime.Parse("2019-08-27 01:02:03");
            var container      = new GenericDataContainer(
                "1234",
                "jdoe",
                createdTimeUtc,
                "jdoe",
                createdTimeUtc,
                ApiVersion.Current,
                DataEncoder.Encode(JsonConvert.SerializeObject(new { Name = "Doe", Age = 101.4, TimeUtc = createdTimeUtc })));
            var actual   = SqlUpdateStatement.CreateFromContainer(dataType, container);
            var expected = $"UPDATE {dataType} SET Submitter='jdoe', SubmissionTimeUtc='2019-08-27 01:02:03', Data#Name='Doe', Data#Age='101.4', Data#TimeUtc='2019-08-27 01:02:03' WHERE Id='1234'";

            Assert.That(actual, Is.EqualTo(expected));
        }
        public void CanBuildReservationContainer()
        {
            var sut       = CreateReservationContainerBuilder();
            var submitter = "jdoe";
            GenericDataContainer actual = null;

            Assert.That(() => actual = sut.Build(submitter), Throws.Nothing);
            Assert.That(actual, Is.Not.Null);
            Assert.That(actual.OriginalSubmitter, Is.EqualTo(submitter));
            Assert.That(actual.CreatedTimeUtc, Is.EqualTo(DateTime.UtcNow).Within(TimeSpan.FromSeconds(3)));
            Assert.That(actual.Submitter, Is.EqualTo(submitter));
            Assert.That(actual.SubmissionTimeUtc, Is.EqualTo(DateTime.UtcNow).Within(TimeSpan.FromSeconds(3)));
            Assert.That(actual.Data, Is.Not.Null);
            Assert.That(actual.Data.TryGetElement("source_system", out _), Is.True, "source_system exists");
            Assert.That(actual.Data.TryGetElement("source_table", out _), Is.True, "source_table exists");
            Assert.That(actual.Data.TryGetElement("component_type", out _), Is.True, "component_type exists");
            Assert.That(actual.Data.TryGetElement("is_deleted", out _), Is.True, "is_deleted exists");
        }
Ejemplo n.º 7
0
        public void StatementAsExpected()
        {
            var dataType       = "SqlUnitTestObject1";
            var createdTimeUtc = DateTime.Parse("2019-08-27 01:02:03");
            var container      = new GenericDataContainer(
                "1234",
                "jdoe",
                createdTimeUtc,
                "jdoe",
                createdTimeUtc,
                ApiVersion.Current,
                DataEncoder.Encode(JsonConvert.SerializeObject(new { Name = "Doe", Age = 101.4, TimeUtc = createdTimeUtc })));
            var actual   = SqlInsertStatement.CreateFromContainer(dataType, container);
            var expected = $"INSERT INTO {dataType} (Id, OriginalSubmitter, CreatedTimeUtc, Submitter, SubmissionTimeUtc, Data#Name, Data#Age, Data#TimeUtc) "
                           + "VALUES ('1234', 'jdoe', '2019-08-27 01:02:03', 'jdoe', '2019-08-27 01:02:03', 'Doe', '101.4', '2019-08-27 01:02:03')";

            Assert.That(actual, Is.EqualTo(expected));
        }
Ejemplo n.º 8
0
        private async Task <bool> IsAllowedToOverwriteDataAsync(string dataType, GenericDataContainer existingData, User user)
        {
            if (existingData == null)
            {
                return(true);
            }
            if (existingData.Submitter == user.UserName)
            {
                return(true);
            }
            var overwritingAllowed = await authorizationModule.IsOverwritingAllowedForCollectionAsync(dataType);

            if (overwritingAllowed)
            {
                return(true);
            }
            if (user.Roles.Contains(Role.Admin))
            {
                return(true);
            }
            return(false);
        }
        private static async Task TestStoreGetAndDeleteOfObject <T>(IRdDataStorage sut, string id, T obj, Mock <IRdDataStorage> metadataStorageMock)
        {
            var dataType  = obj.GetType().Name;
            var utcNow    = DateTime.UtcNow;
            var container = new GenericDataContainer(
                id,
                "jdoe",
                utcNow,
                "jdoe",
                utcNow,
                "1.0.0.0",
                DataEncoder.Encode(JsonConvert.SerializeObject(obj)));
            await sut.StoreAsync(obj.GetType().Name, container, true);

            metadataStorageMock.Verify(x => x.StoreAsync(dataType, It.IsAny <GenericDataContainer>(), true), Times.Once);
            Console.WriteLine("Test 1 successful");

            // Test 2: Get
            metadataStorageMock.Setup(x => x.GetFromIdAsync(dataType, id)).Returns(Task.FromResult(container));
            var getResult = await sut.GetFromIdAsync(dataType, id);

            Assert.That(getResult, Is.Not.Null);
            Assert.That(getResult.Id, Is.EqualTo(container.Id));
            Assert.That(getResult.Submitter, Is.EqualTo(container.Submitter));
            Assert.That(getResult.SubmissionTimeUtc, Is.EqualTo(container.SubmissionTimeUtc));
            Assert.That(getResult.ApiVersion, Is.EqualTo(container.ApiVersion));
            Assert.That(getResult.Data.ToString(), Is.EqualTo(container.Data.ToString()));
            Console.WriteLine("Test 2 successful");

            // Test 3: Delete
            var deleteResult = await sut.DeleteDataContainerAsync(dataType, id);

            Assert.That(deleteResult, Is.True);
            Assert.That(await sut.ExistsAsync(dataType, id), Is.False);
            metadataStorageMock.Verify(x => x.DeleteDataContainerAsync(typeof(T).Name, id), Times.Once);
            Console.WriteLine("Test 3 successful");
        }
Ejemplo n.º 10
0
        public async Task <IActionResult> Submit([FromBody] SubmitDataBody body)
        {
            if (!NamingConventions.IsValidDataType(body.DataType))
            {
                return(BadRequest($"Data type '{body.DataType}' is not a valid name for a collection"));
            }
            if (body.Data == null)
            {
                return(BadRequest("No data submitted"));
            }

            // Authorize
            var loggedInUsername    = UsernameNormalizer.Normalize(HttpContext.User.Identity.Name);
            var resourceDescription = new SubmitDataResourceDescription(body.DataType);
            var authorizationResult = await authorizationModule.AuthorizeAsync(resourceDescription, loggedInUsername);

            if (!authorizationResult.IsAuthorized)
            {
                return(StatusCode((int)HttpStatusCode.Unauthorized, "Not authorized"));
            }

            IRdDataStorage rdDataStorage;

            try
            {
                rdDataStorage = await dataRouter.GetSourceSystemAsync(body.DataType);
            }
            catch (KeyNotFoundException)
            {
                return(BadRequest($"No data storage backend for data type '{body.DataType}'"));
            }

            // Validate
            var suggestedId = await idPolicy.DetermineIdAsync(body, loggedInUsername, rdDataStorage);

            if (!rdDataStorage.IsValidId(suggestedId.Id))
            {
                return(BadRequest($"The ID '{suggestedId.Id}' for object of type '{body.DataType}' is not valid"));
            }
            if (body.Overwrite)
            {
                if (string.IsNullOrEmpty(suggestedId.Id))
                {
                    return(BadRequest("Overwriting of existing data is requested, but no ID is provided."));
                }
            }
            var validators = await validatorManager.GetApprovedValidators(body.DataType);

            foreach (var validator in validators)
            {
                try
                {
                    var validationResult = validator.Validate(body.Data.ToString());
                    if (!validationResult.IsValid)
                    {
                        return(new ContentResult
                        {
                            ContentType = Conventions.JsonContentType,
                            Content = JsonConvert.SerializeObject(validationResult),
                            StatusCode = (int)HttpStatusCode.BadRequest
                        });
                    }
                }
                catch (Exception e)
                {
                    apiEventLogger.Log(LogLevel.Error, e.ToString());
                    return(StatusCode((int)HttpStatusCode.InternalServerError, e.Message));
                }
            }

            var existingData = await GetExistingMetadataAsync(rdDataStorage, body.DataType, suggestedId.Id);

            if (body.Overwrite)
            {
                if (!await IsAllowedToOverwriteDataAsync(body.DataType, existingData, authorizationResult.User))
                {
                    return(StatusCode((int)HttpStatusCode.Unauthorized, "Data from other users cannot be overwritten, unless you're an admin"));
                }
            }
            else if (existingData != null && !suggestedId.HasBeenReserved)
            {
                return(Conflict($"Document of type '{body.DataType}' with ID '{suggestedId.Id}' already exists"));
            }

            // Provide
            var apiVersion    = ApiVersion.Current;
            var data          = DataEncoder.Encode(JsonConvert.SerializeObject(body.Data));
            var utcNow        = DateTime.UtcNow;
            var dataContainer = new GenericDataContainer(
                suggestedId.Id,
                existingData?.OriginalSubmitter ?? authorizationResult.User.UserName,
                existingData?.CreatedTimeUtc ?? utcNow,
                authorizationResult.User.UserName,
                utcNow,
                apiVersion,
                data);

            try
            {
                var storeResult = await rdDataStorage.StoreAsync(body.DataType, dataContainer, body.Overwrite || suggestedId.HasBeenReserved);

                apiEventLogger.Log(LogLevel.Info, $"User '{authorizationResult.User.UserName}' has submitted data of type '{body.DataType}' with ID '{suggestedId.Id}'");
                await subscriptionManager.NotifyDataChangedAsync(body.DataType, suggestedId.Id, storeResult.ModificationType);

                if (storeResult.IsNewCollection)
                {
                    newCollectionTasks.PerformTasks(body.DataType, authorizationResult.User);
                }
                return(new ContentResult
                {
                    ContentType = "text/plain",
                    Content = storeResult.Id,
                    StatusCode = (int)HttpStatusCode.OK
                });
            }
            catch (DocumentAlreadyExistsException)
            {
                return(Conflict($"Document of type '{body.DataType}' with ID '{suggestedId.Id}' already exists"));
            }
            catch (Exception e)
            {
                apiEventLogger.Log(LogLevel.Error, e.ToString());
                return(StatusCode((int)HttpStatusCode.InternalServerError, e.Message));
            }
        }