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); }
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); }
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); }
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"); }
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)); }
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"); }
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)); } }