Reduce factory usage across spec/services area (#32098)
				
					
				
			This commit is contained in:
		
							parent
							
								
									4fe7f213a6
								
							
						
					
					
						commit
						e4e07b1c34
					
				| @ -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 |  | ||||||
| 
 | 
 | ||||||
|         it 'actually deletes the statuses' do |           expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])) | ||||||
|           subject.call(account_policy, 10) |             .to be_nil | ||||||
|           expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).to be_nil |           expect { recent_status.reload } | ||||||
|           expect { recent_status.reload }.to_not raise_error |             .to_not raise_error | ||||||
|         end |           expect { unrelated_status.reload } | ||||||
| 
 |             .to_not raise_error | ||||||
|         it 'preserves recent and unrelated statuses' do |           expect { recent_status.reload } | ||||||
|           subject.call(account_policy, 10) |             .to_not raise_error | ||||||
|           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 |           expect(subject.call(account_policy, 2)) | ||||||
|           subject.call(account_policy, 2) |             .to eq(1) | ||||||
|           expect(Status.find_by(id: very_old_status.id)).to be_nil |           expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])) | ||||||
|           subject.call(account_policy, 2) |             .to be_nil | ||||||
|           expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).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) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'updates the existing media attachment in-place, does not queue redownload, updates media, records media change' do | ||||||
|         subject.call(status, json, json) |         subject.call(status, json, json) | ||||||
|       end |  | ||||||
| 
 | 
 | ||||||
|       it 'updates the existing media attachment in-place' do |         expect(status.media_attachments.ordered.reload.first) | ||||||
|         media_attachment = status.media_attachments.ordered.reload.first |           .to be_present | ||||||
|  |           .and have_attributes( | ||||||
|  |             remote_url: 'https://example.com/foo.png', | ||||||
|  |             description: 'A picture' | ||||||
|  |           ) | ||||||
| 
 | 
 | ||||||
|         expect(media_attachment).to_not be_nil |         expect(RedownloadMediaWorker) | ||||||
|         expect(media_attachment.remote_url).to eq 'https://example.com/foo.png' |           .to_not have_received(:perform_async) | ||||||
|         expect(media_attachment.description).to eq 'A picture' |  | ||||||
|       end |  | ||||||
| 
 | 
 | ||||||
