Edit history from formerRepresentations
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
This commit is contained in:
1 parent
02928caac1
commit
679463eb3f
12 files changed
+288
-24
No files matched your search
@@ -0,0 +1,97 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user