Ingestion of remote collection items (#38106)

This commit is contained in:
David Roetzel
2026-03-09 15:59:57 +01:00
committed by GitHub
parent 2c6d072175
commit 1d46558e8d
10 changed files with 399 additions and 60 deletions

View File

@@ -3,78 +3,118 @@
require 'rails_helper'
RSpec.describe ActivityPub::Activity::Add do
let(:sender) { Fabricate(:account, featured_collection_url: 'https://example.com/featured', domain: 'example.com') }
let(:status) { Fabricate(:status, account: sender, visibility: :private) }
context 'when the target is the featured collection' do
let(:sender) { Fabricate(:account, featured_collection_url: 'https://example.com/featured', domain: 'example.com') }
let(:status) { Fabricate(:status, account: sender, visibility: :private) }
let(:json) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'foo',
type: 'Add',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: ActivityPub::TagManager.instance.uri_for(status),
target: sender.featured_collection_url,
}.with_indifferent_access
end
describe '#perform' do
subject { described_class.new(json, sender) }
it 'creates a pin' do
subject.perform
expect(sender.pinned?(status)).to be true
let(:json) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'foo',
type: 'Add',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: ActivityPub::TagManager.instance.uri_for(status),
target: sender.featured_collection_url,
}.with_indifferent_access
end
context 'when status was not known before' do
let(:service_stub) { instance_double(ActivityPub::FetchRemoteStatusService) }
describe '#perform' do
subject { described_class.new(json, sender) }
let(:json) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'foo',
type: 'Add',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: 'https://example.com/unknown',
target: sender.featured_collection_url,
}.with_indifferent_access
it 'creates a pin' do
subject.perform
expect(sender.pinned?(status)).to be true
end
before do
allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_stub)
end
context 'when status was not known before' do
let(:service_stub) { instance_double(ActivityPub::FetchRemoteStatusService) }
let(:json) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'foo',
type: 'Add',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: 'https://example.com/unknown',
target: sender.featured_collection_url,
}.with_indifferent_access
end
context 'when there is a local follower' do
before do
account = Fabricate(:account)
account.follow!(sender)
allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_stub)
end
it 'fetches the status and pins it' do
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, **|
expect(uri).to eq 'https://example.com/unknown'
expect(id).to be true
expect(on_behalf_of&.following?(sender)).to be true
status
context 'when there is a local follower' do
before do
account = Fabricate(:account)
account.follow!(sender)
end
subject.perform
expect(service_stub).to have_received(:call)
expect(sender.pinned?(status)).to be true
end
end
context 'when there is no local follower' do
it 'tries to fetch the status' do
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, **|
expect(uri).to eq 'https://example.com/unknown'
expect(id).to be true
expect(on_behalf_of).to be_nil
nil
it 'fetches the status and pins it' do
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, **|
expect(uri).to eq 'https://example.com/unknown'
expect(id).to be true
expect(on_behalf_of&.following?(sender)).to be true
status
end
subject.perform
expect(service_stub).to have_received(:call)
expect(sender.pinned?(status)).to be true
end
end
context 'when there is no local follower' do
it 'tries to fetch the status' do
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, **|
expect(uri).to eq 'https://example.com/unknown'
expect(id).to be true
expect(on_behalf_of).to be_nil
nil
end
subject.perform
expect(service_stub).to have_received(:call)
expect(sender.pinned?(status)).to be false
end
subject.perform
expect(service_stub).to have_received(:call)
expect(sender.pinned?(status)).to be false
end
end
end
end
context 'when the target is a collection', feature: :collections_federation do
subject { described_class.new(activity_json, collection.account) }
let(:collection) { Fabricate(:remote_collection) }
let(:featured_item_json) do
{
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => 'https://other.example.com/featured_item/1',
'type' => 'FeaturedItem',
'featuredObject' => 'https://example.com/actor/1',
'featuredObjectType' => 'Person',
'featureAuthorization' => 'https://example.com/auth/1',
}
end
let(:activity_json) do
{
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Add',
'actor' => collection.account.uri,
'target' => collection.uri,
'object' => featured_item_json,
}
end
let(:stubbed_service) do
instance_double(ActivityPub::ProcessFeaturedItemService, call: true)
end
before do
allow(ActivityPub::ProcessFeaturedItemService).to receive(:new).and_return(stubbed_service)
end
it 'determines the correct collection and calls the service' do
subject.perform
expect(stubbed_service).to have_received(:call).with(collection, featured_item_json)
end
end
end