diff options
Diffstat (limited to 'spec/lib')
-rw-r--r-- | spec/lib/activitypub/activity/accept_spec.rb | 38 | ||||
-rw-r--r-- | spec/lib/activitypub/activity/announce_spec.rb | 29 | ||||
-rw-r--r-- | spec/lib/activitypub/activity/block_spec.rb | 28 | ||||
-rw-r--r-- | spec/lib/activitypub/activity/create_spec.rb | 221 | ||||
-rw-r--r-- | spec/lib/activitypub/activity/delete_spec.rb | 53 | ||||
-rw-r--r-- | spec/lib/activitypub/activity/follow_spec.rb | 49 | ||||
-rw-r--r-- | spec/lib/activitypub/activity/like_spec.rb | 29 | ||||
-rw-r--r-- | spec/lib/activitypub/activity/reject_spec.rb | 38 | ||||
-rw-r--r-- | spec/lib/activitypub/activity/undo_spec.rb | 107 | ||||
-rw-r--r-- | spec/lib/activitypub/activity/update_spec.rb | 41 | ||||
-rw-r--r-- | spec/lib/activitypub/linked_data_signature_spec.rb | 82 | ||||
-rw-r--r-- | spec/lib/activitypub/tag_manager_spec.rb | 99 | ||||
-rw-r--r-- | spec/lib/formatter_spec.rb | 4 | ||||
-rw-r--r-- | spec/lib/ostatus/atom_serializer_spec.rb | 42 | ||||
-rw-r--r-- | spec/lib/status_finder_spec.rb (renamed from spec/lib/stream_entry_finder_spec.rb) | 24 | ||||
-rw-r--r-- | spec/lib/tag_manager_spec.rb | 15 |
16 files changed, 856 insertions, 43 deletions
diff --git a/spec/lib/activitypub/activity/accept_spec.rb b/spec/lib/activitypub/activity/accept_spec.rb new file mode 100644 index 000000000..6503c83e3 --- /dev/null +++ b/spec/lib/activitypub/activity/accept_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Accept do + let(:sender) { Fabricate(:account) } + let(:recipient) { Fabricate(:account) } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Accept', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: { + id: 'bar', + type: 'Follow', + actor: ActivityPub::TagManager.instance.uri_for(recipient), + object: ActivityPub::TagManager.instance.uri_for(sender), + }, + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + Fabricate(:follow_request, account: recipient, target_account: sender) + subject.perform + end + + it 'creates a follow relationship' do + expect(recipient.following?(sender)).to be true + end + + it 'removes the follow request' do + expect(recipient.requested?(sender)).to be false + end + end +end diff --git a/spec/lib/activitypub/activity/announce_spec.rb b/spec/lib/activitypub/activity/announce_spec.rb new file mode 100644 index 000000000..54dd52a60 --- /dev/null +++ b/spec/lib/activitypub/activity/announce_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Announce do + let(:sender) { Fabricate(:account) } + let(:recipient) { Fabricate(:account) } + let(:status) { Fabricate(:status, account: recipient) } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Announce', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(status), + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + subject.perform + end + + it 'creates a reblog by sender of status' do + expect(sender.reblogged?(status)).to be true + end + end +end diff --git a/spec/lib/activitypub/activity/block_spec.rb b/spec/lib/activitypub/activity/block_spec.rb new file mode 100644 index 000000000..23c8cc31c --- /dev/null +++ b/spec/lib/activitypub/activity/block_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Block do + let(:sender) { Fabricate(:account) } + let(:recipient) { Fabricate(:account) } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Block', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(recipient), + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + subject.perform + end + + it 'creates a block from sender to recipient' do + expect(sender.blocking?(recipient)).to be true + end + end +end diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb new file mode 100644 index 000000000..fcb044ebc --- /dev/null +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -0,0 +1,221 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Create do + let(:sender) { Fabricate(:account, followers_url: 'http://example.com/followers') } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Create', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: object_json, + }.with_indifferent_access + end + + subject { described_class.new(json, sender) } + + before do + stub_request(:get, 'http://example.com/attachment.png').to_return(request_fixture('avatar.txt')) + end + + describe '#perform' do + before do + subject.perform + end + + context 'standalone' do + let(:object_json) do + { + id: 'bar', + type: 'Note', + content: 'Lorem ipsum', + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.text).to eq 'Lorem ipsum' + end + + it 'missing to/cc defaults to direct privacy' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.visibility).to eq 'direct' + end + end + + context 'public' do + let(:object_json) do + { + id: 'bar', + type: 'Note', + content: 'Lorem ipsum', + to: 'https://www.w3.org/ns/activitystreams#Public', + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.visibility).to eq 'public' + end + end + + context 'unlisted' do + let(:object_json) do + { + id: 'bar', + type: 'Note', + content: 'Lorem ipsum', + cc: 'https://www.w3.org/ns/activitystreams#Public', + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.visibility).to eq 'unlisted' + end + end + + context 'private' do + let(:object_json) do + { + id: 'bar', + type: 'Note', + content: 'Lorem ipsum', + to: 'http://example.com/followers', + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.visibility).to eq 'private' + end + end + + context 'direct' do + let(:recipient) { Fabricate(:account) } + + let(:object_json) do + { + id: 'bar', + type: 'Note', + content: 'Lorem ipsum', + to: ActivityPub::TagManager.instance.uri_for(recipient), + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.visibility).to eq 'direct' + end + end + + context 'as a reply' do + let(:original_status) { Fabricate(:status) } + + let(:object_json) do + { + id: 'bar', + type: 'Note', + content: 'Lorem ipsum', + inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status), + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.thread).to eq original_status + expect(status.reply?).to be true + expect(status.in_reply_to_account).to eq original_status.account + expect(status.conversation).to eq original_status.conversation + end + end + + context 'with mentions' do + let(:recipient) { Fabricate(:account) } + + let(:object_json) do + { + id: 'bar', + type: 'Note', + content: 'Lorem ipsum', + tag: [ + { + type: 'Mention', + href: ActivityPub::TagManager.instance.uri_for(recipient), + }, + ], + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.mentions.map(&:account)).to include(recipient) + end + end + + context 'with media attachments' do + let(:object_json) do + { + id: 'bar', + type: 'Note', + content: 'Lorem ipsum', + attachment: [ + { + type: 'Document', + mime_type: 'image/png', + url: 'http://example.com/attachment.png', + }, + ], + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.media_attachments.map(&:remote_url)).to include('http://example.com/attachment.png') + end + end + + context 'with hashtags' do + let(:object_json) do + { + id: 'bar', + type: 'Note', + content: 'Lorem ipsum', + tag: [ + { + type: 'Hashtag', + href: 'http://example.com/blah', + name: '#test', + }, + ], + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.tags.map(&:name)).to include('test') + end + end + end +end diff --git a/spec/lib/activitypub/activity/delete_spec.rb b/spec/lib/activitypub/activity/delete_spec.rb new file mode 100644 index 000000000..38254e31c --- /dev/null +++ b/spec/lib/activitypub/activity/delete_spec.rb @@ -0,0 +1,53 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Delete do + let(:sender) { Fabricate(:account, domain: 'example.com') } + let(:status) { Fabricate(:status, account: sender, uri: 'foobar') } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Delete', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(status), + signature: 'foo', + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + subject.perform + end + + it 'deletes sender\'s status' do + expect(Status.find_by(id: status.id)).to be_nil + end + end + + context 'when the status has been reblogged' do + describe '#perform' do + subject { described_class.new(json, sender) } + let(:reblogger) { Fabricate(:account) } + let(:follower) { Fabricate(:account, username: 'follower', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } + + before do + stub_request(:post, 'http://example.com/inbox').to_return(status: 200) + follower.follow!(reblogger) + Fabricate(:status, account: reblogger, reblog: status) + subject.perform + end + + it 'deletes sender\'s status' do + expect(Status.find_by(id: status.id)).to be_nil + end + + it 'sends delete activity to followers of rebloggers' do + # one for Delete original post, and one for Undo reblog (normal delivery) + expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.twice + end + end + end +end diff --git a/spec/lib/activitypub/activity/follow_spec.rb b/spec/lib/activitypub/activity/follow_spec.rb new file mode 100644 index 000000000..6bbacdbe6 --- /dev/null +++ b/spec/lib/activitypub/activity/follow_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Follow do + let(:sender) { Fabricate(:account) } + let(:recipient) { Fabricate(:account) } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Follow', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(recipient), + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + context 'unlocked account' do + before do + subject.perform + end + + it 'creates a follow from sender to recipient' do + expect(sender.following?(recipient)).to be true + end + + it 'does not create a follow request' do + expect(sender.requested?(recipient)).to be false + end + end + + context 'locked account' do + before do + recipient.update(locked: true) + subject.perform + end + + it 'does not create a follow from sender to recipient' do + expect(sender.following?(recipient)).to be false + end + + it 'creates a follow request' do + expect(sender.requested?(recipient)).to be true + end + end + end +end diff --git a/spec/lib/activitypub/activity/like_spec.rb b/spec/lib/activitypub/activity/like_spec.rb new file mode 100644 index 000000000..b69615a9d --- /dev/null +++ b/spec/lib/activitypub/activity/like_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Like do + let(:sender) { Fabricate(:account) } + let(:recipient) { Fabricate(:account) } + let(:status) { Fabricate(:status, account: recipient) } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Like', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(status), + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + subject.perform + end + + it 'creates a favourite from sender to status' do + expect(sender.favourited?(status)).to be true + end + end +end diff --git a/spec/lib/activitypub/activity/reject_spec.rb b/spec/lib/activitypub/activity/reject_spec.rb new file mode 100644 index 000000000..7fd95bcc6 --- /dev/null +++ b/spec/lib/activitypub/activity/reject_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Reject do + let(:sender) { Fabricate(:account) } + let(:recipient) { Fabricate(:account) } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Reject', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: { + id: 'bar', + type: 'Follow', + actor: ActivityPub::TagManager.instance.uri_for(recipient), + object: ActivityPub::TagManager.instance.uri_for(sender), + }, + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + Fabricate(:follow_request, account: recipient, target_account: sender) + subject.perform + end + + it 'does not create a follow relationship' do + expect(recipient.following?(sender)).to be false + end + + it 'removes the follow request' do + expect(recipient.requested?(sender)).to be false + end + end +end diff --git a/spec/lib/activitypub/activity/undo_spec.rb b/spec/lib/activitypub/activity/undo_spec.rb new file mode 100644 index 000000000..14c68efe5 --- /dev/null +++ b/spec/lib/activitypub/activity/undo_spec.rb @@ -0,0 +1,107 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Undo do + let(:sender) { Fabricate(:account, domain: 'example.com') } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Undo', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: object_json, + }.with_indifferent_access + end + + subject { described_class.new(json, sender) } + + describe '#perform' do + context 'with Announce' do + let(:status) { Fabricate(:status) } + + let(:object_json) do + { + id: 'bar', + type: 'Announce', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(status), + } + end + + before do + Fabricate(:status, reblog: status, account: sender, uri: 'bar') + end + + it 'deletes the reblog' do + subject.perform + expect(sender.reblogged?(status)).to be false + end + end + + context 'with Block' do + let(:recipient) { Fabricate(:account) } + + let(:object_json) do + { + id: 'bar', + type: 'Block', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(recipient), + } + end + + before do + sender.block!(recipient) + end + + it 'deletes block from sender to recipient' do + subject.perform + expect(sender.blocking?(recipient)).to be false + end + end + + context 'with Follow' do + let(:recipient) { Fabricate(:account) } + + let(:object_json) do + { + id: 'bar', + type: 'Follow', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(recipient), + } + end + + before do + sender.follow!(recipient) + end + + it 'deletes follow from sender to recipient' do + subject.perform + expect(sender.following?(recipient)).to be false + end + end + + context 'with Like' do + let(:status) { Fabricate(:status) } + + let(:object_json) do + { + id: 'bar', + type: 'Like', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(status), + } + end + + before do + Fabricate(:favourite, account: sender, status: status) + end + + it 'deletes favourite from sender to status' do + subject.perform + expect(sender.favourited?(status)).to be false + end + end + end +end diff --git a/spec/lib/activitypub/activity/update_spec.rb b/spec/lib/activitypub/activity/update_spec.rb new file mode 100644 index 000000000..0bd6d00d9 --- /dev/null +++ b/spec/lib/activitypub/activity/update_spec.rb @@ -0,0 +1,41 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Update do + let!(:sender) { Fabricate(:account) } + + before do + sender.update!(uri: ActivityPub::TagManager.instance.uri_for(sender)) + end + + let(:modified_sender) do + sender.dup.tap do |modified_sender| + modified_sender.display_name = 'Totally modified now' + end + end + + let(:actor_json) do + ActiveModelSerializers::SerializableResource.new(modified_sender, serializer: ActivityPub::ActorSerializer, key_transform: :camel_lower).as_json + end + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Update', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: actor_json, + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + subject.perform + end + + it 'updates profile' do + expect(sender.reload.display_name).to eq 'Totally modified now' + end + end +end diff --git a/spec/lib/activitypub/linked_data_signature_spec.rb b/spec/lib/activitypub/linked_data_signature_spec.rb new file mode 100644 index 000000000..a4d6fe8c3 --- /dev/null +++ b/spec/lib/activitypub/linked_data_signature_spec.rb @@ -0,0 +1,82 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::LinkedDataSignature do + include JsonLdHelper + + let!(:sender) { Fabricate(:account, uri: 'http://example.com/alice') } + + let(:raw_json) do + { + '@context' => 'https://www.w3.org/ns/activitystreams', + 'id' => 'http://example.com/hello-world', + } + end + + let(:json) { raw_json.merge('signature' => signature) } + + subject { described_class.new(json) } + + describe '#verify_account!' do + context 'when signature matches' do + let(:raw_signature) do + { + 'creator' => 'http://example.com/alice', + 'created' => '2017-09-23T20:21:34Z', + } + end + + let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => sign(sender, raw_signature, raw_json)) } + + it 'returns creator' do + expect(subject.verify_account!).to eq sender + end + end + + context 'when signature is missing' do + let(:signature) { nil } + + it 'returns nil' do + expect(subject.verify_account!).to be_nil + end + end + + context 'when signature is tampered' do + let(:raw_signature) do + { + 'creator' => 'http://example.com/alice', + 'created' => '2017-09-23T20:21:34Z', + } + end + + let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => 's69F3mfddd99dGjmvjdjjs81e12jn121Gkm1') } + + it 'returns nil' do + expect(subject.verify_account!).to be_nil + end + end + end + + describe '#sign!' do + subject { described_class.new(raw_json).sign!(sender) } + + it 'returns a hash' do + expect(subject).to be_a Hash + end + + it 'contains signature' do + expect(subject['signature']).to be_a Hash + expect(subject['signature']['signatureValue']).to be_present + end + + it 'can be verified again' do + expect(described_class.new(subject).verify_account!).to eq sender + end + end + + def sign(from_account, options, document) + options_hash = Digest::SHA256.hexdigest(canonicalize(options.merge('@context' => ActivityPub::LinkedDataSignature::CONTEXT))) + document_hash = Digest::SHA256.hexdigest(canonicalize(document)) + to_be_verified = options_hash + document_hash + Base64.strict_encode64(from_account.keypair.sign(OpenSSL::Digest::SHA256.new, to_be_verified)) + end +end diff --git a/spec/lib/activitypub/tag_manager_spec.rb b/spec/lib/activitypub/tag_manager_spec.rb new file mode 100644 index 000000000..8f7662e24 --- /dev/null +++ b/spec/lib/activitypub/tag_manager_spec.rb @@ -0,0 +1,99 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::TagManager do + include RoutingHelper + + subject { described_class.instance } + + describe '#url_for' do + it 'returns a string' do + account = Fabricate(:account) + expect(subject.url_for(account)).to be_a String + end + end + + describe '#uri_for' do + it 'returns a string' do + account = Fabricate(:account) + expect(subject.uri_for(account)).to be_a String + end + end + + describe '#to' do + it 'returns public collection for public status' do + status = Fabricate(:status, visibility: :public) + expect(subject.to(status)).to eq ['https://www.w3.org/ns/activitystreams#Public'] + end + + it 'returns followers collection for unlisted status' do + status = Fabricate(:status, visibility: :unlisted) + expect(subject.to(status)).to eq [account_followers_url(status.account)] + end + + it 'returns followers collection for private status' do + status = Fabricate(:status, visibility: :private) + expect(subject.to(status)).to eq [account_followers_url(status.account)] + end + + it 'returns URIs of mentions for direct status' do + status = Fabricate(:status, visibility: :direct) + mentioned = Fabricate(:account) + status.mentions.create(account: mentioned) + expect(subject.to(status)).to eq [subject.uri_for(mentioned)] + end + end + + describe '#cc' do + it 'returns followers collection for public status' do + status = Fabricate(:status, visibility: :public) + expect(subject.cc(status)).to eq [account_followers_url(status.account)] + end + + it 'returns public collection for unlisted status' do + status = Fabricate(:status, visibility: :unlisted) + expect(subject.cc(status)).to eq ['https://www.w3.org/ns/activitystreams#Public'] + end + + it 'returns empty array for private status' do + status = Fabricate(:status, visibility: :private) + expect(subject.cc(status)).to eq [] + end + + it 'returns empty array for direct status' do + status = Fabricate(:status, visibility: :direct) + expect(subject.cc(status)).to eq [] + end + + it 'returns URIs of mentions for non-direct status' do + status = Fabricate(:status, visibility: :public) + mentioned = Fabricate(:account) + status.mentions.create(account: mentioned) + expect(subject.cc(status)).to include(subject.uri_for(mentioned)) + end + end + + describe '#local_uri?' do + it 'returns false for non-local URI' do + expect(subject.local_uri?('http://example.com/123')).to be false + end + + it 'returns true for local URIs' do + account = Fabricate(:account) + expect(subject.local_uri?(subject.uri_for(account))).to be true + end + end + + describe '#uri_to_local_id' do + it 'returns the local ID' do + account = Fabricate(:account) + expect(subject.uri_to_local_id(subject.uri_for(account), :username)).to eq account.username + end + end + + describe '#uri_to_resource' do + it 'returns the local resource' do + account = Fabricate(:account) + expect(subject.uri_to_resource(subject.uri_for(account), Account)).to eq account + end + end +end diff --git a/spec/lib/formatter_spec.rb b/spec/lib/formatter_spec.rb index dfe1d8b8f..ab04ccbab 100644 --- a/spec/lib/formatter_spec.rb +++ b/spec/lib/formatter_spec.rb @@ -178,7 +178,7 @@ RSpec.describe Formatter do end context 'with remote status' do - let(:status) { Fabricate(:status, text: 'Beep boop', uri: 'beepboop') } + let(:status) { Fabricate(:status, account: remote_account, text: 'Beep boop') } it 'reformats' do is_expected.to eq 'Beep boop' @@ -226,7 +226,7 @@ RSpec.describe Formatter do end context 'with remote status' do - let(:status) { Fabricate(:status, text: '<script>alert("Hello")</script>', uri: 'beep boop') } + let(:status) { Fabricate(:status, account: remote_account, text: '<script>alert("Hello")</script>') } it 'returns tag-stripped text' do is_expected.to eq '' diff --git a/spec/lib/ostatus/atom_serializer_spec.rb b/spec/lib/ostatus/atom_serializer_spec.rb index b0cb8f019..0451eceeb 100644 --- a/spec/lib/ostatus/atom_serializer_spec.rb +++ b/spec/lib/ostatus/atom_serializer_spec.rb @@ -196,7 +196,7 @@ RSpec.describe OStatus::AtomSerializer do author = OStatus::AtomSerializer.new.author(account) - link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' } + link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' } expect(link[:type]).to eq 'text/html' expect(link[:rel]).to eq 'alternate' expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/@username' @@ -403,10 +403,10 @@ RSpec.describe OStatus::AtomSerializer do it 'returns element whose rendered view triggers creation when processed' do remote_account = Account.create!(username: 'username') - remote_status = Fabricate(:status, account: remote_account) - remote_status.stream_entry.update!(created_at: '2000-01-01T00:00:00Z') + remote_status = Fabricate(:status, account: remote_account, created_at: '2000-01-01T00:00:00Z') entry = OStatus::AtomSerializer.new.entry(remote_status.stream_entry, true) + entry.nodes.delete_if { |node| node[:type] == 'application/activity+json' } # Remove ActivityPub link to simplify test xml = OStatus::AtomSerializer.render(entry).gsub('cb6e6126.ngrok.io', 'remote') remote_status.destroy! @@ -415,12 +415,12 @@ RSpec.describe OStatus::AtomSerializer do account = Account.create!( domain: 'remote', username: 'username', - last_webfingered_at: Time.now.utc, + last_webfingered_at: Time.now.utc ) ProcessFeedService.new.call(xml, account) - expect(Status.find_by(uri: "tag:remote,2000-01-01:objectId=#{remote_status.id}:objectType=Status")).to be_instance_of Status + expect(Status.find_by(uri: "https://remote/users/#{remote_status.account.to_param}/statuses/#{remote_status.id}")).to be_instance_of Status end end @@ -464,12 +464,11 @@ RSpec.describe OStatus::AtomSerializer do end it 'appends id element with unique tag' do - status = Fabricate(:status, reblog_of_id: nil) - status.stream_entry.update!(created_at: '2000-01-01T00:00:00Z') + status = Fabricate(:status, reblog_of_id: nil, created_at: '2000-01-01T00:00:00Z') entry = OStatus::AtomSerializer.new.entry(status.stream_entry) - expect(entry.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(entry.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" end it 'appends published element with created date' do @@ -514,7 +513,7 @@ RSpec.describe OStatus::AtomSerializer do entry = OStatus::AtomSerializer.new.entry(reblog.stream_entry) object = entry.nodes.find { |node| node.name == 'activity:object' } - expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{reblogged.id}:objectType=Status" + expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{reblogged.account.to_param}/statuses/#{reblogged.id}" end it 'does not append activity:object element if target is not present' do @@ -529,9 +528,9 @@ RSpec.describe OStatus::AtomSerializer do entry = OStatus::AtomSerializer.new.entry(status.stream_entry) - link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' } + link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' } expect(link[:type]).to eq 'text/html' - expect(link[:href]).to eq "https://cb6e6126.ngrok.io/users/username/updates/#{status.stream_entry.id}" + expect(link[:href]).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}" end it 'appends link element for itself' do @@ -552,7 +551,7 @@ RSpec.describe OStatus::AtomSerializer do entry = OStatus::AtomSerializer.new.entry(reply_status.stream_entry) in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' } - expect(in_reply_to[:ref]).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{in_reply_to_status.id}:objectType=Status" + expect(in_reply_to[:ref]).to eq "https://cb6e6126.ngrok.io/users/#{in_reply_to_status.account.to_param}/statuses/#{in_reply_to_status.id}" end it 'does not append thr:in-reply-to element if not threaded' do @@ -642,7 +641,7 @@ RSpec.describe OStatus::AtomSerializer do feed = OStatus::AtomSerializer.new.feed(account, []) - link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' } + link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' } expect(link[:type]).to eq 'text/html' expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/@username' end @@ -933,7 +932,7 @@ RSpec.describe OStatus::AtomSerializer do favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite) object = favourite_salmon.nodes.find { |node| node.name == 'activity:object' } - expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" end it 'appends thr:in-reply-to element for status' do @@ -944,7 +943,7 @@ RSpec.describe OStatus::AtomSerializer do favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite) in_reply_to = favourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' } - expect(in_reply_to.ref).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}" end @@ -1033,7 +1032,7 @@ RSpec.describe OStatus::AtomSerializer do unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite) object = unfavourite_salmon.nodes.find { |node| node.name == 'activity:object' } - expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" end it 'appends thr:in-reply-to element for status' do @@ -1044,7 +1043,7 @@ RSpec.describe OStatus::AtomSerializer do unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite) in_reply_to = unfavourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' } - expect(in_reply_to.ref).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}" end @@ -1452,7 +1451,7 @@ RSpec.describe OStatus::AtomSerializer do it 'appends id element with URL for status' do status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z') object = OStatus::AtomSerializer.new.object(status) - expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" end it 'appends published element with created date' do @@ -1462,7 +1461,8 @@ RSpec.describe OStatus::AtomSerializer do end it 'appends updated element with updated date' do - status = Fabricate(:status, updated_at: '2000-01-01T00:00:00Z') + status = Fabricate(:status) + status.updated_at = '2000-01-01T00:00:00Z' object = OStatus::AtomSerializer.new.object(status) expect(object.updated.text).to eq '2000-01-01T00:00:00Z' end @@ -1509,7 +1509,7 @@ RSpec.describe OStatus::AtomSerializer do entry = OStatus::AtomSerializer.new.object(status) - link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' } + link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' } expect(link[:type]).to eq 'text/html' expect(link[:href]).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}" end @@ -1522,7 +1522,7 @@ RSpec.describe OStatus::AtomSerializer do entry = OStatus::AtomSerializer.new.object(reply) in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' } - expect(in_reply_to.ref).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{thread.id}:objectType=Status" + expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{thread.account.to_param}/statuses/#{thread.id}" expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{thread.id}" end diff --git a/spec/lib/stream_entry_finder_spec.rb b/spec/lib/status_finder_spec.rb index 64e03c36a..3ef086736 100644 --- a/spec/lib/stream_entry_finder_spec.rb +++ b/spec/lib/status_finder_spec.rb @@ -2,17 +2,17 @@ require 'rails_helper' -describe StreamEntryFinder do +describe StatusFinder do include RoutingHelper - describe '#stream_entry' do + describe '#status' do context 'with a status url' do let(:status) { Fabricate(:status) } let(:url) { short_account_status_url(account_username: status.account.username, id: status.id) } subject { described_class.new(url) } it 'finds the stream entry' do - expect(subject.stream_entry).to eq(status.stream_entry) + expect(subject.status).to eq(status) end it 'raises an error if action is not :show' do @@ -20,7 +20,7 @@ describe StreamEntryFinder do expect(recognized).to receive(:[]).with(:action).and_return(:create) expect(Rails.application.routes).to receive(:recognize_path).with(url).and_return(recognized) - expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound) + expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound) end end @@ -30,7 +30,17 @@ describe StreamEntryFinder do subject { described_class.new(url) } it 'finds the stream entry' do - expect(subject.stream_entry).to eq(stream_entry) + expect(subject.status).to eq(stream_entry.status) + end + end + + context 'with a remote url even if id exists on local' do + let(:status) { Fabricate(:status) } + let(:url) { "https://example.com/users/test/statuses/#{status.id}" } + subject { described_class.new(url) } + + it 'raises an error' do + expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound) end end @@ -39,7 +49,7 @@ describe StreamEntryFinder do subject { described_class.new(url) } it 'raises an error' do - expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound) + expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound) end end @@ -48,7 +58,7 @@ describe StreamEntryFinder do subject { described_class.new(url) } it 'raises an error' do - expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound) + expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound) end end end diff --git a/spec/lib/tag_manager_spec.rb b/spec/lib/tag_manager_spec.rb index 1fae6bec4..1cd6e0a6f 100644 --- a/spec/lib/tag_manager_spec.rb +++ b/spec/lib/tag_manager_spec.rb @@ -157,23 +157,12 @@ RSpec.describe TagManager do describe '#uri_for' do subject { TagManager.instance.uri_for(target) } - context 'activity object' do - let(:target) { Fabricate(:status, reblog: Fabricate(:status)).stream_entry } - - before { target.update!(created_at: '2000-01-01T00:00:00Z') } - - it 'returns the unique tag for status' do - expect(target.object_type).to eq :activity - is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status" - end - end - context 'comment object' do let(:target) { Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reply: true) } it 'returns the unique tag for status' do expect(target.object_type).to eq :comment - is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status" + is_expected.to eq target.uri end end @@ -182,7 +171,7 @@ RSpec.describe TagManager do it 'returns the unique tag for status' do expect(target.object_type).to eq :note - is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status" + is_expected.to eq target.uri end end |