108 lines
4.9 KiB
C#
108 lines
4.9 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using ItWorx.KnowledgeHub.Contracts.Knowledge;
|
|
using ItWorx.KnowledgeHub.IntegrationTests.Infrastructure;
|
|
|
|
namespace ItWorx.KnowledgeHub.IntegrationTests.Knowledge;
|
|
|
|
/// <summary>Every published mutation creates a revision atomically (M3-A01), and a user
|
|
/// can compare/restore past revisions without losing the current version (M3-A02).</summary>
|
|
[Collection(PostgresTestGroup.Name)]
|
|
public sealed class RevisionsTests(PostgresContainerFixture postgres) : OwnerSetupTestBase(postgres)
|
|
{
|
|
[Fact]
|
|
public async Task Publishing_creates_a_new_revision_every_time()
|
|
{
|
|
using var client = Factory.CreateClient();
|
|
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
|
|
|
|
var createResponse = await SetupHelper.PostWithCsrfAsync(
|
|
client, "/api/v1/pages", new CreatePageRequest(null, "Revisiepagina", "WikiPage", "Versie 1", null));
|
|
var page = await createResponse.Content.ReadFromJsonAsync<PageDetail>();
|
|
Assert.NotNull(page);
|
|
|
|
await SetupHelper.PutWithCsrfAsync(
|
|
client,
|
|
$"/api/v1/pages/{page.Id}",
|
|
new UpdatePageRequest("Revisiepagina", "Versie 2", "WikiPage", "Active", "Naar versie 2"),
|
|
page.ETag);
|
|
|
|
var revisions = await client.GetFromJsonAsync<List<PageRevisionSummary>>($"/api/v1/pages/{page.Id}/revisions");
|
|
|
|
Assert.NotNull(revisions);
|
|
Assert.Equal(2, revisions.Count);
|
|
// Most recent first.
|
|
Assert.Equal(2, revisions[0].RevisionNumber);
|
|
Assert.Equal(1, revisions[1].RevisionNumber);
|
|
Assert.Equal("Naar versie 2", revisions[0].ChangeSummary);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Restoring_a_past_revision_creates_a_new_revision_without_losing_history()
|
|
{
|
|
using var client = Factory.CreateClient();
|
|
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
|
|
|
|
var createResponse = await SetupHelper.PostWithCsrfAsync(
|
|
client, "/api/v1/pages", new CreatePageRequest(null, "Titel A", "WikiPage", "Inhoud A", null));
|
|
var page = await createResponse.Content.ReadFromJsonAsync<PageDetail>();
|
|
Assert.NotNull(page);
|
|
|
|
var afterFirstEdit = await SetupHelper.PutWithCsrfAsync(
|
|
client,
|
|
$"/api/v1/pages/{page.Id}",
|
|
new UpdatePageRequest("Titel B", "Inhoud B", "WikiPage", "Active", null),
|
|
page.ETag);
|
|
var pageAfterEdit = await afterFirstEdit.Content.ReadFromJsonAsync<PageDetail>();
|
|
Assert.NotNull(pageAfterEdit);
|
|
Assert.Equal("Titel B", pageAfterEdit.Title);
|
|
|
|
// Fetch the original revision's content before restoring it.
|
|
var originalRevision = await client.GetFromJsonAsync<PageRevisionDetailResponse>($"/api/v1/pages/{page.Id}/revisions/1");
|
|
Assert.NotNull(originalRevision);
|
|
Assert.Equal("Titel A", originalRevision.Title);
|
|
Assert.Equal("Inhoud A", originalRevision.Markdown);
|
|
|
|
var restoreResponse = await SetupHelper.PostWithCsrfAndIfMatchAsync(
|
|
client, $"/api/v1/pages/{page.Id}/revisions/1/restore", (object?)null, pageAfterEdit.ETag);
|
|
Assert.Equal(HttpStatusCode.OK, restoreResponse.StatusCode);
|
|
|
|
var restored = await restoreResponse.Content.ReadFromJsonAsync<PageDetail>();
|
|
Assert.NotNull(restored);
|
|
Assert.Equal("Titel A", restored.Title);
|
|
Assert.Equal("Inhoud A", restored.Markdown);
|
|
Assert.Equal(3, restored.CurrentRevisionNumber);
|
|
|
|
// History is never rewritten: all three revisions remain, including the
|
|
// "Titel B" state that briefly existed as the current version.
|
|
var revisions = await client.GetFromJsonAsync<List<PageRevisionSummary>>($"/api/v1/pages/{page.Id}/revisions");
|
|
Assert.NotNull(revisions);
|
|
Assert.Equal(3, revisions.Count);
|
|
Assert.Contains(revisions, revision => revision.RevisionNumber == 2 && revision.Title == "Titel B");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Restoring_against_a_stale_etag_is_rejected_as_a_conflict()
|
|
{
|
|
using var client = Factory.CreateClient();
|
|
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
|
|
|
|
var createResponse = await SetupHelper.PostWithCsrfAsync(
|
|
client, "/api/v1/pages", new CreatePageRequest(null, "Titel A", "WikiPage", "Inhoud A", null));
|
|
var page = await createResponse.Content.ReadFromJsonAsync<PageDetail>();
|
|
Assert.NotNull(page);
|
|
|
|
await SetupHelper.PutWithCsrfAsync(
|
|
client,
|
|
$"/api/v1/pages/{page.Id}",
|
|
new UpdatePageRequest("Titel B", "Inhoud B", "WikiPage", "Active", null),
|
|
page.ETag);
|
|
|
|
// page.ETag is now stale (it was captured before the edit above).
|
|
var restoreResponse = await SetupHelper.PostWithCsrfAndIfMatchAsync(
|
|
client, $"/api/v1/pages/{page.Id}/revisions/1/restore", (object?)null, page.ETag);
|
|
|
|
Assert.Equal(HttpStatusCode.PreconditionFailed, restoreResponse.StatusCode);
|
|
}
|
|
}
|