Fix errors in CLI specs (#27399)

This commit is contained in:
Claire 2023-10-17 15:30:12 +02:00 committed by GitHub
parent c0cda1adaf
commit b34a2b1b33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 41 additions and 46 deletions

View File

@ -6,6 +6,24 @@ require 'mastodon/cli/accounts'
describe Mastodon::CLI::Accounts do describe Mastodon::CLI::Accounts do
let(:cli) { described_class.new } let(:cli) { described_class.new }
# `parallelize_with_progress` cannot run in transactions, so instead,
# stub it with an alternative implementation that runs sequentially
# and can run in transactions.
def stub_parallelize_with_progress!
allow(cli).to receive(:parallelize_with_progress) do |scope, &block|
aggregate = 0
total = 0
scope.reorder(nil).find_each do |record|
value = block.call(record)
aggregate += value if value.is_a?(Integer)
total += 1
end
[total, aggregate]
end
end
describe '.exit_on_failure?' do describe '.exit_on_failure?' do
it 'returns true' do it 'returns true' do
expect(described_class.exit_on_failure?).to be true expect(described_class.exit_on_failure?).to be true
@ -551,20 +569,15 @@ describe Mastodon::CLI::Accounts do
let!(:follower_rony) { Fabricate(:account, username: 'rony') } let!(:follower_rony) { Fabricate(:account, username: 'rony') }
let!(:follower_charles) { Fabricate(:account, username: 'charles') } let!(:follower_charles) { Fabricate(:account, username: 'charles') }
let(:follow_service) { instance_double(FollowService, call: nil) } let(:follow_service) { instance_double(FollowService, call: nil) }
let(:scope) { Account.local.without_suspended }
before do before do
allow(cli).to receive(:parallelize_with_progress).and_yield(follower_bob)
.and_yield(follower_rony)
.and_yield(follower_charles)
.and_return([3, nil])
allow(FollowService).to receive(:new).and_return(follow_service) allow(FollowService).to receive(:new).and_return(follow_service)
stub_parallelize_with_progress!
end end
it 'makes all local accounts follow the target account' do it 'makes all local accounts follow the target account' do
cli.follow(target_account.username) cli.follow(target_account.username)
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(follow_service).to have_received(:call).with(follower_bob, target_account, any_args).once expect(follow_service).to have_received(:call).with(follower_bob, target_account, any_args).once
expect(follow_service).to have_received(:call).with(follower_rony, target_account, any_args).once expect(follow_service).to have_received(:call).with(follower_rony, target_account, any_args).once
expect(follow_service).to have_received(:call).with(follower_charles, target_account, any_args).once expect(follow_service).to have_received(:call).with(follower_charles, target_account, any_args).once
@ -572,7 +585,7 @@ describe Mastodon::CLI::Accounts do
it 'displays a successful message' do it 'displays a successful message' do
expect { cli.follow(target_account.username) }.to output( expect { cli.follow(target_account.username) }.to output(
a_string_including('OK, followed target from 3 accounts') a_string_including("OK, followed target from #{Account.local.count} accounts")
).to_stdout ).to_stdout
end end
end end
@ -592,26 +605,21 @@ describe Mastodon::CLI::Accounts do
context 'when the given username is found' do context 'when the given username is found' do
let!(:target_account) { Fabricate(:account) } let!(:target_account) { Fabricate(:account) }
let!(:follower_chris) { Fabricate(:account, username: 'chris') } let!(:follower_chris) { Fabricate(:account, username: 'chris', domain: nil) }
let!(:follower_rambo) { Fabricate(:account, username: 'rambo') } let!(:follower_rambo) { Fabricate(:account, username: 'rambo', domain: nil) }
let!(:follower_ana) { Fabricate(:account, username: 'ana') } let!(:follower_ana) { Fabricate(:account, username: 'ana', domain: nil) }
let(:unfollow_service) { instance_double(UnfollowService, call: nil) } let(:unfollow_service) { instance_double(UnfollowService, call: nil) }
let(:scope) { target_account.followers.local }
before do before do
accounts = [follower_chris, follower_rambo, follower_ana] accounts = [follower_chris, follower_rambo, follower_ana]
accounts.each { |account| target_account.follow!(account) } accounts.each { |account| account.follow!(target_account) }
allow(cli).to receive(:parallelize_with_progress).and_yield(follower_chris)
.and_yield(follower_rambo)
.and_yield(follower_ana)
.and_return([3, nil])
allow(UnfollowService).to receive(:new).and_return(unfollow_service) allow(UnfollowService).to receive(:new).and_return(unfollow_service)
stub_parallelize_with_progress!
end end
it 'makes all local accounts unfollow the target account' do it 'makes all local accounts unfollow the target account' do
cli.unfollow(target_account.username) cli.unfollow(target_account.username)
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(unfollow_service).to have_received(:call).with(follower_chris, target_account).once expect(unfollow_service).to have_received(:call).with(follower_chris, target_account).once
expect(unfollow_service).to have_received(:call).with(follower_rambo, target_account).once expect(unfollow_service).to have_received(:call).with(follower_rambo, target_account).once
expect(unfollow_service).to have_received(:call).with(follower_ana, target_account).once expect(unfollow_service).to have_received(:call).with(follower_ana, target_account).once
@ -671,6 +679,8 @@ describe Mastodon::CLI::Accounts do
let(:scope) { Account.remote } let(:scope) { Account.remote }
before do before do
# TODO: we should be using `stub_parallelize_with_progress!` but
# this makes the assertions harder to write
allow(cli).to receive(:parallelize_with_progress).and_yield(remote_account_example_com) allow(cli).to receive(:parallelize_with_progress).and_yield(remote_account_example_com)
.and_yield(account_example_net) .and_yield(account_example_net)
.and_return([2, nil]) .and_return([2, nil])
@ -1112,26 +1122,19 @@ describe Mastodon::CLI::Accounts do
describe '#cull' do describe '#cull' do
let(:delete_account_service) { instance_double(DeleteAccountService, call: nil) } let(:delete_account_service) { instance_double(DeleteAccountService, call: nil) }
let!(:tom) { Fabricate(:account, updated_at: 30.days.ago, username: 'tom', uri: 'https://example.com/users/tom', domain: 'example.com') } let!(:tom) { Fabricate(:account, updated_at: 30.days.ago, username: 'tom', uri: 'https://example.com/users/tom', domain: 'example.com', protocol: :activitypub) }
let!(:bob) { Fabricate(:account, updated_at: 30.days.ago, last_webfingered_at: nil, username: 'bob', uri: 'https://example.org/users/bob', domain: 'example.org') } let!(:bob) { Fabricate(:account, updated_at: 30.days.ago, last_webfingered_at: nil, username: 'bob', uri: 'https://example.org/users/bob', domain: 'example.org', protocol: :activitypub) }
let!(:gon) { Fabricate(:account, updated_at: 15.days.ago, last_webfingered_at: 15.days.ago, username: 'gon', uri: 'https://example.net/users/gon', domain: 'example.net') } let!(:gon) { Fabricate(:account, updated_at: 15.days.ago, last_webfingered_at: 15.days.ago, username: 'gon', uri: 'https://example.net/users/gon', domain: 'example.net', protocol: :activitypub) }
let!(:ana) { Fabricate(:account, username: 'ana', uri: 'https://example.com/users/ana', domain: 'example.com') } let!(:ana) { Fabricate(:account, username: 'ana', uri: 'https://example.com/users/ana', domain: 'example.com', protocol: :activitypub) }
let!(:tales) { Fabricate(:account, updated_at: 10.days.ago, last_webfingered_at: nil, username: 'tales', uri: 'https://example.net/users/tales', domain: 'example.net') } let!(:tales) { Fabricate(:account, updated_at: 10.days.ago, last_webfingered_at: nil, username: 'tales', uri: 'https://example.net/users/tales', domain: 'example.net', protocol: :activitypub) }
before do before do
allow(DeleteAccountService).to receive(:new).and_return(delete_account_service) allow(DeleteAccountService).to receive(:new).and_return(delete_account_service)
end end
context 'when no domain is specified' do context 'when no domain is specified' do
let(:scope) { Account.remote.where(protocol: :activitypub).partitioned }
before do before do
allow(cli).to receive(:parallelize_with_progress).and_yield(tom) stub_parallelize_with_progress!
.and_yield(bob)
.and_yield(gon)
.and_yield(ana)
.and_yield(tales)
.and_return([5, 3])
stub_request(:head, 'https://example.org/users/bob').to_return(status: 404) stub_request(:head, 'https://example.org/users/bob').to_return(status: 404)
stub_request(:head, 'https://example.net/users/gon').to_return(status: 410) stub_request(:head, 'https://example.net/users/gon').to_return(status: 410)
stub_request(:head, 'https://example.net/users/tales').to_return(status: 200) stub_request(:head, 'https://example.net/users/tales').to_return(status: 200)
@ -1140,7 +1143,6 @@ describe Mastodon::CLI::Accounts do
it 'deletes all inactive remote accounts that longer exist in the origin server' do it 'deletes all inactive remote accounts that longer exist in the origin server' do
cli.cull cli.cull
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(delete_account_service).to have_received(:call).with(bob, reserve_username: false).once expect(delete_account_service).to have_received(:call).with(bob, reserve_username: false).once
expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once
end end
@ -1148,35 +1150,27 @@ describe Mastodon::CLI::Accounts do
it 'does not delete any active remote account that still exists in the origin server' do it 'does not delete any active remote account that still exists in the origin server' do
cli.cull cli.cull
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(delete_account_service).to_not have_received(:call).with(tom, reserve_username: false) expect(delete_account_service).to_not have_received(:call).with(tom, reserve_username: false)
expect(delete_account_service).to_not have_received(:call).with(ana, reserve_username: false) expect(delete_account_service).to_not have_received(:call).with(ana, reserve_username: false)
expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false) expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false)
end end
it 'touches inactive remote accounts that have not been deleted' do it 'touches inactive remote accounts that have not been deleted' do
allow(tales).to receive(:touch) expect { cli.cull }.to(change { tales.reload.updated_at })
cli.cull
expect(tales).to have_received(:touch).once
end end
it 'displays the summary correctly' do it 'displays the summary correctly' do
expect { cli.cull }.to output( expect { cli.cull }.to output(
a_string_including('Visited 5 accounts, removed 3') a_string_including('Visited 5 accounts, removed 2')
).to_stdout ).to_stdout
end end
end end
context 'when a domain is specified' do context 'when a domain is specified' do
let(:domain) { 'example.net' } let(:domain) { 'example.net' }
let(:scope) { Account.remote.where(protocol: :activitypub, domain: domain).partitioned }
before do before do
allow(cli).to receive(:parallelize_with_progress).and_yield(gon) stub_parallelize_with_progress!
.and_yield(tales)
.and_return([2, 2])
stub_request(:head, 'https://example.net/users/gon').to_return(status: 410) stub_request(:head, 'https://example.net/users/gon').to_return(status: 410)
stub_request(:head, 'https://example.net/users/tales').to_return(status: 404) stub_request(:head, 'https://example.net/users/tales').to_return(status: 404)
end end
@ -1184,13 +1178,12 @@ describe Mastodon::CLI::Accounts do
it 'deletes inactive remote accounts that longer exist in the specified domain' do it 'deletes inactive remote accounts that longer exist in the specified domain' do
cli.cull(domain) cli.cull(domain)
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once
expect(delete_account_service).to have_received(:call).with(tales, reserve_username: false).once expect(delete_account_service).to have_received(:call).with(tales, reserve_username: false).once
end end
it 'displays the summary correctly' do it 'displays the summary correctly' do
expect { cli.cull }.to output( expect { cli.cull(domain) }.to output(
a_string_including('Visited 2 accounts, removed 2') a_string_including('Visited 2 accounts, removed 2')
).to_stdout ).to_stdout
end end
@ -1199,7 +1192,9 @@ describe Mastodon::CLI::Accounts do
context 'when a domain is unavailable' do context 'when a domain is unavailable' do
shared_examples 'an unavailable domain' do shared_examples 'an unavailable domain' do
before do before do
allow(cli).to receive(:parallelize_with_progress).and_yield(tales).and_return([1, 0]) stub_parallelize_with_progress!
stub_request(:head, 'https://example.org/users/bob').to_return(status: 200)
stub_request(:head, 'https://example.net/users/gon').to_return(status: 200)
end end
it 'skips accounts from the unavailable domain' do it 'skips accounts from the unavailable domain' do
@ -1210,7 +1205,7 @@ describe Mastodon::CLI::Accounts do
it 'displays the summary correctly' do it 'displays the summary correctly' do
expect { cli.cull }.to output( expect { cli.cull }.to output(
a_string_including("Visited 1 accounts, removed 0\nThe following domains were not available during the check:\n example.net") a_string_including("Visited 5 accounts, removed 0\nThe following domains were not available during the check:\n example.net")
).to_stdout ).to_stdout
end end
end end