Reduce factory usage across `spec/services` area (#32098)

pull/32211/head^2
Matt Jankowski 8 months ago committed by GitHub
parent 4fe7f213a6
commit e4e07b1c34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -27,39 +27,35 @@ RSpec.describe AccountStatusesCleanupService do
end end
context 'when given a normal budget of 10' do context 'when given a normal budget of 10' do
it 'reports 3 deleted statuses' do it 'reports 3 deleted statuses and records last deleted id, deletes statuses, preserves recent unrelated statuses' do
expect(subject.call(account_policy, 10)).to eq 3 expect(subject.call(account_policy, 10))
end .to eq(3)
it 'records the last deleted id' do expect(account_policy.last_inspected)
subject.call(account_policy, 10) .to eq [old_status.id, another_old_status.id].max
expect(account_policy.last_inspected).to eq [old_status.id, another_old_status.id].max
end expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id]))
.to be_nil
it 'actually deletes the statuses' do expect { recent_status.reload }
subject.call(account_policy, 10) .to_not raise_error
expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).to be_nil expect { unrelated_status.reload }
expect { recent_status.reload }.to_not raise_error .to_not raise_error
end expect { recent_status.reload }
.to_not raise_error
it 'preserves recent and unrelated statuses' do
subject.call(account_policy, 10)
expect { unrelated_status.reload }.to_not raise_error
expect { recent_status.reload }.to_not raise_error
end end
end end
context 'when called repeatedly with a budget of 2' do context 'when called repeatedly with a budget of 2' do
it 'reports 2 then 1 deleted statuses' do it 'reports 2 then 1 deleted statuses and deletes in expected order' do
expect(subject.call(account_policy, 2)).to eq 2 expect(subject.call(account_policy, 2))
expect(subject.call(account_policy, 2)).to eq 1 .to eq(2)
end expect(Status.find_by(id: very_old_status.id))
.to be_nil
it 'actually deletes the statuses in the expected order' do
subject.call(account_policy, 2) expect(subject.call(account_policy, 2))
expect(Status.find_by(id: very_old_status.id)).to be_nil .to eq(1)
subject.call(account_policy, 2) expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id]))
expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).to be_nil .to be_nil
end end
end end
@ -90,19 +86,24 @@ RSpec.describe AccountStatusesCleanupService do
end end
end end
it 'reports 0 deleted statuses then 0 then 3 then 0 again' do it 'reports 0 deleted statuses then 0 then 3 then 0 again, and keeps id under oldest deletable record' do
expect(subject.call(account_policy, 10)).to eq 0 expect(subject.call(account_policy, 10))
expect(subject.call(account_policy, 10)).to eq 0 .to eq(0)
expect(subject.call(account_policy, 10)).to eq 3 expect(subject.call(account_policy, 10))
expect(subject.call(account_policy, 10)).to eq 0 .to eq(0)
expect(subject.call(account_policy, 10))
.to eq(3)
expect(subject.call(account_policy, 10))
.to eq(0)
expect(account_policy.last_inspected)
.to be < oldest_deletable_record_id
end end
it 'never causes the recorded id to get higher than oldest deletable toot' do def oldest_deletable_record_id
subject.call(account_policy, 10) Mastodon::Snowflake.id_at(
subject.call(account_policy, 10) account_policy.min_status_age.seconds.ago,
subject.call(account_policy, 10) with_random: false
subject.call(account_policy, 10) )
expect(account_policy.last_inspected).to be < Mastodon::Snowflake.id_at(account_policy.min_status_age.seconds.ago, with_random: false)
end end
end end
end end

@ -2,10 +2,6 @@
require 'rails_helper' require 'rails_helper'
def poll_option_json(name, votes)
{ type: 'Note', name: name, replies: { type: 'Collection', totalItems: votes } }
end
RSpec.describe ActivityPub::ProcessStatusUpdateService do RSpec.describe ActivityPub::ProcessStatusUpdateService do
subject { described_class.new } subject { described_class.new }
@ -294,7 +290,6 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
context 'when originally without media attachments' do context 'when originally without media attachments' do
before do before do
stub_request(:get, 'https://example.com/foo.png').to_return(body: attachment_fixture('emojo.png')) stub_request(:get, 'https://example.com/foo.png').to_return(body: attachment_fixture('emojo.png'))
subject.call(status, json, json)
end end
let(:payload) do let(:payload) do
@ -310,19 +305,18 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
} }
end end
it 'updates media attachments' do it 'updates media attachments, fetches attachment, records media change in edit' do
media_attachment = status.reload.ordered_media_attachments.first subject.call(status, json, json)
expect(media_attachment).to_not be_nil expect(status.reload.ordered_media_attachments.first)
expect(media_attachment.remote_url).to eq 'https://example.com/foo.png' .to be_present
end .and(have_attributes(remote_url: 'https://example.com/foo.png'))
it 'fetches the attachment' do expect(a_request(:get, 'https://example.com/foo.png'))
expect(a_request(:get, 'https://example.com/foo.png')).to have_been_made .to have_been_made
end
it 'records media change in edit' do expect(status.edits.reload.last.ordered_media_attachment_ids)
expect(status.edits.reload.last.ordered_media_attachment_ids).to_not be_empty .to_not be_empty
end end
end end
@ -344,27 +338,26 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
before do before do
allow(RedownloadMediaWorker).to receive(:perform_async) allow(RedownloadMediaWorker).to receive(:perform_async)
subject.call(status, json, json)
end end
it 'updates the existing media attachment in-place' do it 'updates the existing media attachment in-place, does not queue redownload, updates media, records media change' do
media_attachment = status.media_attachments.ordered.reload.first subject.call(status, json, json)
expect(media_attachment).to_not be_nil expect(status.media_attachments.ordered.reload.first)
expect(media_attachment.remote_url).to eq 'https://example.com/foo.png' .to be_present
expect(media_attachment.description).to eq 'A picture' .and have_attributes(
end remote_url: 'https://example.com/foo.png',
description: 'A picture'
)
it 'does not queue redownload for the existing media attachment' do expect(RedownloadMediaWorker)
expect(RedownloadMediaWorker).to_not have_received(:perform_async) .to_not have_received(:perform_async)
end
it 'updates media attachments' do expect(status.ordered_media_attachments.map(&:remote_url))
expect(status.ordered_media_attachments.map(&:remote_url)).to eq %w(https://example.com/foo.png) .to eq %w(https://example.com/foo.png)
end
it 'records media change in edit' do expect(status.edits.reload.last.ordered_media_attachment_ids)
expect(status.edits.reload.last.ordered_media_attachment_ids).to_not be_empty .to_not be_empty
end end
end end
@ -372,10 +365,11 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
before do before do
poll = Fabricate(:poll, status: status) poll = Fabricate(:poll, status: status)
status.update(preloadable_poll: poll) status.update(preloadable_poll: poll)
subject.call(status, json, json)
end end
it 'removes poll and records media change in edit' do it 'removes poll and records media change in edit' do
subject.call(status, json, json)
expect(status.reload.poll).to be_nil expect(status.reload.poll).to be_nil
expect(status.edits.reload.last.poll_options).to be_nil expect(status.edits.reload.last.poll_options).to be_nil
end end
@ -398,15 +392,13 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
} }
end end
before do it 'creates a poll and records media change in edit' do
subject.call(status, json, json) subject.call(status, json, json)
end
it 'creates a poll and records media change in edit' do expect(status.reload.poll)
poll = status.reload.poll .to be_present
.and have_attributes(options: %w(Foo Bar Baz))
expect(poll).to_not be_nil
expect(poll.options).to eq %w(Foo Bar Baz)
expect(status.edits.reload.last.poll_options).to eq %w(Foo Bar Baz) expect(status.edits.reload.last.poll_options).to eq %w(Foo Bar Baz)
end end
end end
@ -419,4 +411,8 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
.to eq '2021-09-08 22:39:25 UTC' .to eq '2021-09-08 22:39:25 UTC'
end end
end end
def poll_option_json(name, votes)
{ type: 'Note', name: name, replies: { type: 'Collection', totalItems: votes } }
end
end end

