- JobQueue takes an optional scope, so a test's worker leases and reaps only its own jobs. - The dead-host delivery test runs alone (Exclusive), on its own jobs, and cleans up the breaker rows it trips; the breaker has tests of its own on unique hosts. - Index and migration tests run alone: they drop indexes and rewrite every post. - DomainBlocks.Load replaces reflection and a database-wide block in tests. - Harness.Outgoing sees only deliveries queued since the harness started: Peer ports are reused within a run, which made the circle test flaky. - Two pure-logic tests leave Mongo-gated classes, so CI runs them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ELjqpznMFMNrJoJUj6K5p2
73 lines
2.8 KiB
C#
73 lines
2.8 KiB
C#
using MongoDB.Entities;
|
|
|
|
using PrivaPub.Federation.Objects;
|
|
using PrivaPub.Models.Federation;
|
|
using PrivaPub.Models.Jobs;
|
|
using PrivaPub.Tests.Support;
|
|
|
|
using System.Text.Json.Nodes;
|
|
|
|
namespace PrivaPub.Tests.Federation
|
|
{
|
|
[Trait("Category", "Integration")]
|
|
public sealed class ProvenanceTests : 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 A_delivered_post_keeps_its_raw_object_how_it_came_and_every_edit()
|
|
{
|
|
var token = TestContext.Current.CancellationToken;
|
|
var (_, alice) = await _harness.Persona("alice");
|
|
var mallory = new RemoteActor(_harness.Peer, "mallory");
|
|
var origin = new Uri(mallory.Id).GetLeftPart(UriPartial.Authority);
|
|
var note = new JsonObject
|
|
{
|
|
["id"] = $"{origin}/notes/{Guid.NewGuid():N}",
|
|
["type"] = "Note",
|
|
["attributedTo"] = mallory.Id,
|
|
["content"] = "<p>hi</p>",
|
|
["_misskey_quote"] = $"{origin}/notes/elsewhere",
|
|
["to"] = new JsonArray(Addressing.Public),
|
|
["cc"] = new JsonArray(alice.Uri),
|
|
["tag"] = new JsonArray(new JsonObject { ["type"] = "Mention", ["href"] = alice.Uri, ["name"] = "@alice" })
|
|
};
|
|
var create = new JsonObject { ["id"] = $"{origin}/activities/{Guid.NewGuid():N}", ["type"] = "Create", ["actor"] = mallory.Id, ["object"] = note.DeepClone() };
|
|
|
|
await _harness.Deliver(mallory, "/human-centipede", create);
|
|
var edited = note.DeepClone().AsObject();
|
|
edited["content"] = "<p>hi again</p>";
|
|
edited["updated"] = DateTime.UtcNow.ToString("O");
|
|
await _harness.Deliver(mallory, "/human-centipede", new JsonObject
|
|
{
|
|
["id"] = $"{origin}/activities/{Guid.NewGuid():N}", ["type"] = "Update", ["actor"] = mallory.Id, ["object"] = edited
|
|
});
|
|
|
|
var record = await DB.Default.Find<ObjectRecord>().Match(r => r.ObjectURI == note["id"]!.GetValue<string>()).ExecuteFirstAsync(token);
|
|
Assert.NotNull(record);
|
|
Assert.Equal(ObjectPath.Delivered, record.Path);
|
|
Assert.False(record.Refetched);
|
|
Assert.Equal("shared", record.Inbox);
|
|
Assert.Equal(mallory.KeyId, record.KeyId);
|
|
Assert.Equal(create["id"]!.GetValue<string>(), record.ActivityId);
|
|
Assert.Contains("digest", record.SignedHeaders);
|
|
Assert.Equal("<p>hi</p>", JsonNode.Parse(record.Raw)!["content"]!.GetValue<string>());
|
|
Assert.Contains("legacy-quote", ObjectFeatures.Detect(JsonNode.Parse(record.Raw)!.AsObject()));
|
|
Assert.Equal("<p>hi again</p>", JsonNode.Parse(Assert.Single(record.Revisions).Raw)!["content"]!.GetValue<string>());
|
|
Assert.True(await DB.Default.Find<Job>().Match(j => j.Kind == JobKind.DescribeInstance && j.Payload == record.Host).ExecuteAnyAsync(token));
|
|
}
|
|
}
|
|
}
|