using PrivaPub.Federation.Actors; using PrivaPub.Models.Jobs; using PrivaPub.Tests.Support; using PrivaPub.Tests.Support.Host; using System.Net; using System.Text.Json.Nodes; namespace PrivaPub.Tests.Http { // Lemmy 1.0's multi-communities and PieFed's feeds are `Feed` actors whose `following` is their communities [Trait("Category", "Integration")] public sealed class MastodonFeedTests : IAsyncLifetime { PrivaPubHost _host; Peer _peer; public async ValueTask InitializeAsync() { Assert.SkipUnless(MongoFixture.Enabled, MongoFixture.Skip); _host = await PrivaPubHost.Shared(); _peer = await Peer.Start(); } public async ValueTask DisposeAsync() { if (_peer != default) await _peer.DisposeAsync(); } [Fact] public async Task A_feed_shows_as_an_account_whose_following_is_its_communities() { var token = TestContext.Current.CancellationToken; var reader = await _host.Mastodon("feeder"); var cats = new RemoteActor(_peer, "cats", type: "Group"); var dogs = new RemoteActor(_peer, "dogs", type: "Group"); var name = $"feed{Guid.NewGuid():N}"[..12]; var feed = $"{_peer.A}/m/{name}"; // as Lemmy serves one: the instance's inbox and key, its text in `description` _peer.Serve($"/m/{name}", new JsonObject { ["@context"] = new JsonArray("https://join-lemmy.org/context.json", "https://www.w3.org/ns/activitystreams"), ["type"] = "Feed", ["id"] = feed, ["inbox"] = $"{_peer.A}/inbox", ["publicKey"] = new JsonObject { ["id"] = $"{_peer.A}/#main-key", ["owner"] = $"{_peer.A}/", ["publicKeyPem"] = "-----BEGIN PUBLIC KEY-----\n-----END PUBLIC KEY-----\n" }, ["following"] = $"{feed}/following", ["preferredUsername"] = name, ["name"] = "Pets", ["description"] = "every pet", ["attributedTo"] = $"{_peer.A}/users/owner" }.ToJsonString()); _peer.Serve($"/m/{name}/following", new JsonObject { ["type"] = "Collection", ["id"] = $"{feed}/following", ["totalItems"] = 2, ["items"] = new JsonArray(cats.Id, dogs.Id) }.ToJsonString()); var account = await _host.Get().GetActor(feed, refresh: true, token); Assert.NotNull(account); await _host.Run(j => j.Kind == JobKind.CountAccount && j.Payload == feed, token); var shown = (await reader.Client.Get($"/api/v1/accounts/{account.ID}")).Ok().Body; Assert.Equal(("Pets", 2), (shown.Text("display_name"), shown.Number("following_count"))); Assert.Contains("every pet", shown.Text("note")); var communities = (await reader.Client.Get($"/api/v1/accounts/{account.ID}/following")).Ok().Array; Assert.Equal(new[] { cats.Id, dogs.Id }, communities.Select(c => c.Text("uri"))); Assert.All(communities, c => Assert.True(c!["group"]!.GetValue())); Assert.Equal(HttpStatusCode.UnprocessableEntity, (await reader.Client.Post($"/api/v1/accounts/{account.ID}/follow")).Status); } } }