@ -12,15 +12,15 @@ RSpec.describe AuthorizeFollowService do
before do before do
FollowRequest.create(account: bob, target_account: sender) FollowRequest.create(account: bob, target_account: sender)
subject.call(bob, sender)
end end
it 'removes follow request' do it 'removes follow request and creates follow relation' do
expect(bob.requested?(sender)).to be false subject.call(bob, sender)
end
it 'creates follow relation' do expect(bob)
expect(bob.following?(sender)).to be true .to_not be_requested(sender)
expect(bob)
.to be_following(sender)
end end
end end
@ -30,19 +30,17 @@ RSpec.describe AuthorizeFollowService do
before do before do
FollowRequest.create(account: bob, target_account: sender) FollowRequest.create(account: bob, target_account: sender)
stub_request(:post, bob.inbox_url).to_return(status: 200) stub_request(:post, bob.inbox_url).to_return(status: 200)
subject.call(bob, sender)
end end
it 'removes follow request' do it 'removes follow request, creates follow relation, send accept activity', :inline_jobs do
expect(bob.requested?(sender)).to be false subject.call(bob, sender)
end
it 'creates follow relation' do
expect(bob.following?(sender)).to be true
end
it 'sends an accept activity', :inline_jobs do expect(bob)
expect(a_request(:post, bob.inbox_url)).to have_been_made.once .to_not be_requested(sender)
expect(bob)
.to be_following(sender)
expect(a_request(:post, bob.inbox_url))
.to have_been_made.once
end end
end end
end end

@ -24,32 +24,38 @@ RSpec.describe BatchedRemoveStatusService, :inline_jobs do
status_alice_hello status_alice_hello
status_alice_other status_alice_other
end
it 'removes status records, removes from author and local follower feeds, notifies stream, sends delete' do
subject.call([status_alice_hello, status_alice_other]) subject.call([status_alice_hello, status_alice_other])
end
it 'removes statuses' do expect { Status.find(status_alice_hello.id) }
expect { Status.find(status_alice_hello.id) }.to raise_error ActiveRecord::RecordNotFound .to raise_error ActiveRecord::RecordNotFound
expect { Status.find(status_alice_other.id) }.to raise_error ActiveRecord::RecordNotFound expect { Status.find(status_alice_other.id) }
end .to raise_error ActiveRecord::RecordNotFound
it 'removes statuses from author\'s home feed' do expect(feed_ids_for(alice))
expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id) .to_not include(status_alice_hello.id, status_alice_other.id)
end
it 'removes statuses from local follower\'s home feed' do expect(feed_ids_for(jeff))
expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id) .to_not include(status_alice_hello.id, status_alice_other.id)
end
it 'notifies streaming API of followers' do expect(redis)
expect(redis).to have_received(:publish).with("timeline:#{jeff.id}", any_args).at_least(:once) .to have_received(:publish)
end .with("timeline:#{jeff.id}", any_args).at_least(:once)
expect(redis)
.to have_received(:publish)
.with('timeline:public', any_args).at_least(:once)
it 'notifies streaming API of public timeline' do expect(a_request(:post, 'http://example.com/inbox'))
expect(redis).to have_received(:publish).with('timeline:public', any_args).at_least(:once) .to have_been_made.at_least_once
end end
it 'sends delete activity to followers' do def feed_ids_for(account)
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.at_least_once HomeFeed
.new(account)
.get(10)
.pluck(:id)
end end
end end

@ -26,15 +26,16 @@ RSpec.describe BlockService do
before do before do
stub_request(:post, 'http://example.com/inbox').to_return(status: 200) stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
subject.call(sender, bob)
end end
it 'creates a blocking relation' do it 'creates a blocking relation and send block activity', :inline_jobs do
expect(sender.blocking?(bob)).to be true subject.call(sender, bob)
end
expect(sender)
.to be_blocking(bob)
it 'sends a block activity', :inline_jobs do expect(a_request(:post, 'http://example.com/inbox'))
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once .to have_been_made.once
end end
end end
end end

@ -24,30 +24,19 @@ RSpec.describe BulkImportService do
].map { |data| import.rows.create!(data: data) } ].map { |data| import.rows.create!(data: data) }
end end
before do before { account.follow!(Fabricate(:account)) }
account.follow!(Fabricate(:account))
end
it 'does not immediately change who the account follows' do
expect { subject.call(import) }.to_not(change { account.reload.active_relationships.to_a })
end
it 'enqueues workers for the expected rows' do it 'does not immediately change who the account follows, enqueues workers, sends follow requests after worker run' do
subject.call(import) expect { subject.call(import) }
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) .to_not(change { account.reload.active_relationships.to_a })
end
it 'requests to follow all the listed users once the workers have run' do
subject.call(import)
resolve_account_service_double = instance_double(ResolveAccountService) expect(row_worker_job_args)
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) .to match_array(rows.map(&:id))
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
Import::RowWorker.drain stub_resolve_account_and_drain_workers
expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }).to contain_exactly('user@foo.bar', 'unknown@unknown.bar') expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct })
.to contain_exactly('user@foo.bar', 'unknown@unknown.bar')
end end
end end
@ -71,31 +60,20 @@ RSpec.describe BulkImportService do
account.follow!(to_be_unfollowed) account.follow!(to_be_unfollowed)
end end
it 'unfollows user not present on list' do it 'updates the existing follow relationship as expected and unfollows user not on list, enqueues workers, sends follow reqs after worker run' do
subject.call(import) expect { subject.call(import) }
expect(account.following?(to_be_unfollowed)).to be false .to change { Follow.where(account: account, target_account: followed).pick(:show_reblogs, :notify, :languages) }.from([true, false, nil]).to([false, true, ['en']])
end
it 'updates the existing follow relationship as expected' do
expect { subject.call(import) }.to change { Follow.where(account: account, target_account: followed).pick(:show_reblogs, :notify, :languages) }.from([true, false, nil]).to([false, true, ['en']])
end
it 'enqueues workers for the expected rows' do expect(account)
subject.call(import) .to_not be_following(to_be_unfollowed)
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id))
end
it 'requests to follow all the expected users once the workers have run' do
subject.call(import)
resolve_account_service_double = instance_double(ResolveAccountService) expect(row_worker_job_args)
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) .to match_array(rows[1..].map(&:id))
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
Import::RowWorker.drain stub_resolve_account_and_drain_workers
expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }).to contain_exactly('user@foo.bar', 'unknown@unknown.bar') expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct })
.to contain_exactly('user@foo.bar', 'unknown@unknown.bar')
end end
end end
@ -110,30 +88,19 @@ RSpec.describe BulkImportService do
].map { |data| import.rows.create!(data: data) } ].map { |data| import.rows.create!(data: data) }
end end
before do before { account.block!(Fabricate(:account, username: 'already_blocked', domain: 'remote.org')) }
account.block!(Fabricate(:account, username: 'already_blocked', domain: 'remote.org'))
end
it 'does not immediately change who the account blocks' do
expect { subject.call(import) }.to_not(change { account.reload.blocking.to_a })
end
it 'enqueues workers for the expected rows' do it 'does not immediately change who the account blocks, enqueues worker, blocks after run' do
subject.call(import) expect { subject.call(import) }
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) .to_not(change { account.reload.blocking.to_a })
end
it 'blocks all the listed users once the workers have run' do
subject.call(import)
resolve_account_service_double = instance_double(ResolveAccountService) expect(row_worker_job_args)
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) .to match_array(rows.map(&:id))
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
Import::RowWorker.drain stub_resolve_account_and_drain_workers
expect(account.blocking.map(&:acct)).to contain_exactly('already_blocked@remote.org', 'user@foo.bar', 'unknown@unknown.bar') expect(account.reload.blocking.map(&:acct))
.to contain_exactly('already_blocked@remote.org', 'user@foo.bar', 'unknown@unknown.bar')
end end
end end
@ -157,27 +124,18 @@ RSpec.describe BulkImportService do
account.block!(to_be_unblocked) account.block!(to_be_unblocked)
end end
it 'unblocks user not present on list' do it 'unblocks user not present on list, enqueues worker, requests follow after run' do
subject.call(import) subject.call(import)
expect(account.blocking?(to_be_unblocked)).to be false
end
it 'enqueues workers for the expected rows' do
subject.call(import)
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id))
end
it 'requests to follow all the expected users once the workers have run' do expect(account.blocking?(to_be_unblocked)).to be false
subject.call(import)
resolve_account_service_double = instance_double(ResolveAccountService) expect(row_worker_job_args)
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) .to match_array(rows[1..].map(&:id))
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
Import::RowWorker.drain stub_resolve_account_and_drain_workers
expect(account.blocking.map(&:acct)).to contain_exactly('blocked@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') expect(account.blocking.map(&:acct))
.to contain_exactly('blocked@foo.bar', 'user@foo.bar', 'unknown@unknown.bar')
end end
end end
@ -192,30 +150,19 @@ RSpec.describe BulkImportService do
].map { |data| import.rows.create!(data: data) } ].map { |data| import.rows.create!(data: data) }
end end
before do before { account.mute!(Fabricate(:account, username: 'already_muted', domain: 'remote.org')) }
account.mute!(Fabricate(:account, username: 'already_muted', domain: 'remote.org'))
end
it 'does not immediately change who the account blocks' do
expect { subject.call(import) }.to_not(change { account.reload.muting.to_a })
end
it 'enqueues workers for the expected rows' do
subject.call(import)
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id))
end
it 'mutes all the listed users once the workers have run' do it 'does not immediately change who the account blocks, enqueures worker, mutes users after worker run' do
subject.call(import) expect { subject.call(import) }
.to_not(change { account.reload.muting.to_a })
resolve_account_service_double = instance_double(ResolveAccountService) expect(row_worker_job_args)
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) .to match_array(rows.map(&:id))
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
Import::RowWorker.drain stub_resolve_account_and_drain_workers
expect(account.muting.map(&:acct)).to contain_exactly('already_muted@remote.org', 'user@foo.bar', 'unknown@unknown.bar') expect(account.reload.muting.map(&:acct))
.to contain_exactly('already_muted@remote.org', 'user@foo.bar', 'unknown@unknown.bar')
end end
end end
@ -239,31 +186,19 @@ RSpec.describe BulkImportService do
account.mute!(to_be_unmuted) account.mute!(to_be_unmuted)
end end
it 'updates the existing mute as expected' do it 'updates the existing mute as expected and unblocks user not on list, and enqueues worker, and requests follow after worker run' do
expect { subject.call(import) }.to change { Mute.where(account: account, target_account: muted).pick(:hide_notifications) }.from(false).to(true) expect { subject.call(import) }
end .to change { Mute.where(account: account, target_account: muted).pick(:hide_notifications) }.from(false).to(true)
it 'unblocks user not present on list' do
subject.call(import)
expect(account.muting?(to_be_unmuted)).to be false expect(account.muting?(to_be_unmuted)).to be false
end
it 'enqueues workers for the expected rows' do
subject.call(import)
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id))
end
it 'requests to follow all the expected users once the workers have run' do
subject.call(import)
resolve_account_service_double = instance_double(ResolveAccountService) expect(row_worker_job_args)
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) .to match_array(rows[1..].map(&:id))
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
Import::RowWorker.drain stub_resolve_account_and_drain_workers
expect(account.muting.map(&:acct)).to contain_exactly('muted@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') expect(account.muting.map(&:acct))
.to contain_exactly('muted@foo.bar', 'user@foo.bar', 'unknown@unknown.bar')
end end
end end
@ -284,13 +219,11 @@ RSpec.describe BulkImportService do
account.block_domain!('blocked.com') account.block_domain!('blocked.com')
end end
it 'blocks all the new domains' do it 'blocks all the new domains and marks import finished' do
subject.call(import) subject.call(import)
expect(account.domain_blocks.pluck(:domain)).to contain_exactly('alreadyblocked.com', 'blocked.com', 'to-block.com')
end
it 'marks the import as finished' do expect(account.domain_blocks.pluck(:domain))
subject.call(import) .to contain_exactly('alreadyblocked.com', 'blocked.com', 'to-block.com')
expect(import.reload.state_finished?).to be true expect(import.reload.state_finished?).to be true
end end
end end
@ -312,14 +245,13 @@ RSpec.describe BulkImportService do
account.block_domain!('blocked.com') account.block_domain!('blocked.com')
end end
it 'blocks all the new domains' do it 'blocks all the new domains and marks import finished' do
subject.call(import) subject.call(import)
expect(account.domain_blocks.pluck(:domain)).to contain_exactly('blocked.com', 'to-block.com')
end
it 'marks the import as finished' do expect(account.domain_blocks.pluck(:domain))
subject.call(import) .to contain_exactly('blocked.com', 'to-block.com')
expect(import.reload.state_finished?).to be true expect(import.reload.state_finished?)
.to be true
end end
end end
@ -347,22 +279,16 @@ RSpec.describe BulkImportService do
account.bookmarks.create!(status: bookmarked) account.bookmarks.create!(status: bookmarked)
end end
it 'enqueues workers for the expected rows' do it 'enqueues workers for the expected rows and updates bookmarks after worker run' do
subject.call(import)
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id))
end
it 'updates the bookmarks as expected once the workers have run' do
subject.call(import) subject.call(import)
service_double = instance_double(ActivityPub::FetchRemoteStatusService) expect(row_worker_job_args)
allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double) .to match_array(rows.map(&:id))
allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') }
allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) }
Import::RowWorker.drain stub_fetch_remote_and_drain_workers
expect(account.bookmarks.map { |bookmark| bookmark.status.uri }).to contain_exactly(already_bookmarked.uri, status.uri, bookmarked.uri, 'https://domain.unknown/foo') expect(account.bookmarks.map { |bookmark| bookmark.status.uri })
.to contain_exactly(already_bookmarked.uri, status.uri, bookmarked.uri, 'https://domain.unknown/foo')
end end
end end
@ -390,23 +316,48 @@ RSpec.describe BulkImportService do
account.bookmarks.create!(status: bookmarked) account.bookmarks.create!(status: bookmarked)
end end
it 'enqueues workers for the expected rows' do it 'enqueues workers for the expected rows and updates bookmarks' do
subject.call(import) subject.call(import)
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id))
expect(row_worker_job_args)
.to match_array(rows.map(&:id))
stub_fetch_remote_and_drain_workers
expect(account.bookmarks.map { |bookmark| bookmark.status.uri })
.to contain_exactly(status.uri, bookmarked.uri, 'https://domain.unknown/foo')
end end
end
it 'updates the bookmarks as expected once the workers have run' do def row_worker_job_args
subject.call(import) Import::RowWorker
.jobs
.pluck('args')
.flatten
end
service_double = instance_double(ActivityPub::FetchRemoteStatusService) def stub_resolve_account_and_drain_workers
allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double) resolve_account_service_double = instance_double(ResolveAccountService)
allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') } allow(ResolveAccountService)
allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) } .to receive(:new)
.and_return(resolve_account_service_double)
allow(resolve_account_service_double)
.to receive(:call)
.with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
allow(resolve_account_service_double)
.to receive(:call)
.with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
Import::RowWorker.drain
end
Import::RowWorker.drain def stub_fetch_remote_and_drain_workers
service_double = instance_double(ActivityPub::FetchRemoteStatusService)
allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double)
allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') }
allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) }
expect(account.bookmarks.map { |bookmark| bookmark.status.uri }).to contain_exactly(status.uri, bookmarked.uri, 'https://domain.unknown/foo') Import::RowWorker.drain
end
end end
end end
end end