|       it 'does not queue redownload for the existing media attachment' do |         expect(status.ordered_media_attachments.map(&:remote_url)) | ||||||
|         expect(RedownloadMediaWorker).to_not have_received(:perform_async) |           .to eq %w(https://example.com/foo.png) | ||||||
|       end |  | ||||||
| 
 | 
 | ||||||
|       it 'updates media attachments' do |         expect(status.edits.reload.last.ordered_media_attachment_ids) | ||||||
|         expect(status.ordered_media_attachments.map(&:remote_url)).to eq %w(https://example.com/foo.png) |           .to_not be_empty | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       it 'records media change in edit' do |  | ||||||
|         expect(status.edits.reload.last.ordered_media_attachment_ids).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 |  | ||||||
|         subject.call(status, json, json) |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       it 'creates a poll and records media change in edit' do |       it 'creates a poll and records media change in edit' do | ||||||
|         poll = status.reload.poll |         subject.call(status, json, json) | ||||||
|  | 
 | ||||||
|  |         expect(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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'removes follow request and creates follow relation' do | ||||||
|       subject.call(bob, sender) |       subject.call(bob, sender) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'removes follow request' do |       expect(bob) | ||||||
|       expect(bob.requested?(sender)).to be false |         .to_not be_requested(sender) | ||||||
|     end |       expect(bob) | ||||||
| 
 |         .to be_following(sender) | ||||||
|     it 'creates follow relation' do |  | ||||||
|       expect(bob.following?(sender)).to be true |  | ||||||
|     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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'removes follow request, creates follow relation, send accept activity', :inline_jobs do | ||||||
|       subject.call(bob, sender) |       subject.call(bob, sender) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'removes follow request' do |       expect(bob) | ||||||
|       expect(bob.requested?(sender)).to be false |         .to_not be_requested(sender) | ||||||
|     end |       expect(bob) | ||||||
| 
 |         .to be_following(sender) | ||||||
|     it 'creates follow relation' do |       expect(a_request(:post, bob.inbox_url)) | ||||||
|       expect(bob.following?(sender)).to be true |         .to have_been_made.once | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'sends an accept activity', :inline_jobs do |  | ||||||
|       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]) | ||||||
|  | 
 | ||||||
|  |     expect { Status.find(status_alice_hello.id) } | ||||||
|  |       .to raise_error ActiveRecord::RecordNotFound | ||||||
|  |     expect { Status.find(status_alice_other.id) } | ||||||
|  |       .to raise_error ActiveRecord::RecordNotFound | ||||||
|  | 
 | ||||||
|  |     expect(feed_ids_for(alice)) | ||||||
|  |       .to_not include(status_alice_hello.id, status_alice_other.id) | ||||||
|  | 
 | ||||||
|  |     expect(feed_ids_for(jeff)) | ||||||
|  |       .to_not include(status_alice_hello.id, status_alice_other.id) | ||||||
|  | 
 | ||||||
|  |     expect(redis) | ||||||
|  |       .to have_received(:publish) | ||||||
|  |       .with("timeline:#{jeff.id}", any_args).at_least(:once) | ||||||
|  | 
 | ||||||
|  |     expect(redis) | ||||||
|  |       .to have_received(:publish) | ||||||
|  |       .with('timeline:public', any_args).at_least(:once) | ||||||
|  | 
 | ||||||
|  |     expect(a_request(:post, 'http://example.com/inbox')) | ||||||
|  |       .to have_been_made.at_least_once | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   it 'removes statuses' do |   def feed_ids_for(account) | ||||||
|     expect { Status.find(status_alice_hello.id) }.to raise_error ActiveRecord::RecordNotFound |     HomeFeed | ||||||
|     expect { Status.find(status_alice_other.id) }.to raise_error ActiveRecord::RecordNotFound |       .new(account) | ||||||
|   end |       .get(10) | ||||||
| 
 |       .pluck(:id) | ||||||
|   it 'removes statuses from author\'s home feed' do |  | ||||||
|     expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   it 'removes statuses from local follower\'s home feed' do |  | ||||||
|     expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   it 'notifies streaming API of followers' do |  | ||||||
|     expect(redis).to have_received(:publish).with("timeline:#{jeff.id}", any_args).at_least(:once) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   it 'notifies streaming API of public timeline' do |  | ||||||
|     expect(redis).to have_received(:publish).with('timeline:public', any_args).at_least(:once) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   it 'sends delete activity to followers' do |  | ||||||
|     expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.at_least_once |  | ||||||
|   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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'creates a blocking relation and send block activity', :inline_jobs do | ||||||
|       subject.call(sender, bob) |       subject.call(sender, bob) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'creates a blocking relation' do |       expect(sender) | ||||||
|       expect(sender.blocking?(bob)).to be true |         .to be_blocking(bob) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     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 |       it 'does not immediately change who the account follows, enqueues workers, sends follow requests after worker run' do | ||||||
|         expect { subject.call(import) }.to_not(change { account.reload.active_relationships.to_a }) |         expect { subject.call(import) } | ||||||
|       end |           .to_not(change { account.reload.active_relationships.to_a }) | ||||||
| 
 | 
 | ||||||
|       it 'enqueues workers for the expected rows' do |         expect(row_worker_job_args) | ||||||
|         subject.call(import) |           .to match_array(rows.map(&:id)) | ||||||
|         expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) |  | ||||||
|       end |  | ||||||
| 
 | 
 | ||||||
|       it 'requests to follow all the listed users once the workers have run' do |         stub_resolve_account_and_drain_workers | ||||||
|         subject.call(import) |  | ||||||
| 
 | 
 | ||||||
|         resolve_account_service_double = instance_double(ResolveAccountService) |         expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }) | ||||||
|         allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) |           .to contain_exactly('user@foo.bar', 'unknown@unknown.bar') | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
|         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(account) | ||||||
|         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']]) |           .to_not be_following(to_be_unfollowed) | ||||||
|       end |  | ||||||
| 
 | 
 | ||||||
