using MongoDB.Entities; using PrivaPub.ClientModels.Post; using PrivaPub.Federation.Objects; using PrivaPub.Models.Post; using PrivaPub.Tests.Support; using System.Text.Json.Nodes; namespace PrivaPub.Tests.Federation { [Trait("Category", "Integration")] public sealed class InboundRoutingTests : 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 string NewId(RemoteActor actor, string kind) => $"{Origin(actor)}/{kind}/{Guid.NewGuid():N}"; async Task LocalPost(string text) { var (root, alice) = await _harness.Persona("alice"); await _harness.Posts.InsertPost(root, new InsertPostForm { AvatarId = alice.Id, Text = text }, TestContext.Current.CancellationToken); return await DB.Default.Find().Match(p => p.GroupUserId == alice.Id).ExecuteFirstAsync(TestContext.Current.CancellationToken); } [Fact] public async Task A_downvote_counts_and_its_undo_takes_it_back() { var token = TestContext.Current.CancellationToken; var post = await LocalPost("vote on me"); var lemmy = new RemoteActor(_harness.Peer, "voter"); var dislike = new JsonObject { ["id"] = NewId(lemmy, "activities/dislike"), ["type"] = "Dislike", ["actor"] = lemmy.Id, ["object"] = post.ObjectURI }; await _harness.Deliver(lemmy, "/human-centipede", dislike); Assert.Equal(1, (await DB.Default.Find().OneAsync(post.ID, token)).DownvotesCount); await _harness.Deliver(lemmy, "/human-centipede", new JsonObject { ["id"] = NewId(lemmy, "activities/undo"), ["type"] = "Undo", ["actor"] = lemmy.Id, ["object"] = dislike.DeepClone() }); Assert.Equal(0, (await DB.Default.Find().OneAsync(post.ID, token)).DownvotesCount); } [Fact] public async Task A_delete_that_arrives_first_keeps_the_post_from_coming_back() { var token = TestContext.Current.CancellationToken; var (_, alice) = await _harness.Persona("alice"); var mallory = new RemoteActor(_harness.Peer, "mallory"); var noteId = NewId(mallory, "notes"); await _harness.Deliver(mallory, "/human-centipede", new JsonObject { ["id"] = NewId(mallory, "activities/delete"), ["type"] = "Delete", ["actor"] = mallory.Id, ["object"] = new JsonObject { ["id"] = noteId, ["type"] = "Tombstone" } }); await _harness.Deliver(mallory, "/human-centipede", new JsonObject { ["id"] = NewId(mallory, "activities/create"), ["type"] = "Create", ["actor"] = mallory.Id, ["object"] = new JsonObject { ["id"] = noteId, ["type"] = "Note", ["attributedTo"] = mallory.Id, ["content"] = "

late

", ["to"] = new JsonArray(Addressing.Public), ["cc"] = new JsonArray(alice.Uri), ["tag"] = new JsonArray(new JsonObject { ["type"] = "Mention", ["href"] = alice.Uri, ["name"] = "@alice" }) } }); Assert.False(await DB.Default.Find().Match(p => p.ObjectURI == noteId).ExecuteAnyAsync(token)); } [Fact] public async Task A_lemmy_private_message_arrives_as_a_direct_message() { var token = TestContext.Current.CancellationToken; var (_, alice) = await _harness.Persona("alice"); var lemmy = new RemoteActor(_harness.Peer, "pm"); var messageId = NewId(lemmy, "private_message"); await _harness.Deliver(lemmy, "/human-centipede", new JsonObject { ["id"] = NewId(lemmy, "activities/create"), ["type"] = "Create", ["actor"] = lemmy.Id, ["to"] = new JsonArray(alice.Uri), ["object"] = new JsonObject { ["id"] = messageId, ["type"] = "ChatMessage", ["attributedTo"] = lemmy.Id, ["to"] = new JsonArray(alice.Uri), ["content"] = "

psst

", ["mediaType"] = "text/html", ["published"] = DateTime.UtcNow.ToString("O") } }); var message = await DB.Default.Find().Match(p => p.ObjectURI == messageId).ExecuteFirstAsync(token); Assert.NotNull(message); Assert.Equal(PostVisibility.Direct, message.Visibility); Assert.NotNull(message.ConversationId); } [Fact] public async Task A_join_of_a_local_post_is_answered_with_ignore() { var post = await LocalPost("not an event"); var mobilizon = new RemoteActor(_harness.Peer, "joiner"); await _harness.Deliver(mobilizon, "/human-centipede", new JsonObject { ["id"] = NewId(mobilizon, "join"), ["type"] = "Join", ["actor"] = mobilizon.Id, ["object"] = post.ObjectURI }); var answer = Assert.Single(await _harness.Outgoing(mobilizon.Id + "/inbox")); Assert.Equal("Ignore", answer["type"]!.GetValue()); } } }