@ -11,11 +11,9 @@ RSpec.describe FavouriteService do
let(:bob) { Fabricate(:account) } let(:bob) { Fabricate(:account) }
let(:status) { Fabricate(:status, account: bob) } let(:status) { Fabricate(:status, account: bob) }
before do it 'creates a favourite' do
subject.call(sender, status) subject.call(sender, status)
end
it 'creates a favourite' do
expect(status.favourites.first).to_not be_nil expect(status.favourites.first).to_not be_nil
end end
end end
@ -26,15 +24,16 @@ RSpec.describe FavouriteService do
before do before do
stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {}) stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {})
subject.call(sender, status)
end end
it 'creates a favourite' do it 'creates a favourite and sends like activity', :inline_jobs do
expect(status.favourites.first).to_not be_nil subject.call(sender, status)
end
expect(status.favourites.first)
.to_not be_nil
it 'sends a like activity', :inline_jobs do expect(a_request(:post, 'http://example.com/inbox'))
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once .to have_been_made.once
end end
end end
end end

@ -143,15 +143,16 @@ RSpec.describe FollowService do
before do before do
stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {}) stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {})
subject.call(sender, bob)
end end
it 'creates follow request' do it 'creates follow request and sends an activity to inbox', :inline_jobs do
expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil subject.call(sender, bob)
end
expect(FollowRequest.find_by(account: sender, target_account: bob))
.to_not be_nil
it 'sends a follow activity to the inbox', :inline_jobs do expect(a_request(:post, 'http://example.com/inbox'))
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once .to have_been_made.once
end end
end end
end end

@ -16,20 +16,25 @@ RSpec.describe ProcessMentionsService do
before do before do
account.block!(individually_blocked_account) account.block!(individually_blocked_account)
account.domain_blocks.create!(domain: domain_blocked_account.domain) account.domain_blocks.create!(domain: domain_blocked_account.domain)
end
subject.call(status) it 'creates a mention to the non-blocked account but not the individually or domain blocked accounts' do
expect { subject.call(status) }
.to create_mention_for_non_blocked
.and skip_mention_for_individual
.and skip_mention_for_domain_blocked
end end
it 'creates a mention to the non-blocked account' do def create_mention_for_non_blocked
expect(non_blocked_account.mentions.where(status: status).count).to eq 1 change { non_blocked_account.mentions.where(status: status).count }.to(1)
end end
it 'does not create a mention to the individually blocked account' do def skip_mention_for_individual
expect(individually_blocked_account.mentions.where(status: status).count).to eq 0 not_change { individually_blocked_account.mentions.where(status: status).count }.from(0)
end end
it 'does not create a mention to the domain-blocked account' do def skip_mention_for_domain_blocked
expect(domain_blocked_account.mentions.where(status: status).count).to eq 0 not_change { domain_blocked_account.mentions.where(status: status).count }.from(0)
end end
end end
@ -40,11 +45,9 @@ RSpec.describe ProcessMentionsService do
context 'with a valid remote user' do context 'with a valid remote user' do
let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
before do it 'creates a mention' do
subject.call(status) subject.call(status)
end
it 'creates a mention' do
expect(remote_user.mentions.where(status: status).count).to eq 1 expect(remote_user.mentions.where(status: status).count).to eq 1
end end
end end
@ -53,11 +56,9 @@ RSpec.describe ProcessMentionsService do
let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct} @#{remote_user.acct} @#{remote_user.acct}", visibility: :public) } let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct} @#{remote_user.acct} @#{remote_user.acct}", visibility: :public) }
before do it 'creates exactly one mention' do
subject.call(status, save_records: false) subject.call(status, save_records: false)
end
it 'creates exactly one mention' do
expect(status.mentions.size).to eq 1 expect(status.mentions.size).to eq 1
end end
end end
@ -66,11 +67,9 @@ RSpec.describe ProcessMentionsService do
let!(:remote_user) { Fabricate(:account, username: 'sneak', protocol: :activitypub, domain: 'xn--hresiar-mxa.ch', inbox_url: 'http://example.com/inbox') } let!(:remote_user) { Fabricate(:account, username: 'sneak', protocol: :activitypub, domain: 'xn--hresiar-mxa.ch', inbox_url: 'http://example.com/inbox') }
let!(:status) { Fabricate(:status, account: account, text: 'Hello @sneak@hæresiar.ch') } let!(:status) { Fabricate(:status, account: account, text: 'Hello @sneak@hæresiar.ch') }
before do it 'creates a mention' do
subject.call(status) subject.call(status)
end
it 'creates a mention' do
expect(remote_user.mentions.where(status: status).count).to eq 1 expect(remote_user.mentions.where(status: status).count).to eq 1
end end
end end
@ -79,11 +78,9 @@ RSpec.describe ProcessMentionsService do
let!(:remote_user) { Fabricate(:account, username: 'foo', protocol: :activitypub, domain: 'xn--y9a3aq.xn--y9a3aq', inbox_url: 'http://example.com/inbox') } let!(:remote_user) { Fabricate(:account, username: 'foo', protocol: :activitypub, domain: 'xn--y9a3aq.xn--y9a3aq', inbox_url: 'http://example.com/inbox') }
let!(:status) { Fabricate(:status, account: account, text: 'Hello @foo@հայ.հայ') } let!(:status) { Fabricate(:status, account: account, text: 'Hello @foo@հայ.հայ') }
before do it 'creates a mention' do
subject.call(status) subject.call(status)
end
it 'creates a mention' do
expect(remote_user.mentions.where(status: status).count).to eq 1 expect(remote_user.mentions.where(status: status).count).to eq 1
end end
end end
@ -95,10 +92,11 @@ RSpec.describe ProcessMentionsService do
before do before do
stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 404) stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 404)
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com').to_return(status: 500) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com').to_return(status: 500)
subject.call(status)
end end
it 'creates a mention' do it 'creates a mention' do
subject.call(status)
expect(remote_user.mentions.where(status: status).count).to eq 1 expect(remote_user.mentions.where(status: status).count).to eq 1
end end
end end

@ -10,17 +10,15 @@ RSpec.describe RejectFollowService do
describe 'local' do describe 'local' do
let(:bob) { Fabricate(:account) } let(:bob) { Fabricate(:account) }
before do before { FollowRequest.create(account: bob, target_account: sender) }
FollowRequest.create(account: bob, target_account: sender)
subject.call(bob, sender)
end
it 'removes follow request' do it 'removes follow request and does not create relation' do
expect(bob.requested?(sender)).to be false subject.call(bob, sender)
end
it 'does not create follow relation' do expect(bob)
expect(bob.following?(sender)).to be false .to_not be_requested(sender)
expect(bob)
.to_not be_following(sender)
end end
end end
@ -30,19 +28,17 @@ RSpec.describe RejectFollowService do
before do before do
FollowRequest.create(account: bob, target_account: sender) FollowRequest.create(account: bob, target_account: sender)
stub_request(:post, bob.inbox_url).to_return(status: 200) stub_request(:post, bob.inbox_url).to_return(status: 200)
subject.call(bob, sender)
end
it 'removes follow request' do
expect(bob.requested?(sender)).to be false
end end
it 'does not create follow relation' do it 'removes follow request, does not create relation, sends reject activity', :inline_jobs do
expect(bob.following?(sender)).to be false subject.call(bob, sender)
end
it 'sends a reject activity', :inline_jobs do expect(bob)
expect(a_request(:post, bob.inbox_url)).to have_been_made.once .to_not be_requested(sender)
expect(bob)
.to_not be_following(sender)
expect(a_request(:post, bob.inbox_url))
.to have_been_made.once
end end
end end
end end

