From d98ff3dc97b11f3b1dcfdf2eebf030162145de19 Mon Sep 17 00:00:00 2001 From: Adrian Hall Date: Mon, 6 Jan 2025 09:15:27 -0800 Subject: [PATCH] (#162) Added additional read call at end of replace operation to get current state of object --- .../Controllers/TableController.Create.cs | 3 --- .../Controllers/TableController.Replace.cs | 8 +++++-- .../TableController_Replace_Tests.cs | 2 +- .../Service/Replace_Tests.cs | 11 +++++++--- .../Properties/launchSettings.json | 22 +++---------------- 5 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/CommunityToolkit.Datasync.Server/Controllers/TableController.Create.cs b/src/CommunityToolkit.Datasync.Server/Controllers/TableController.Create.cs index ceb6d6b7..b9b74a42 100644 --- a/src/CommunityToolkit.Datasync.Server/Controllers/TableController.Create.cs +++ b/src/CommunityToolkit.Datasync.Server/Controllers/TableController.Create.cs @@ -27,11 +27,8 @@ public virtual async Task CreateAsync(CancellationToken cancellat Logger.LogInformation("CreateAsync: {entity}", entity.ToJsonString()); await AuthorizeRequestAsync(TableOperation.Create, entity, cancellationToken).ConfigureAwait(false); - await AccessControlProvider.PreCommitHookAsync(TableOperation.Create, entity, cancellationToken).ConfigureAwait(false); - await Repository.CreateAsync(entity, cancellationToken).ConfigureAwait(false); - await PostCommitHookAsync(TableOperation.Create, entity, cancellationToken).ConfigureAwait(false); Logger.LogInformation("CreateAsync: created {entity}", entity.ToJsonString()); diff --git a/src/CommunityToolkit.Datasync.Server/Controllers/TableController.Replace.cs b/src/CommunityToolkit.Datasync.Server/Controllers/TableController.Replace.cs index 32d09571..14ba0e81 100644 --- a/src/CommunityToolkit.Datasync.Server/Controllers/TableController.Replace.cs +++ b/src/CommunityToolkit.Datasync.Server/Controllers/TableController.Replace.cs @@ -53,7 +53,11 @@ public virtual async Task ReplaceAsync([FromRoute] string id, Can await Repository.ReplaceAsync(entity, version, cancellationToken).ConfigureAwait(false); await PostCommitHookAsync(TableOperation.Update, entity, cancellationToken).ConfigureAwait(false); - Logger.LogInformation("ReplaceAsync: replaced {entity}", entity.ToJsonString()); - return Ok(entity); + // Under certain (repository specific) circumstances, the entity may not be modified by the ReplaceAsync + // operation, so we have to do an additional GET to ensure we are getting the right version of the entity + TEntity? updatedEntity = await Repository.ReadAsync(id, cancellationToken).ConfigureAwait(false); + + Logger.LogInformation("ReplaceAsync: replaced {entity}", updatedEntity.ToJsonString()); + return Ok(updatedEntity); } } diff --git a/tests/CommunityToolkit.Datasync.Server.Test/Controllers/TableController_Replace_Tests.cs b/tests/CommunityToolkit.Datasync.Server.Test/Controllers/TableController_Replace_Tests.cs index 8256a87d..3ffcccdb 100644 --- a/tests/CommunityToolkit.Datasync.Server.Test/Controllers/TableController_Replace_Tests.cs +++ b/tests/CommunityToolkit.Datasync.Server.Test/Controllers/TableController_Replace_Tests.cs @@ -181,7 +181,7 @@ public async Task ReplaceAsync_Works(bool includeIfMatch, bool includeLastModifi await accessProvider.Received(1).PostCommitHookAsync(TableOperation.Update, Arg.Any(), Arg.Any()); firedEvents.Should().ContainSingle(); - await repository.Received(1).ReadAsync(entity.Id, Arg.Any()); + await repository.Received(2).ReadAsync(entity.Id, Arg.Any()); await repository.Received(1).ReplaceAsync(Arg.Any(), Arg.Any(), Arg.Any()); } } diff --git a/tests/CommunityToolkit.Datasync.Server.Test/Service/Replace_Tests.cs b/tests/CommunityToolkit.Datasync.Server.Test/Service/Replace_Tests.cs index df7a3575..5f0a0add 100644 --- a/tests/CommunityToolkit.Datasync.Server.Test/Service/Replace_Tests.cs +++ b/tests/CommunityToolkit.Datasync.Server.Test/Service/Replace_Tests.cs @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#define CAPTURE_STRING_JSON + using CommunityToolkit.Datasync.TestCommon; using CommunityToolkit.Datasync.TestCommon.Databases; using CommunityToolkit.Datasync.TestCommon.Models; -using CommunityToolkit.Datasync.TestService.AccessControlProviders; -using Microsoft.AspNetCore.Localization; using System.Net; using System.Net.Http.Json; using System.Text; @@ -24,9 +24,14 @@ public async Task Replace_Returns200() HttpResponseMessage response = await this.client.PutAsJsonAsync($"{this.factory.MovieEndpoint}/{existingMovie.Id}", existingMovie, this.serializerOptions); response.Should().HaveStatusCode(HttpStatusCode.OK); +#if CAPTURE_STRING_JSON + string jsonContent = await response.Content.ReadAsStringAsync(); + ClientMovie clientMovie = JsonSerializer.Deserialize(jsonContent, this.serializerOptions); +#else ClientMovie clientMovie = await response.Content.ReadFromJsonAsync(this.serializerOptions); +#endif + clientMovie.Should().NotBeNull().And.HaveChangedMetadata(existingMovie, this.StartTime).And.BeEquivalentTo(existingMovie); - InMemoryMovie inMemoryMovie = this.factory.GetServerEntityById(clientMovie.Id); clientMovie.Should().HaveEquivalentMetadataTo(inMemoryMovie).And.BeEquivalentTo(inMemoryMovie); response.Headers.ETag.Should().BeETag($"\"{clientMovie.Version}\""); diff --git a/tests/CommunityToolkit.Datasync.TestService/Properties/launchSettings.json b/tests/CommunityToolkit.Datasync.TestService/Properties/launchSettings.json index 8a549371..633e15c9 100644 --- a/tests/CommunityToolkit.Datasync.TestService/Properties/launchSettings.json +++ b/tests/CommunityToolkit.Datasync.TestService/Properties/launchSettings.json @@ -1,19 +1,11 @@ { "$schema": "https://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:6523", - "sslPort": 44367 - } - }, "profiles": { "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "launchUrl": "weatherforecast", + "launchUrl": "api/in-memory/movies", "applicationUrl": "http://localhost:5082", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" @@ -23,16 +15,8 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "launchUrl": "weatherforecast", - "applicationUrl": "https://localhost:7186;http://localhost:5082", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "weatherforecast", + "launchUrl": "api/in-memory/movies", + "applicationUrl": "https://localhost:5001;http://localhost:5082", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }