diff --git a/lib/mastodon/cli/cache.rb b/lib/mastodon/cli/cache.rb index 105d4b3c3..e8a2ac161 100644 --- a/lib/mastodon/cli/cache.rb +++ b/lib/mastodon/cli/cache.rb @@ -23,22 +23,12 @@ module Mastodon::CLI def recount(type) case type when 'accounts' - processed, = parallelize_with_progress(Account.local.includes(:account_stat)) do |account| - account_stat = account.account_stat - account_stat.following_count = account.active_relationships.count - account_stat.followers_count = account.passive_relationships.count - account_stat.statuses_count = account.statuses.where.not(visibility: :direct).count - - account_stat.save if account_stat.changed? + processed, = parallelize_with_progress(accounts_with_stats) do |account| + recount_account_stats(account) end when 'statuses' - processed, = parallelize_with_progress(Status.includes(:status_stat)) do |status| - status_stat = status.status_stat - status_stat.replies_count = status.replies.where.not(visibility: :direct).count - status_stat.reblogs_count = status.reblogs.count - status_stat.favourites_count = status.favourites.count - - status_stat.save if status_stat.changed? + processed, = parallelize_with_progress(statuses_with_stats) do |status| + recount_status_stats(status) end else say("Unknown type: #{type}", :red) @@ -48,5 +38,35 @@ module Mastodon::CLI say say("OK, recounted #{processed} records", :green) end + + private + + def accounts_with_stats + Account.local.includes(:account_stat) + end + + def statuses_with_stats + Status.includes(:status_stat) + end + + def recount_account_stats(account) + account.account_stat.tap do |account_stat| + account_stat.following_count = account.active_relationships.count + account_stat.followers_count = account.passive_relationships.count + account_stat.statuses_count = account.statuses.where.not(visibility: :direct).count + + account_stat.save if account_stat.changed? + end + end + + def recount_status_stats(status) + status.status_stat.tap do |status_stat| + status_stat.replies_count = status.replies.where.not(visibility: :direct).count + status_stat.reblogs_count = status.reblogs.count + status_stat.favourites_count = status.favourites.count + + status_stat.save if status_stat.changed? + end + end end end diff --git a/spec/fabricators/status_stat_fabricator.rb b/spec/fabricators/status_stat_fabricator.rb new file mode 100644 index 000000000..715e6d4ab --- /dev/null +++ b/spec/fabricators/status_stat_fabricator.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +Fabricator(:status_stat) do + status + replies_count '123' + reblogs_count '456' + favourites_count '789' +end diff --git a/spec/lib/mastodon/cli/cache_spec.rb b/spec/lib/mastodon/cli/cache_spec.rb index f101bc200..3ab42dc8c 100644 --- a/spec/lib/mastodon/cli/cache_spec.rb +++ b/spec/lib/mastodon/cli/cache_spec.rb @@ -4,9 +4,68 @@ require 'rails_helper' require 'mastodon/cli/cache' describe Mastodon::CLI::Cache do + let(:cli) { described_class.new } + describe '.exit_on_failure?' do it 'returns true' do expect(described_class.exit_on_failure?).to be true end end + + describe '#clear' do + before { allow(Rails.cache).to receive(:clear) } + + it 'clears the Rails cache' do + expect { cli.invoke(:clear) }.to output( + a_string_including('OK') + ).to_stdout + expect(Rails.cache).to have_received(:clear) + end + end + + describe '#recount' do + context 'with the `accounts` argument' do + let(:arguments) { ['accounts'] } + let(:account_stat) { Fabricate(:account_stat) } + + before do + account_stat.update(statuses_count: 123) + end + + it 're-calculates account records in the cache' do + expect { cli.invoke(:recount, arguments) }.to output( + a_string_including('OK') + ).to_stdout + + expect(account_stat.reload.statuses_count).to be_zero + end + end + + context 'with the `statuses` argument' do + let(:arguments) { ['statuses'] } + let(:status_stat) { Fabricate(:status_stat) } + + before do + status_stat.update(replies_count: 123) + end + + it 're-calculates account records in the cache' do + expect { cli.invoke(:recount, arguments) }.to output( + a_string_including('OK') + ).to_stdout + + expect(status_stat.reload.replies_count).to be_zero + end + end + + context 'with an unknown type' do + let(:arguments) { ['other-type'] } + + it 'Exits with an error message' do + expect { cli.invoke(:recount, arguments) }.to output( + a_string_including('Unknown') + ).to_stdout.and raise_error(SystemExit) + end + end + end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index f4113d565..2645f74e4 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -79,6 +79,7 @@ RSpec.configure do |config| config.before :each, type: :cli do stub_stdout + stub_reset_connection_pools end config.before :each, type: :feature do @@ -121,9 +122,20 @@ def attachment_fixture(name) end def stub_stdout + # TODO: Is there a bettery way to: + # - Avoid CLI command output being printed out + # - Allow rspec to assert things against STDOUT + # - Avoid disabling stdout for other desirable output (deprecation warnings, for example) allow($stdout).to receive(:write) end +def stub_reset_connection_pools + # TODO: Is there a better way to correctly run specs without stubbing this? + # (Avoids reset_connection_pools! in test env) + allow(ActiveRecord::Base).to receive(:establish_connection) + allow(RedisConfiguration).to receive(:establish_pool) +end + def stub_jsonld_contexts! stub_request(:get, 'https://www.w3.org/ns/activitystreams').to_return(request_fixture('json-ld.activitystreams.txt')) stub_request(:get, 'https://w3id.org/identity/v1').to_return(request_fixture('json-ld.identity.txt'))