|       it 'enqueues workers for the expected rows' do |         expect(row_worker_job_args) | ||||||
|         subject.call(import) |           .to match_array(rows[1..].map(&:id)) | ||||||
|         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 |         stub_resolve_account_and_drain_workers | ||||||
|         subject.call(import) |  | ||||||
| 
 | 
 | ||||||
|         resolve_account_service_double = instance_double(ResolveAccountService) |         expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }) | ||||||
|         allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) |           .to contain_exactly('user@foo.bar', 'unknown@unknown.bar') | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
|         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 |       it 'does not immediately change who the account blocks, enqueues worker, blocks after run' do | ||||||
|         expect { subject.call(import) }.to_not(change { account.reload.blocking.to_a }) |         expect { subject.call(import) } | ||||||
|       end |           .to_not(change { account.reload.blocking.to_a }) | ||||||
| 
 | 
 | ||||||
|       it 'enqueues workers for the expected rows' do |         expect(row_worker_job_args) | ||||||
|         subject.call(import) |           .to match_array(rows.map(&:id)) | ||||||
|         expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) |  | ||||||
|       end |  | ||||||
| 
 | 
 | ||||||
|       it 'blocks all the listed users once the workers have run' do |         stub_resolve_account_and_drain_workers | ||||||
|         subject.call(import) |  | ||||||
| 
 | 
 | ||||||
|         resolve_account_service_double = instance_double(ResolveAccountService) |         expect(account.reload.blocking.map(&:acct)) | ||||||
|         allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) |           .to contain_exactly('already_blocked@remote.org', 'user@foo.bar', 'unknown@unknown.bar') | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
|         expect(account.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 |         expect(account.blocking?(to_be_unblocked)).to be false | ||||||
|       end |  | ||||||
| 
 | 
 | ||||||
|       it 'enqueues workers for the expected rows' do |         expect(row_worker_job_args) | ||||||
|         subject.call(import) |           .to match_array(rows[1..].map(&:id)) | ||||||
|         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 |         stub_resolve_account_and_drain_workers | ||||||
|         subject.call(import) |  | ||||||
| 
 | 
 | ||||||
|         resolve_account_service_double = instance_double(ResolveAccountService) |         expect(account.blocking.map(&:acct)) | ||||||
|         allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) |           .to contain_exactly('blocked@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
|         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 |       it 'does not immediately change who the account blocks, enqueures worker, mutes users after worker run' do | ||||||
|         expect { subject.call(import) }.to_not(change { account.reload.muting.to_a }) |         expect { subject.call(import) } | ||||||
|       end |           .to_not(change { account.reload.muting.to_a }) | ||||||
| 
 | 
 | ||||||
|       it 'enqueues workers for the expected rows' do |         expect(row_worker_job_args) | ||||||
|         subject.call(import) |           .to match_array(rows.map(&:id)) | ||||||
|         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 |         stub_resolve_account_and_drain_workers | ||||||
|         subject.call(import) |  | ||||||
| 
 | 
 | ||||||
|         resolve_account_service_double = instance_double(ResolveAccountService) |         expect(account.reload.muting.map(&:acct)) | ||||||
|         allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) |           .to contain_exactly('already_muted@remote.org', 'user@foo.bar', 'unknown@unknown.bar') | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
|         expect(account.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 |         expect(row_worker_job_args) | ||||||
|         subject.call(import) |           .to match_array(rows[1..].map(&:id)) | ||||||
|         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 |         stub_resolve_account_and_drain_workers | ||||||
|         subject.call(import) |  | ||||||
| 
 | 
 | ||||||
|         resolve_account_service_double = instance_double(ResolveAccountService) |         expect(account.muting.map(&:acct)) | ||||||
|         allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) |           .to contain_exactly('muted@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
|         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) |  | ||||||
|         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(status.uri, bookmarked.uri, 'https://domain.unknown/foo') |         expect(account.bookmarks.map { |bookmark| bookmark.status.uri }) | ||||||
|  |           .to contain_exactly(status.uri, bookmarked.uri, 'https://domain.unknown/foo') | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | 
 | ||||||
