100 lines
4.4 KiB
C#
100 lines
4.4 KiB
C#
using MongoDB.Entities;
|
|||
|
|
|
||
|
|
using PrivaPub.Models.Post;
|
||
|
|
using PrivaPub.Models.Social;
|
||
|
|
using PrivaPub.Tests.Support;
|
||
|
|
|
||
|
|
using System.Text.Json.Nodes;
|
||
|
|
|
||
|
|
using static PrivaPub.Tests.Support.FederatedSeeds;
|
||
|
|
|
||
|
|
namespace PrivaPub.Tests.Federation
|
||
|
|
{
|
||
|
|
// a persona joins a remote event (owner decision 2026-10-05): Join, answered Accept or Reject; Leave
|
||
|
|
[Trait("Category", "Integration")]
|
||
|
|
public sealed class ParticipationTests : 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();
|
||
|
|
}
|
||
|
|
|
||
|
|
async Task<(PrivaPub.Federation.Actors.LocalActor Alice, RemoteActor Group, Post Event)> Announced(string joinMode = "free")
|
||
|
|
{
|
||
|
|
var token = TestContext.Current.CancellationToken;
|
||
|
|
var (_, alice) = await _harness.Persona("alice");
|
||
|
|
var group = new RemoteActor(_harness.Peer, "group", type: "Group");
|
||
|
|
await Follows(alice.Id, group);
|
||
|
|
var happening = new JsonObject
|
||
|
|
{
|
||
|
|
["id"] = NewId(group, "events"), ["type"] = "Event", ["name"] = "A picnic", ["content"] = "<p>bring bread</p>",
|
||
|
|
["attributedTo"] = group.Id, ["startTime"] = DateTime.UtcNow.AddDays(3).ToString("O"), ["joinMode"] = joinMode,
|
||
|
|
["to"] = new JsonArray(PrivaPub.Federation.Objects.Addressing.Public), ["cc"] = new JsonArray(group.Id + "/followers")
|
||
|
|
};
|
||
|
|
await _harness.Deliver(group, "/human-centipede", Create(group, happening));
|
||
|
|
return (alice, group, await DB.Default.Find<Post>().Match(p => p.ObjectURI == IdOf(happening)).ExecuteSingleAsync(token));
|
||
|
|
}
|
||
|
|
|
||
|
|
Task<Participation> Of(PrivaPub.Federation.Actors.LocalActor alice, Post happening) =>
|
||
|
|
DB.Default.Find<Participation>().Match(p => p.AvatarId == alice.Id && p.PostId == happening.ID).ExecuteFirstAsync(TestContext.Current.CancellationToken);
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task A_persona_joins_an_event_its_server_accepts_and_leaves_it()
|
||
|
|
{
|
||
|
|
var token = TestContext.Current.CancellationToken;
|
||
|
|
var (alice, group, happening) = await Announced();
|
||
|
|
|
||
|
|
Assert.True((await _harness.Participations.Join(alice, happening.ID, token)).Ok);
|
||
|
|
|
||
|
|
var join = Assert.Single(await _harness.Outgoing(group.Id + "/inbox"), a => a["type"]!.GetValue<string>() == "Join");
|
||
|
|
Assert.Equal((alice.Uri, happening.ObjectURI), (join["actor"]!.GetValue<string>(), join["object"]!.GetValue<string>()));
|
||
|
|
Assert.Equal(ParticipationState.Pending, (await Of(alice, happening)).State);
|
||
|
|
|
||
|
|
await _harness.Deliver(group, "/human-centipede", new JsonObject
|
||
|
|
{
|
||
|
|
["id"] = NewId(group, "accepts"), ["type"] = "Accept", ["actor"] = group.Id, ["object"] = join["id"]!.GetValue<string>()
|
||
|
|
});
|
||
|
|
Assert.Equal(ParticipationState.Accepted, (await Of(alice, happening)).State);
|
||
|
|
|
||
|
|
Assert.True((await _harness.Participations.Leave(alice, happening.ID, token)).Ok);
|
||
|
|
Assert.Null(await Of(alice, happening));
|
||
|
|
var leave = Assert.Single(await _harness.Outgoing(group.Id + "/inbox"), a => a["type"]!.GetValue<string>() == "Leave");
|
||
|
|
Assert.Equal(happening.ObjectURI, leave["object"]!.GetValue<string>());
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task A_refusal_counts_an_answer_from_another_server_does_not_and_an_invitation_only_event_is_not_joined()
|
||
|
|
{
|
||
|
|
var token = TestContext.Current.CancellationToken;
|
||
|
|
var (alice, group, happening) = await Announced();
|
||
|
|
await _harness.Participations.Join(alice, happening.ID, token);
|
||
|
|
var join = Assert.Single(await _harness.Outgoing(group.Id + "/inbox"), a => a["type"]!.GetValue<string>() == "Join");
|
||
|
|
|
||
|
|
var stranger = new RemoteActor(_harness.Peer, "stranger", _harness.Peer.B);
|
||
|
|
await _harness.Deliver(stranger, "/human-centipede", new JsonObject
|
||
|
|
{
|
||
|
|
["id"] = NewId(stranger, "accepts"), ["type"] = "Accept", ["actor"] = stranger.Id, ["object"] = join["id"]!.GetValue<string>()
|
||
|
|
});
|
||
|
|
Assert.Equal(ParticipationState.Pending, (await Of(alice, happening)).State);
|
||
|
|
|
||
|
|
await _harness.Deliver(group, "/human-centipede", new JsonObject
|
||
|
|
{
|
||
|
|
["id"] = NewId(group, "rejects"), ["type"] = "Reject", ["actor"] = group.Id,
|
||
|
|
["object"] = new JsonObject { ["id"] = join["id"]!.GetValue<string>(), ["type"] = "Join", ["actor"] = alice.Uri, ["object"] = happening.ObjectURI }
|
||
|
|
});
|
||
|
|
Assert.Equal(ParticipationState.Rejected, (await Of(alice, happening)).State);
|
||
|
|
|
||
|
|
var (carol, _, invitationOnly) = await Announced("invite");
|
||
|
|
Assert.Equal(422, (await _harness.Participations.Join(carol, invitationOnly.ID, token)).Status);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|