@ -10,13 +10,13 @@ RSpec.describe RemoveFromFollowersService do
describe 'local' do describe 'local' do
let(:sender) { Fabricate(:account, username: 'alice') } let(:sender) { Fabricate(:account, username: 'alice') }
before do before { Follow.create(account: sender, target_account: bob) }
Follow.create(account: sender, target_account: bob)
subject.call(bob, sender)
end
it 'does not create follow relation' do it 'does not create follow relation' do
expect(bob.followed_by?(sender)).to be false subject.call(bob, sender)
expect(bob)
.to_not be_followed_by(sender)
end end
end end
@ -26,15 +26,16 @@ RSpec.describe RemoveFromFollowersService do
before do before do
Follow.create(account: sender, target_account: bob) Follow.create(account: sender, target_account: bob)
stub_request(:post, sender.inbox_url).to_return(status: 200) stub_request(:post, sender.inbox_url).to_return(status: 200)
subject.call(bob, sender)
end end
it 'does not create follow relation' do it 'does not create follow relation and sends reject activity', :inline_jobs do
expect(bob.followed_by?(sender)).to be false subject.call(bob, sender)
end
expect(bob)
.to_not be_followed_by(sender)
it 'sends a reject activity', :inline_jobs do expect(a_request(:post, sender.inbox_url))
expect(a_request(:post, sender.inbox_url)).to have_been_made.once .to have_been_made.once
end end
end end
end end

@ -28,42 +28,38 @@ RSpec.describe RemoveStatusService, :inline_jobs do
Fabricate(:status, account: bill, reblog: status, uri: 'hoge') Fabricate(:status, account: bill, reblog: status, uri: 'hoge')
end end
it 'removes status from author\'s home feed' do it 'removes status from notifications and from author and local follower home feeds, publishes to media timeline, sends delete activities' do
subject.call(status)
expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(status.id)
end
it 'removes status from local follower\'s home feed' do
subject.call(status)
expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(status.id)
end
it 'publishes to public media timeline' do
allow(redis).to receive(:publish).with(any_args) allow(redis).to receive(:publish).with(any_args)
subject.call(status) expect { subject.call(status) }
.to remove_status_from_notifications
expect(redis).to have_received(:publish).with('timeline:public:media', Oj.dump(event: :delete, payload: status.id.to_s)) expect(home_feed_ids(alice))
end .to_not include(status.id)
expect(home_feed_ids(jeff))
.to_not include(status.id)
it 'sends Delete activity to followers' do expect(redis)
subject.call(status) .to have_received(:publish).with('timeline:public:media', Oj.dump(event: :delete, payload: status.id.to_s))
expect(delete_delivery(hank, status)) expect(delete_delivery(hank, status))
.to have_been_made.once .to have_been_made.once
end
it 'sends Delete activity to rebloggers' do
subject.call(status)
expect(delete_delivery(bill, status)) expect(delete_delivery(bill, status))
.to have_been_made.once .to have_been_made.once
end end
it 'remove status from notifications' do def home_feed_ids(personage)
expect { subject.call(status) }.to change { HomeFeed
Notification.where(activity_type: 'Favourite', from_account: jeff, account: alice).count .new(personage)
}.from(1).to(0) .get(10)
.pluck(:id)
end
def remove_status_from_notifications
change { Notification.where(activity_type: 'Favourite', from_account: jeff, account: alice).count }
.from(1)
.to(0)
end end
def delete_delivery(target, status) def delete_delivery(target, status)

@ -31,14 +31,13 @@ RSpec.describe ReportService do
context 'when forward is true', :inline_jobs do context 'when forward is true', :inline_jobs do
let(:forward) { true } let(:forward) { true }
it 'sends ActivityPub payload when forward is true' do it 'has a URI and sends ActivityPub payload' do
subject.call(source_account, remote_account, forward: forward)
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made
end
it 'has an uri' do
report = subject.call(source_account, remote_account, forward: forward) report = subject.call(source_account, remote_account, forward: forward)
expect(report.uri).to_not be_nil
expect(report.uri)
.to_not be_nil
expect(a_request(:post, 'http://example.com/inbox'))
.to have_been_made
end end
context 'when reporting a reply on a different remote server' do context 'when reporting a reply on a different remote server' do
@ -122,13 +121,12 @@ RSpec.describe ReportService do
status.mentions.create(account: source_account) status.mentions.create(account: source_account)
end end
it 'creates a report' do it 'creates a report and attaches the DM to the report' do
expect { subject.call }.to change { target_account.targeted_reports.count }.from(0).to(1) expect { subject.call }
end .to change { target_account.targeted_reports.count }.from(0).to(1)
it 'attaches the DM to the report' do expect(target_account.targeted_reports.pluck(:status_ids))
subject.call .to eq [[status.id]]
expect(target_account.targeted_reports.pluck(:status_ids)).to eq [[status.id]]
end end
end end
@ -146,13 +144,12 @@ RSpec.describe ReportService do
status.mentions.create(account: source_account) status.mentions.create(account: source_account)
end end
it 'creates a report' do it 'creates a report and attaches DM to report' do
expect { subject.call }.to change { target_account.targeted_reports.count }.from(0).to(1) expect { subject.call }
end .to change { target_account.targeted_reports.count }.from(0).to(1)
it 'attaches the DM to the report' do expect(target_account.targeted_reports.pluck(:status_ids))
subject.call .to eq [[status.id]]
expect(target_account.targeted_reports.pluck(:status_ids)).to eq [[status.id]]
end end
end end