|  |     def row_worker_job_args | ||||||
|  |       Import::RowWorker | ||||||
|  |         .jobs | ||||||
|  |         .pluck('args') | ||||||
|  |         .flatten | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def stub_resolve_account_and_drain_workers | ||||||
|  |       resolve_account_service_double = instance_double(ResolveAccountService) | ||||||
|  |       allow(ResolveAccountService) | ||||||
|  |         .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 | ||||||
|  | 
 | ||||||
|  |     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) } | ||||||
|  | 
 | ||||||
|  |       Import::RowWorker.drain | ||||||
|  |     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 |  | ||||||
|       subject.call(sender, status) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'creates a favourite' do |     it 'creates a favourite' do | ||||||
|  |       subject.call(sender, status) | ||||||
|  | 
 | ||||||
|       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: {}) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'creates a favourite and sends like activity', :inline_jobs do | ||||||
|       subject.call(sender, status) |       subject.call(sender, status) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'creates a favourite' do |       expect(status.favourites.first) | ||||||
|       expect(status.favourites.first).to_not be_nil |         .to_not be_nil | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     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: {}) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'creates follow request and sends an activity to inbox', :inline_jobs do | ||||||
|       subject.call(sender, bob) |       subject.call(sender, bob) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'creates follow request' do |       expect(FollowRequest.find_by(account: sender, target_account: bob)) | ||||||
|       expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil |         .to_not be_nil | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     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) | ||||||
| 
 |  | ||||||
|       subject.call(status) |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'creates a mention to the non-blocked account' do |     it 'creates a mention to the non-blocked account but not the individually or domain blocked accounts' do | ||||||
|       expect(non_blocked_account.mentions.where(status: status).count).to eq 1 |       expect { subject.call(status) } | ||||||
|  |         .to create_mention_for_non_blocked | ||||||
|  |         .and skip_mention_for_individual | ||||||
|  |         .and skip_mention_for_domain_blocked | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'does not create a mention to the individually blocked account' do |     def create_mention_for_non_blocked | ||||||
|       expect(individually_blocked_account.mentions.where(status: status).count).to eq 0 |       change { non_blocked_account.mentions.where(status: status).count }.to(1) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'does not create a mention to the domain-blocked account' do |     def skip_mention_for_individual | ||||||
|       expect(domain_blocked_account.mentions.where(status: status).count).to eq 0 |       not_change { individually_blocked_account.mentions.where(status: status).count }.from(0) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def skip_mention_for_domain_blocked | ||||||
|  |       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 |  | ||||||
|           subject.call(status) |  | ||||||
|         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 | ||||||
| @ -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 |  | ||||||
|           subject.call(status, save_records: false) |  | ||||||
|         end |  | ||||||
| 
 |  | ||||||
|         it 'creates exactly one mention' do |         it 'creates exactly one mention' do | ||||||
|  |           subject.call(status, save_records: false) | ||||||
|  | 
 | ||||||
|           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 |  | ||||||
|           subject.call(status) |  | ||||||
|         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 | ||||||
| @ -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 |  | ||||||
|           subject.call(status) |  | ||||||
|         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 | ||||||
| @ -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) | 
 | ||||||
|  |     it 'removes follow request and does not create relation' do | ||||||
|       subject.call(bob, sender) |       subject.call(bob, sender) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'removes follow request' do |       expect(bob) | ||||||
|       expect(bob.requested?(sender)).to be false |         .to_not be_requested(sender) | ||||||
|     end |       expect(bob) | ||||||
| 
 |         .to_not be_following(sender) | ||||||
|     it 'does not create follow relation' do |  | ||||||
|       expect(bob.following?(sender)).to be false |  | ||||||
|     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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'removes follow request, does not create relation, sends reject activity', :inline_jobs do | ||||||
|       subject.call(bob, sender) |       subject.call(bob, sender) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'removes follow request' do |       expect(bob) | ||||||
|       expect(bob.requested?(sender)).to be false |         .to_not be_requested(sender) | ||||||
|     end |       expect(bob) | ||||||
| 
 |         .to_not be_following(sender) | ||||||
