78 lines
3.5 KiB
C#
78 lines
3.5 KiB
C#
using MongoDB.Entities;
|
|||
|
|
|
||
|
|
using PrivaPub.Federation.Actors;
|
||
|
|
using PrivaPub.Models.Jobs;
|
||
|
|
using PrivaPub.Models.Post;
|
||
|
|
using PrivaPub.Models.Social;
|
||
|
|
using PrivaPub.Tests.Support;
|
||
|
|
|
||
|
|
using System.Text.Json.Nodes;
|
||
|
|
|
||
|
|
namespace PrivaPub.Tests.Federation
|
||
|
|
{
|
||
|
|
// a follow that holds reads the account's latest public posts from its outbox, so its profile is not empty
|
||
|
|
[Trait("Category", "Integration")]
|
||
|
|
public sealed class BackfillTests : 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();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task An_accepted_follow_reads_the_accounts_latest_public_posts_from_its_outbox()
|
||
|
|
{
|
||
|
|
var token = TestContext.Current.CancellationToken;
|
||
|
|
var (_, alice) = await _harness.Persona("alice");
|
||
|
|
var bob = new RemoteActor(_harness.Peer, "bob");
|
||
|
|
var mallory = new RemoteActor(_harness.Peer, "mallory", _harness.Peer.B);
|
||
|
|
var origin = new Uri(bob.Id).GetLeftPart(UriPartial.Authority);
|
||
|
|
JsonObject Note(string id, string text, RemoteActor author) => new()
|
||
|
|
{
|
||
|
|
["id"] = id, ["type"] = "Note", ["attributedTo"] = author.Id, ["content"] = $"<p>{text}</p>",
|
||
|
|
["to"] = new JsonArray("https://www.w3.org/ns/activitystreams#Public"), ["published"] = DateTime.UtcNow.ToString("O")
|
||
|
|
};
|
||
|
|
var older = $"{origin}/notes/{Guid.NewGuid():N}";
|
||
|
|
var newer = $"{origin}/notes/{Guid.NewGuid():N}";
|
||
|
|
var notBobs = $"{new Uri(mallory.Id).GetLeftPart(UriPartial.Authority)}/notes/{Guid.NewGuid():N}";
|
||
|
|
_harness.Peer.Serve(new Uri(older).AbsolutePath, Note(older, "an older post", bob).ToJsonString());
|
||
|
|
_harness.Peer.Serve(new Uri(newer).AbsolutePath, Note(newer, "a newer post", bob).ToJsonString());
|
||
|
|
_harness.Peer.Serve(new Uri(bob.Id).AbsolutePath + "/outbox", new JsonObject
|
||
|
|
{
|
||
|
|
["id"] = bob.Id + "/outbox", ["type"] = "OrderedCollection", ["totalItems"] = 4,
|
||
|
|
["orderedItems"] = new JsonArray(
|
||
|
|
new JsonObject { ["type"] = "Create", ["object"] = Note(newer, "a newer post", bob) },
|
||
|
|
new JsonObject { ["type"] = "Announce", ["object"] = notBobs },
|
||
|
|
new JsonObject { ["type"] = "Create", ["object"] = notBobs },
|
||
|
|
new JsonObject { ["type"] = "Create", ["object"] = older })
|
||
|
|
}.ToJsonString());
|
||
|
|
var account = await _harness.Remote.GetActor(bob.Id, refresh: false, token);
|
||
|
|
var followId = alice.ActivityUri($"follow-{Guid.NewGuid():N}");
|
||
|
|
await DB.Default.SaveAsync(new Following
|
||
|
|
{
|
||
|
|
AvatarId = alice.Id, TargetActorURI = bob.Id, TargetAccountId = account.ID, State = FollowState.Requested, FollowActivityURI = followId
|
||
|
|
}, token);
|
||
|
|
|
||
|
|
await _harness.Deliver(bob, "/human-centipede", new JsonObject
|
||
|
|
{
|
||
|
|
["id"] = $"{bob.Id}#accept-{Guid.NewGuid():N}", ["type"] = "Accept", ["actor"] = bob.Id,
|
||
|
|
["object"] = new JsonObject { ["id"] = followId, ["type"] = "Follow", ["actor"] = alice.Uri, ["object"] = bob.Id }
|
||
|
|
});
|
||
|
|
var job = await DB.Default.Find<Job>().Match(j => j.Kind == JobKind.BackfillOutbox && j.Payload == bob.Id).ExecuteSingleAsync(token);
|
||
|
|
await new OutboxBackfill(_harness.Db, _harness.Remote, _harness.RemotePosts).Handle(job, token);
|
||
|
|
|
||
|
|
var held = (await DB.Default.Find<Post>().Match(p => p.ActorURI == bob.Id).ExecuteAsync(token)).Select(p => p.ObjectURI).ToHashSet();
|
||
|
|
Assert.Equal(new HashSet<string> { older, newer }, held);
|
||
|
|
Assert.False(await DB.Default.Find<Post>().Match(p => p.ObjectURI == notBobs).ExecuteAnyAsync(token));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|