@ -22,37 +22,38 @@ RSpec.describe ResolveAccountService do
context 'when domain is banned' do context 'when domain is banned' do
before { Fabricate(:domain_block, domain: 'ap.example.com', severity: :suspend) } before { Fabricate(:domain_block, domain: 'ap.example.com', severity: :suspend) }
it 'does not return an account' do it 'does not return an account or make a webfinger query' do
expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to be_nil expect(subject.call('foo@ap.example.com', skip_webfinger: true))
end .to be_nil
expect(webfinger_discovery_request)
it 'does not make a webfinger query' do .to_not have_been_made
subject.call('foo@ap.example.com', skip_webfinger: true)
expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made
end end
end end
context 'when domain is not banned' do context 'when domain is not banned' do
it 'returns the expected account' do it 'returns the expected account and does not make a webfinger query' do
expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to eq remote_account expect(subject.call('foo@ap.example.com', skip_webfinger: true))
end .to eq remote_account
expect(webfinger_discovery_request)
it 'does not make a webfinger query' do .to_not have_been_made
subject.call('foo@ap.example.com', skip_webfinger: true)
expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made
end end
end end
end end
context 'when account is not known' do context 'when account is not known' do
it 'does not return an account' do it 'does not return an account and does not make webfinger query' do
expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to be_nil expect(subject.call('foo@ap.example.com', skip_webfinger: true))
.to be_nil
expect(webfinger_discovery_request)
.to_not have_been_made
end end
end
it 'does not make a webfinger query' do def webfinger_discovery_request
subject.call('foo@ap.example.com', skip_webfinger: true) a_request(
expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made :get,
end 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com'
)
end end
end end
@ -84,13 +85,11 @@ RSpec.describe ResolveAccountService do
allow(AccountDeletionWorker).to receive(:perform_async) allow(AccountDeletionWorker).to receive(:perform_async)
end end
it 'returns nil' do it 'returns nil and queues deletion worker' do
expect(subject.call('hoge@example.com')).to be_nil expect(subject.call('hoge@example.com'))
end .to be_nil
expect(AccountDeletionWorker)
it 'queues account deletion worker' do .to have_received(:perform_async)
subject.call('hoge@example.com')
expect(AccountDeletionWorker).to have_received(:perform_async)
end end
end end
@ -110,9 +109,12 @@ RSpec.describe ResolveAccountService do
it 'returns new remote account' do it 'returns new remote account' do
account = subject.call('Foo@redirected.example.com') account = subject.call('Foo@redirected.example.com')
expect(account.activitypub?).to be true expect(account)
expect(account.acct).to eq 'foo@ap.example.com' .to have_attributes(
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' activitypub?: true,
acct: 'foo@ap.example.com',
inbox_url: 'https://ap.example.com/users/foo/inbox'
)
end end
end end
@ -125,9 +127,12 @@ RSpec.describe ResolveAccountService do
it 'returns new remote account' do it 'returns new remote account' do
account = subject.call('Foo@redirected.example.com') account = subject.call('Foo@redirected.example.com')
expect(account.activitypub?).to be true expect(account)
expect(account.acct).to eq 'foo@ap.example.com' .to have_attributes(
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' activitypub?: true,
acct: 'foo@ap.example.com',
inbox_url: 'https://ap.example.com/users/foo/inbox'
)
end end
end end
@ -161,9 +166,12 @@ RSpec.describe ResolveAccountService do
it 'returns new remote account' do it 'returns new remote account' do
account = subject.call('foo@ap.example.com') account = subject.call('foo@ap.example.com')
expect(account.activitypub?).to be true expect(account)
expect(account.domain).to eq 'ap.example.com' .to have_attributes(
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' activitypub?: true,
domain: 'ap.example.com',
inbox_url: 'https://ap.example.com/users/foo/inbox'
)
end end
context 'with multiple types' do context 'with multiple types' do
@ -174,10 +182,13 @@ RSpec.describe ResolveAccountService do
it 'returns new remote account' do it 'returns new remote account' do
account = subject.call('foo@ap.example.com') account = subject.call('foo@ap.example.com')
expect(account.activitypub?).to be true expect(account)
expect(account.domain).to eq 'ap.example.com' .to have_attributes(
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' activitypub?: true,
expect(account.actor_type).to eq 'Person' domain: 'ap.example.com',
inbox_url: 'https://ap.example.com/users/foo/inbox',
actor_type: 'Person'
)
end end
end end
end end
@ -186,20 +197,21 @@ RSpec.describe ResolveAccountService do
let!(:duplicate) { Fabricate(:account, username: 'foo', domain: 'old.example.com', uri: 'https://ap.example.com/users/foo') } let!(:duplicate) { Fabricate(:account, username: 'foo', domain: 'old.example.com', uri: 'https://ap.example.com/users/foo') }
let!(:status) { Fabricate(:status, account: duplicate, text: 'foo') } let!(:status) { Fabricate(:status, account: duplicate, text: 'foo') }
it 'returns new remote account' do it 'returns new remote account and merges accounts', :inline_jobs do
account = subject.call('foo@ap.example.com') account = subject.call('foo@ap.example.com')
expect(account.activitypub?).to be true expect(account)
expect(account.domain).to eq 'ap.example.com' .to have_attributes(
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' activitypub?: true,
expect(account.uri).to eq 'https://ap.example.com/users/foo' domain: 'ap.example.com',
end inbox_url: 'https://ap.example.com/users/foo/inbox',
uri: 'https://ap.example.com/users/foo'
it 'merges accounts', :inline_jobs do )
account = subject.call('foo@ap.example.com')
expect(status.reload.account_id).to eq account.id expect(status.reload.account_id)
expect(Account.where(uri: account.uri).count).to eq 1 .to eq account.id
expect(Account.where(uri: account.uri).count)
.to eq 1
end end
end end
@ -210,11 +222,15 @@ RSpec.describe ResolveAccountService do
it 'returns new remote account' do it 'returns new remote account' do
account = subject.call('foo@ap.example.com') account = subject.call('foo@ap.example.com')
expect(account.activitypub?).to be true expect(account)
expect(account.domain).to eq 'ap.example.com' .to have_attributes(
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' activitypub?: true,
expect(account.uri).to eq 'https://ap.example.com/users/foo' domain: 'ap.example.com',
expect(status.reload.account).to eq(account) inbox_url: 'https://ap.example.com/users/foo/inbox',
uri: 'https://ap.example.com/users/foo'
)
expect(status.reload.account)
.to eq(account)
end end
end end

@ -51,12 +51,11 @@ RSpec.describe ResolveURLService do
let(:url) { 'https://example.com/@foo/42' } let(:url) { 'https://example.com/@foo/42' }
let(:uri) { 'https://example.com/users/foo/statuses/42' } let(:uri) { 'https://example.com/users/foo/statuses/42' }
it 'returns status by url' do it 'returns status by URL or URI' do
expect(subject.call(url, on_behalf_of: account)).to eq(status) expect(subject.call(url, on_behalf_of: account))
end .to eq(status)
expect(subject.call(uri, on_behalf_of: account))
it 'returns status by uri' do .to eq(status)
expect(subject.call(uri, on_behalf_of: account)).to eq(status)
end end
end end
@ -75,12 +74,11 @@ RSpec.describe ResolveURLService do
let(:url) { 'https://example.com/@foo/42' } let(:url) { 'https://example.com/@foo/42' }
let(:uri) { 'https://example.com/users/foo/statuses/42' } let(:uri) { 'https://example.com/users/foo/statuses/42' }
it 'does not return the status by url' do it 'does not return the status by URL or URI' do
expect(subject.call(url, on_behalf_of: account)).to be_nil expect(subject.call(url, on_behalf_of: account))
end .to be_nil
expect(subject.call(uri, on_behalf_of: account))
it 'does not return the status by uri' do .to be_nil
expect(subject.call(uri, on_behalf_of: account)).to be_nil
end end
end end
@ -107,22 +105,20 @@ RSpec.describe ResolveURLService do
account.follow!(poster) account.follow!(poster)
end end
it 'returns status by url' do it 'returns status by URL or URI' do
expect(subject.call(url, on_behalf_of: account)).to eq(status) expect(subject.call(url, on_behalf_of: account))
end .to eq(status)
expect(subject.call(uri, on_behalf_of: account))
it 'returns status by uri' do .to eq(status)
expect(subject.call(uri, on_behalf_of: account)).to eq(status)
end end
end end
context 'when the account does not follow the poster' do context 'when the account does not follow the poster' do
it 'does not return the status by url' do it 'does not return the status by URL or URI' do
expect(subject.call(url, on_behalf_of: account)).to be_nil expect(subject.call(url, on_behalf_of: account))
end .to be_nil
expect(subject.call(uri, on_behalf_of: account))
it 'does not return the status by uri' do .to be_nil
expect(subject.call(uri, on_behalf_of: account)).to be_nil
end end
end end
end end