|     it 'does not create follow relation' do |       expect(a_request(:post, bob.inbox_url)) | ||||||
|       expect(bob.following?(sender)).to be false |         .to have_been_made.once | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'sends a reject activity', :inline_jobs do |  | ||||||
|       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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'does not create follow relation and sends reject activity', :inline_jobs do | ||||||
|       subject.call(bob, sender) |       subject.call(bob, sender) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'does not create follow relation' do |       expect(bob) | ||||||
|       expect(bob.followed_by?(sender)).to be false |         .to_not be_followed_by(sender) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     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 |       expect(status.reload.account_id) | ||||||
|       account = subject.call('foo@ap.example.com') |         .to eq account.id | ||||||
| 
 |       expect(Account.where(uri: account.uri).count) | ||||||
|       expect(status.reload.account_id).to eq account.id |         .to eq 1 | ||||||
|       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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'destroys the blocking relation and sends unblock activity', :inline_jobs do | ||||||
|       subject.call(sender, bob) |       subject.call(sender, bob) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'destroys the blocking relation' do |       expect(sender) | ||||||
|       expect(sender.blocking?(bob)).to be false |         .to_not be_blocking(bob) | ||||||
|     end |       expect(a_request(:post, 'http://example.com/inbox')) | ||||||
| 
 |         .to have_been_made.once | ||||||
|     it 'sends an unblock activity', :inline_jobs do |  | ||||||
|       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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'destroys the following relation and sends unfollow activity' do | ||||||
|       subject.call(sender, bob) |       subject.call(sender, bob) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'destroys the following relation' do |       expect(sender) | ||||||
|       expect(sender.following?(bob)).to be false |         .to_not be_following(bob) | ||||||
|     end |       expect(a_request(:post, 'http://example.com/inbox')) | ||||||
| 
 |         .to have_been_made.once | ||||||
|     it 'sends an unfollow activity' do |  | ||||||
|       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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'destroys the following relation and sends a reject activity' do | ||||||
|       subject.call(bob, sender) |       subject.call(bob, sender) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'destroys the following relation' do |       expect(sender) | ||||||
|       expect(bob.following?(sender)).to be false |         .to_not be_following(bob) | ||||||
|     end |       expect(a_request(:post, 'http://example.com/inbox')) | ||||||
| 
 |         .to have_been_made.once | ||||||
|     it 'sends a reject activity' do |  | ||||||
|       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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'does not create an edit or notify anyone' do | ||||||
|       subject.call(status, status.account_id, text: 'Foo') |       subject.call(status, status.account_id, text: 'Foo') | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'does not create an edit' do |       expect(status.reload.edits) | ||||||
|       expect(status.reload.edits).to be_empty |         .to be_empty | ||||||
|     end |       expect(ActivityPub::DistributionWorker) | ||||||
| 
 |         .to_not have_received(:perform_async) | ||||||
|     it 'does not notify anyone' do |  | ||||||
|       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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'updates text, resets card, saves edit history' do | ||||||
|       subject.call(status, status.account_id, text: 'Bar') |       subject.call(status, status.account_id, text: 'Bar') | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'updates text' do |       expect(status.reload) | ||||||
|       expect(status.reload.text).to eq 'Bar' |         .to have_attributes( | ||||||
|     end |           text: 'Bar', | ||||||
| 
 |           preview_card: be_nil | ||||||
|     it 'resets preview card' do |         ) | ||||||
|       expect(status.reload.preview_card).to be_nil |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'saves edit history' do |  | ||||||
|       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) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'updates content warning and saves history' do | ||||||
|       subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar') |       subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar') | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'updates content warning' do |       expect(status.reload.spoiler_text) | ||||||
|       expect(status.reload.spoiler_text).to eq 'Bar' |         .to eq 'Bar' | ||||||
|     end |       expect(status.edits.ordered.pluck(:text, :spoiler_text)) | ||||||
| 
 |         .to eq [['Foo', ''], ['Foo', 'Bar']] | ||||||
