Pleroma and Akkoma send a post's earlier versions with it. A post PrivaPub first meets after its edits now has its history, and an edit that carries them brings the versions missed in between; each is read as the post itself is. The Akkoma scenario checks a post fetched after two edits by an account no persona follows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
98 lines
3.7 KiB
C#
98 lines
3.7 KiB
C#
using MongoDB.Entities;
|
|
|
|
using PrivaPub.Federation.Objects;
|
|
using PrivaPub.Models.Post;
|
|
using PrivaPub.Models.Social;
|
|
using PrivaPub.Tests.Support;
|
|
|
|
using System.Text.Json.Nodes;
|
|
|
|
namespace PrivaPub.Tests.Federation
|
|
{
|
|
// Pleroma's and Akkoma's edited posts carry their earlier versions (formerRepresentations): a post first met after its
|
|
// edits has its history, and an edit tells the ones missed in between
|
|
[Trait("Category", "Integration")]
|
|
public sealed class FormerRepresentationsTests : IAsyncLifetime
|
|
{
|
|
Harness _harness;
|
|
|
|
public async ValueTask InitializeAsync()
|
|
{
|
|
Assert.SkipUnless(MongoFixture.Enabled, MongoFixture.Skip);
|
|
_harness = await Harness.Start();
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
if (_harness != default)
|
|
await _harness.DisposeAsync();
|
|
}
|
|
|
|
static string Origin(RemoteActor actor) => new Uri(actor.Id).GetLeftPart(UriPartial.Authority);
|
|
static readonly DateTime Start = DateTime.UtcNow.AddHours(-1);
|
|
|
|
static JsonObject Version(string text, int minutes) => new()
|
|
{
|
|
["type"] = "Note", ["content"] = $"<p>{text}</p>", ["published"] = Start.ToString("O"),
|
|
["updated"] = minutes == 0 ? default : Start.AddMinutes(minutes).ToString("O")
|
|
};
|
|
|
|
async Task<(RemoteActor Carol, JsonObject Note)> Followed(string text, int minutes, params JsonObject[] former)
|
|
{
|
|
var token = TestContext.Current.CancellationToken;
|
|
var (_, alice) = await _harness.Persona("alice");
|
|
var carol = new RemoteActor(_harness.Peer, "carol");
|
|
await DB.Default.SaveAsync(new Following { AvatarId = alice.Id, TargetActorURI = carol.Id, State = FollowState.Accepted }, token);
|
|
var note = Version(text, minutes);
|
|
note["id"] = $"{Origin(carol)}/objects/{Guid.NewGuid():N}";
|
|
note["attributedTo"] = carol.Id;
|
|
note["to"] = new JsonArray(Addressing.Public);
|
|
note["cc"] = new JsonArray($"{carol.Id}/followers");
|
|
if (former.Length > 0)
|
|
note["formerRepresentations"] = new JsonObject { ["type"] = "OrderedCollection", ["totalItems"] = former.Length, ["orderedItems"] = new JsonArray(former) };
|
|
return (carol, note);
|
|
}
|
|
|
|
Task Deliver(RemoteActor carol, string type, JsonObject note) => _harness.Deliver(carol, "/human-centipede", new JsonObject
|
|
{
|
|
["id"] = $"{Origin(carol)}/activities/{Guid.NewGuid():N}", ["type"] = type, ["actor"] = carol.Id,
|
|
["to"] = new JsonArray(Addressing.Public), ["object"] = note.DeepClone()
|
|
});
|
|
|
|
Task<Post> Stored(JsonObject note) =>
|
|
DB.Default.Find<Post>().Match(p => p.ObjectURI == note["id"]!.GetValue<string>()).ExecuteSingleAsync(TestContext.Current.CancellationToken);
|
|
|
|
[Fact]
|
|
public async Task A_post_first_met_after_its_edits_has_its_history()
|
|
{
|
|
var (carol, note) = await Followed("third", 40, Version("second", 20), Version("first", 0));
|
|
|
|
await Deliver(carol, "Create", note);
|
|
|
|
var post = await Stored(note);
|
|
Assert.Equal(["<p>first</p>", "<p>second</p>"], post.Revisions.Select(r => r.ContentHtml));
|
|
Assert.Equal("<p>third</p>", post.ContentHtml);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task An_edit_tells_the_versions_missed_in_between()
|
|
{
|
|
var (carol, note) = await Followed("first", 0);
|
|
await Deliver(carol, "Create", note);
|
|
|
|
var edited = (JsonObject)note.DeepClone();
|
|
edited["content"] = "<p>third</p>";
|
|
edited["updated"] = Start.AddMinutes(40).ToString("O");
|
|
edited["formerRepresentations"] = new JsonObject
|
|
{
|
|
["type"] = "OrderedCollection", ["totalItems"] = 2, ["orderedItems"] = new JsonArray(Version("second", 20), Version("first", 0))
|
|
};
|
|
await Deliver(carol, "Update", edited);
|
|
|
|
var post = await Stored(note);
|
|
Assert.Equal(["<p>first</p>", "<p>second</p>"], post.Revisions.Select(r => r.ContentHtml));
|
|
Assert.Equal("<p>third</p>", post.ContentHtml);
|
|
}
|
|
}
|
|
}
|