@ -32,20 +32,14 @@ RSpec.describe TranslateStatusService do
allow(TranslationService).to receive_messages(configured?: true, configured: translation_service) allow(TranslationService).to receive_messages(configured?: true, configured: translation_service)
end end
it 'returns translated status content' do it 'returns translated status content and source language and provider and original status' do
expect(service.call(status, 'es').content).to eq '<p>Hola</p>' expect(service.call(status, 'es'))
end .to have_attributes(
content: '<p>Hola</p>',
it 'returns source language' do detected_source_language: 'en',
expect(service.call(status, 'es').detected_source_language).to eq 'en' provider: 'Dummy',
end status: status
)
it 'returns translation provider' do
expect(service.call(status, 'es').provider).to eq 'Dummy'
end
it 'returns original status' do
expect(service.call(status, 'es').status).to eq status
end end
describe 'status has content with custom emoji' do describe 'status has content with custom emoji' do
@ -155,26 +149,16 @@ RSpec.describe TranslateStatusService do
let!(:source_texts) { service.send(:source_texts) } let!(:source_texts) { service.send(:source_texts) }
it 'returns formatted poll options' do it 'returns formatted poll options' do
expect(source_texts.size).to eq 3 expect(source_texts)
expect(source_texts.values).to eq %w(<p>Hello</p> Blue Green) .to have_attributes(
end size: 3,
values: %w(<p>Hello</p> Blue Green),
it 'has a first key with content' do keys: contain_exactly(
expect(source_texts.keys.first).to eq :content eq(:content),
end be_a(Poll::Option).and(have_attributes(id: '0', title: 'Blue')),
be_a(Poll::Option).and(have_attributes(id: '1', title: 'Green'))
it 'has the first option in the second key with correct options' do )
option1 = source_texts.keys.second )
expect(option1).to be_a Poll::Option
expect(option1.id).to eq '0'
expect(option1.title).to eq 'Blue'
end
it 'has the second option in the third key with correct options' do
option2 = source_texts.keys.third
expect(option2).to be_a Poll::Option
expect(option2.id).to eq '1'
expect(option2.title).to eq 'Green'
end end
end end
end end

@ -12,26 +12,32 @@ RSpec.describe UnblockDomainService do
let!(:silenced) { Fabricate(:account, domain: 'example.com', silenced_at: domain_block.created_at) } let!(:silenced) { Fabricate(:account, domain: 'example.com', silenced_at: domain_block.created_at) }
let!(:suspended) { Fabricate(:account, domain: 'example.com', suspended_at: domain_block.created_at) } let!(:suspended) { Fabricate(:account, domain: 'example.com', suspended_at: domain_block.created_at) }
it 'unsilences accounts and removes block' do context 'with severity of silence' do
domain_block.update(severity: :silence) before { domain_block.update(severity: :silence) }
subject.call(domain_block) it 'unsilences accounts and removes block' do
expect_deleted_domain_block subject.call(domain_block)
expect(silenced.reload.silenced?).to be false
expect(suspended.reload.suspended?).to be true expect_deleted_domain_block
expect(independently_suspended.reload.suspended?).to be true expect(silenced.reload.silenced?).to be false
expect(independently_silenced.reload.silenced?).to be true expect(suspended.reload.suspended?).to be true
expect(independently_suspended.reload.suspended?).to be true
expect(independently_silenced.reload.silenced?).to be true
end
end end
it 'unsuspends accounts and removes block' do context 'with severity of suspend' do
domain_block.update(severity: :suspend) before { domain_block.update(severity: :suspend) }
subject.call(domain_block) it 'unsuspends accounts and removes block' do
expect_deleted_domain_block subject.call(domain_block)
expect(suspended.reload.suspended?).to be false
expect(silenced.reload.silenced?).to be false expect_deleted_domain_block
expect(independently_suspended.reload.suspended?).to be true expect(suspended.reload.suspended?).to be false
expect(independently_silenced.reload.silenced?).to be true expect(silenced.reload.silenced?).to be false
expect(independently_suspended.reload.suspended?).to be true
expect(independently_silenced.reload.silenced?).to be true
end
end end
end end

@ -10,13 +10,13 @@ RSpec.describe UnblockService do
describe 'local' do describe 'local' do
let(:bob) { Fabricate(:account) } let(:bob) { Fabricate(:account) }
before do before { sender.block!(bob) }
sender.block!(bob)
subject.call(sender, bob)
end
it 'destroys the blocking relation' do it 'destroys the blocking relation' do
expect(sender.blocking?(bob)).to be false subject.call(sender, bob)
expect(sender)
.to_not be_blocking(bob)
end end
end end
@ -26,15 +26,15 @@ RSpec.describe UnblockService do
before do before do
sender.block!(bob) sender.block!(bob)
stub_request(:post, 'http://example.com/inbox').to_return(status: 200) stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
subject.call(sender, bob)
end end
it 'destroys the blocking relation' do it 'destroys the blocking relation and sends unblock activity', :inline_jobs do
expect(sender.blocking?(bob)).to be false subject.call(sender, bob)
end
it 'sends an unblock activity', :inline_jobs do expect(sender)
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once .to_not be_blocking(bob)
expect(a_request(:post, 'http://example.com/inbox'))
.to have_been_made.once
end end
end end
end end

@ -10,13 +10,13 @@ RSpec.describe UnfollowService do
describe 'local' do describe 'local' do
let(:bob) { Fabricate(:account, username: 'bob') } let(:bob) { Fabricate(:account, username: 'bob') }
before do before { sender.follow!(bob) }
sender.follow!(bob)
subject.call(sender, bob)
end
it 'destroys the following relation' do it 'destroys the following relation' do
expect(sender.following?(bob)).to be false subject.call(sender, bob)
expect(sender)
.to_not be_following(bob)
end end
end end
@ -26,15 +26,15 @@ RSpec.describe UnfollowService do
before do before do
sender.follow!(bob) sender.follow!(bob)
stub_request(:post, 'http://example.com/inbox').to_return(status: 200) stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
subject.call(sender, bob)
end end
it 'destroys the following relation' do it 'destroys the following relation and sends unfollow activity' do
expect(sender.following?(bob)).to be false subject.call(sender, bob)
end
it 'sends an unfollow activity' do expect(sender)
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once .to_not be_following(bob)
expect(a_request(:post, 'http://example.com/inbox'))
.to have_been_made.once
end end
end end
@ -44,15 +44,15 @@ RSpec.describe UnfollowService do
before do before do
bob.follow!(sender) bob.follow!(sender)
stub_request(:post, 'http://example.com/inbox').to_return(status: 200) stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
subject.call(bob, sender)
end end
it 'destroys the following relation' do it 'destroys the following relation and sends a reject activity' do
expect(bob.following?(sender)).to be false subject.call(bob, sender)
end
it 'sends a reject activity' do expect(sender)
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once .to_not be_following(bob)
expect(a_request(:post, 'http://example.com/inbox'))
.to have_been_made.once
end end
end end
end end

@ -18,23 +18,19 @@ RSpec.describe UpdateAccountService do
FollowService.new.call(alice, account) FollowService.new.call(alice, account)
FollowService.new.call(bob, account) FollowService.new.call(bob, account)
FollowService.new.call(eve, account) FollowService.new.call(eve, account)
end
it 'auto accepts pending follow requests from appropriate accounts' do
subject.call(account, { locked: false }) subject.call(account, { locked: false })
end
it 'auto-accepts pending follow requests' do expect(alice).to be_following(account)
expect(alice.following?(account)).to be true expect(alice).to_not be_requested(account)
expect(alice.requested?(account)).to be false
end
it 'does not auto-accept pending follow requests from silenced users' do expect(bob).to_not be_following(account)
expect(bob.following?(account)).to be false expect(bob).to be_requested(account)
expect(bob.requested?(account)).to be true
end
it 'auto-accepts pending follow requests from muted users so as to not leak mute' do expect(eve).to be_following(account)
expect(eve.following?(account)).to be true expect(eve).to_not be_requested(account)
expect(eve.requested?(account)).to be false
end end
end end
end end