|     it 'saves edit history' do |  | ||||||
|       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 | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'updates media attachments, handles attachments, saves history' do | ||||||
|       subject.call(status, status.account_id, text: 'Foo', media_ids: [attached_media_attachment.id.to_s]) |       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) | ||||||
|       expect(status.ordered_media_attachments).to eq [attached_media_attachment] |         .to eq [attached_media_attachment] | ||||||
|     end |       expect(detached_media_attachment.reload.status_id) | ||||||
| 
 |         .to eq status.id | ||||||
|     it 'does not detach detached media attachments' do |       expect(attached_media_attachment.reload.status_id) | ||||||
|       expect(detached_media_attachment.reload.status_id).to eq status.id |         .to eq status.id | ||||||
|     end |       expect(status.edits.ordered.pluck(:ordered_media_attachment_ids)) | ||||||
| 
 |         .to eq [[detached_media_attachment.id], [attached_media_attachment.id]] | ||||||
|     it 'attaches attached media attachments' do |  | ||||||
|       expect(attached_media_attachment.reload.status_id).to eq status.id |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'saves edit history' do |  | ||||||
|       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 | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'does not detach media attachment, updates description, and saves history' do | ||||||
|       subject.call(status, status.account_id, text: 'Foo', media_ids: [media_attachment.id.to_s], media_attributes: [{ id: media_attachment.id, description: 'New description' }]) |       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 'does not detach media attachment' do |       expect(media_attachment.reload) | ||||||
|       expect(media_attachment.reload.status_id).to eq status.id |         .to have_attributes( | ||||||
|     end |           status_id: status.id, | ||||||
| 
 |           description: 'New description' | ||||||
|     it 'updates the media attachment description' do |         ) | ||||||
|       expect(media_attachment.reload.description).to eq 'New description' |       expect(status.edits.ordered.map { |edit| edit.ordered_media_attachments.map(&:description) }) | ||||||
|     end |         .to eq [['Old description'], ['New description']] | ||||||
| 
 |  | ||||||
|     it 'saves edit history' do |  | ||||||
|       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]) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'updates poll, resets votes, saves history, requeues notifications' do | ||||||
|       subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i }) |       subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i }) | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'updates poll' do |  | ||||||
|       poll = status.poll.reload |       poll = status.poll.reload | ||||||
|       expect(poll.options).to eq %w(Bar Baz Foo) |  | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'resets votes' do |       expect(poll) | ||||||
|       poll = status.poll.reload |         .to have_attributes( | ||||||
|       expect(poll.votes_count).to eq 0 |           options: %w(Bar Baz Foo), | ||||||
|       expect(poll.votes.count).to eq 0 |           votes_count: 0, | ||||||
|       expect(poll.cached_tallies).to eq [0, 0, 0] |           cached_tallies: [0, 0, 0] | ||||||
|     end |         ) | ||||||
|  |       expect(poll.votes.count) | ||||||
|  |         .to eq(0) | ||||||
| 
 | 
 | ||||||
|     it 'saves edit history' do |       expect(status.edits.ordered.pluck(:poll_options)) | ||||||
|       expect(status.edits.ordered.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)] |         .to eq [%w(Foo Bar), %w(Bar Baz Foo)] | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     it 'requeues expiration notification' do |       expect(PollExpirationNotifyWorker) | ||||||
|       poll = status.poll.reload |         .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)) | ||||||
|       expect(status.active_mentions.pluck(:account_id)).to eq [bob.id] |         .to eq [bob.id] | ||||||
|     end |       expect(status.mentions.pluck(:account_id)) | ||||||
| 
 |         .to contain_exactly(alice.id, bob.id) | ||||||
|     it 'keeps old mentions as silent mentions' do |  | ||||||
|       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 |  | ||||||
|       subject.call(status, status.account_id, text: 'Hello #bar') |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'changes tags' do |     it 'changes tags' do | ||||||
|  |       subject.call(status, status.account_id, text: 'Hello #bar') | ||||||
|  | 
 | ||||||
|       expect(status.tags.pluck(:name)).to eq %w(bar) |       expect(status.tags.pluck(:name)).to eq %w(bar) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user