@ -10,15 +10,15 @@ RSpec.describe UpdateStatusService do
before do before do
allow(ActivityPub::DistributionWorker).to receive(:perform_async) allow(ActivityPub::DistributionWorker).to receive(:perform_async)
subject.call(status, status.account_id, text: 'Foo')
end end
it 'does not create an edit' do it 'does not create an edit or notify anyone' do
expect(status.reload.edits).to be_empty subject.call(status, status.account_id, text: 'Foo')
end
it 'does not notify anyone' do expect(status.reload.edits)
expect(ActivityPub::DistributionWorker).to_not have_received(:perform_async) .to be_empty
expect(ActivityPub::DistributionWorker)
.to_not have_received(:perform_async)
end end
end end
@ -28,18 +28,16 @@ RSpec.describe UpdateStatusService do
before do before do
PreviewCardsStatus.create(status: status, preview_card: preview_card) PreviewCardsStatus.create(status: status, preview_card: preview_card)
subject.call(status, status.account_id, text: 'Bar')
end
it 'updates text' do
expect(status.reload.text).to eq 'Bar'
end end
it 'resets preview card' do it 'updates text, resets card, saves edit history' do
expect(status.reload.preview_card).to be_nil subject.call(status, status.account_id, text: 'Bar')
end
it 'saves edit history' do expect(status.reload)
.to have_attributes(
text: 'Bar',
preview_card: be_nil
)
expect(status.edits.ordered.pluck(:text)).to eq %w(Foo Bar) expect(status.edits.ordered.pluck(:text)).to eq %w(Foo Bar)
end end
end end
@ -50,15 +48,15 @@ RSpec.describe UpdateStatusService do
before do before do
PreviewCardsStatus.create(status: status, preview_card: preview_card) PreviewCardsStatus.create(status: status, preview_card: preview_card)
subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar')
end end
it 'updates content warning' do it 'updates content warning and saves history' do
expect(status.reload.spoiler_text).to eq 'Bar' subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar')
end
it 'saves edit history' do expect(status.reload.spoiler_text)
expect(status.edits.ordered.pluck(:text, :spoiler_text)).to eq [['Foo', ''], ['Foo', 'Bar']] .to eq 'Bar'
expect(status.edits.ordered.pluck(:text, :spoiler_text))
.to eq [['Foo', ''], ['Foo', 'Bar']]
end end
end end
@ -69,23 +67,19 @@ RSpec.describe UpdateStatusService do
before do before do
status.media_attachments << detached_media_attachment status.media_attachments << detached_media_attachment
subject.call(status, status.account_id, text: 'Foo', media_ids: [attached_media_attachment.id.to_s])
end
it 'updates media attachments' do
expect(status.ordered_media_attachments).to eq [attached_media_attachment]
end
it 'does not detach detached media attachments' do
expect(detached_media_attachment.reload.status_id).to eq status.id
end end
it 'attaches attached media attachments' do it 'updates media attachments, handles attachments, saves history' do
expect(attached_media_attachment.reload.status_id).to eq status.id subject.call(status, status.account_id, text: 'Foo', media_ids: [attached_media_attachment.id.to_s])
end
it 'saves edit history' do expect(status.ordered_media_attachments)
expect(status.edits.ordered.pluck(:ordered_media_attachment_ids)).to eq [[detached_media_attachment.id], [attached_media_attachment.id]] .to eq [attached_media_attachment]
expect(detached_media_attachment.reload.status_id)
.to eq status.id
expect(attached_media_attachment.reload.status_id)
.to eq status.id
expect(status.edits.ordered.pluck(:ordered_media_attachment_ids))
.to eq [[detached_media_attachment.id], [attached_media_attachment.id]]
end end
end end
@ -95,19 +89,18 @@ RSpec.describe UpdateStatusService do
before do before do
status.media_attachments << media_attachment status.media_attachments << media_attachment
subject.call(status, status.account_id, text: 'Foo', media_ids: [media_attachment.id.to_s], media_attributes: [{ id: media_attachment.id, description: 'New description' }])
end end
it 'does not detach media attachment' do it 'does not detach media attachment, updates description, and saves history' do
expect(media_attachment.reload.status_id).to eq status.id subject.call(status, status.account_id, text: 'Foo', media_ids: [media_attachment.id.to_s], media_attributes: [{ id: media_attachment.id, description: 'New description' }])
end
it 'updates the media attachment description' do
expect(media_attachment.reload.description).to eq 'New description'
end
it 'saves edit history' do expect(media_attachment.reload)
expect(status.edits.ordered.map { |edit| edit.ordered_media_attachments.map(&:description) }).to eq [['Old description'], ['New description']] .to have_attributes(
status_id: status.id,
description: 'New description'
)
expect(status.edits.ordered.map { |edit| edit.ordered_media_attachments.map(&:description) })
.to eq [['Old description'], ['New description']]
end end
end end
@ -120,28 +113,27 @@ RSpec.describe UpdateStatusService do
before do before do
status.update(poll: poll) status.update(poll: poll)
VoteService.new.call(voter, poll, [0]) VoteService.new.call(voter, poll, [0])
subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i })
end end
it 'updates poll' do it 'updates poll, resets votes, saves history, requeues notifications' do
poll = status.poll.reload subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i })
expect(poll.options).to eq %w(Bar Baz Foo)
end
it 'resets votes' do
poll = status.poll.reload poll = status.poll.reload
expect(poll.votes_count).to eq 0
expect(poll.votes.count).to eq 0
expect(poll.cached_tallies).to eq [0, 0, 0]
end
it 'saves edit history' do expect(poll)
expect(status.edits.ordered.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)] .to have_attributes(
end options: %w(Bar Baz Foo),
votes_count: 0,
cached_tallies: [0, 0, 0]
)
expect(poll.votes.count)
.to eq(0)
it 'requeues expiration notification' do expect(status.edits.ordered.pluck(:poll_options))
poll = status.poll.reload .to eq [%w(Foo Bar), %w(Bar Baz Foo)]
expect(PollExpirationNotifyWorker).to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes)
expect(PollExpirationNotifyWorker)
.to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes)
end end
end end
@ -151,16 +143,13 @@ RSpec.describe UpdateStatusService do
let!(:bob) { Fabricate(:account, username: 'bob') } let!(:bob) { Fabricate(:account, username: 'bob') }
let!(:status) { PostStatusService.new.call(account, text: 'Hello @alice') } let!(:status) { PostStatusService.new.call(account, text: 'Hello @alice') }
before do it 'changes mentions and keeps old as silent' do
subject.call(status, status.account_id, text: 'Hello @bob') subject.call(status, status.account_id, text: 'Hello @bob')
end
it 'changes mentions' do
expect(status.active_mentions.pluck(:account_id)).to eq [bob.id]
end
it 'keeps old mentions as silent mentions' do expect(status.active_mentions.pluck(:account_id))
expect(status.mentions.pluck(:account_id)).to contain_exactly(alice.id, bob.id) .to eq [bob.id]
expect(status.mentions.pluck(:account_id))
.to contain_exactly(alice.id, bob.id)
end end
end end
@ -168,11 +157,9 @@ RSpec.describe UpdateStatusService do
let!(:account) { Fabricate(:account) } let!(:account) { Fabricate(:account) }
let!(:status) { PostStatusService.new.call(account, text: 'Hello #foo') } let!(:status) { PostStatusService.new.call(account, text: 'Hello #foo') }
before do it 'changes tags' do
subject.call(status, status.account_id, text: 'Hello #bar') subject.call(status, status.account_id, text: 'Hello #bar')
end
it 'changes tags' do
expect(status.tags.pluck(:name)).to eq %w(bar) expect(status.tags.pluck(:name)).to eq %w(bar)
end end
end end

Loading…
Cancel
Save