about summary refs log tree commit diff
path: root/spec/services
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services')
-rw-r--r--spec/services/account_search_service_spec.rb6
-rw-r--r--spec/services/account_statuses_cleanup_service_spec.rb6
-rw-r--r--spec/services/activitypub/fetch_featured_collection_service_spec.rb8
-rw-r--r--spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb10
-rw-r--r--spec/services/activitypub/fetch_remote_account_service_spec.rb2
-rw-r--r--spec/services/activitypub/fetch_remote_actor_service_spec.rb2
-rw-r--r--spec/services/activitypub/fetch_remote_key_service_spec.rb2
-rw-r--r--spec/services/activitypub/fetch_remote_status_service_spec.rb138
-rw-r--r--spec/services/activitypub/fetch_replies_service_spec.rb8
-rw-r--r--spec/services/activitypub/process_account_service_spec.rb18
-rw-r--r--spec/services/activitypub/process_collection_service_spec.rb124
-rw-r--r--spec/services/activitypub/process_status_update_service_spec.rb84
-rw-r--r--spec/services/activitypub/synchronize_followers_service_spec.rb8
-rw-r--r--spec/services/after_block_domain_from_account_service_spec.rb6
-rw-r--r--spec/services/after_block_service_spec.rb2
-rw-r--r--spec/services/app_sign_up_service_spec.rb6
-rw-r--r--spec/services/authorize_follow_service_spec.rb6
-rw-r--r--spec/services/batched_remove_status_service_spec.rb2
-rw-r--r--spec/services/block_domain_service_spec.rb12
-rw-r--r--spec/services/block_service_spec.rb6
-rw-r--r--spec/services/bootstrap_timeline_service_spec.rb3
-rw-r--r--spec/services/clear_domain_media_service_spec.rb12
-rw-r--r--spec/services/delete_account_service_spec.rb24
-rw-r--r--spec/services/fan_out_on_write_service_spec.rb9
-rw-r--r--spec/services/favourite_service_spec.rb10
-rw-r--r--spec/services/fetch_link_card_service_spec.rb10
-rw-r--r--spec/services/fetch_oembed_service_spec.rb15
-rw-r--r--spec/services/fetch_remote_status_service_spec.rb7
-rw-r--r--spec/services/fetch_resource_service_spec.rb21
-rw-r--r--spec/services/follow_service_spec.rb8
-rw-r--r--spec/services/import_service_spec.rb29
-rw-r--r--spec/services/mute_service_spec.rb2
-rw-r--r--spec/services/notify_service_spec.rb11
-rw-r--r--spec/services/post_status_service_spec.rb67
-rw-r--r--spec/services/precompute_feed_service_spec.rb3
-rw-r--r--spec/services/process_mentions_service_spec.rb27
-rw-r--r--spec/services/purge_domain_service_spec.rb6
-rw-r--r--spec/services/reblog_service_spec.rb10
-rw-r--r--spec/services/reject_follow_service_spec.rb6
-rw-r--r--spec/services/remove_from_followers_service_spec.rb (renamed from spec/services/remove_from_follwers_service_spec.rb)8
-rw-r--r--spec/services/remove_status_service_spec.rb70
-rw-r--r--spec/services/report_service_spec.rb17
-rw-r--r--spec/services/resolve_account_service_spec.rb34
-rw-r--r--spec/services/resolve_url_service_spec.rb2
-rw-r--r--spec/services/search_service_spec.rb10
-rw-r--r--spec/services/suspend_account_service_spec.rb6
-rw-r--r--spec/services/unallow_domain_service_spec.rb6
-rw-r--r--spec/services/unblock_service_spec.rb6
-rw-r--r--spec/services/unfollow_service_spec.rb6
-rw-r--r--spec/services/unmute_service_spec.rb2
-rw-r--r--spec/services/unsuspend_account_service_spec.rb6
-rw-r--r--spec/services/update_account_service_spec.rb2
-rw-r--r--spec/services/update_status_service_spec.rb35
-rw-r--r--spec/services/verify_link_service_spec.rb24
54 files changed, 623 insertions, 347 deletions
diff --git a/spec/services/account_search_service_spec.rb b/spec/services/account_search_service_spec.rb
index 81cbc175e..bb819bb6c 100644
--- a/spec/services/account_search_service_spec.rb
+++ b/spec/services/account_search_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 describe AccountSearchService, type: :service do
@@ -63,7 +65,7 @@ describe AccountSearchService, type: :service do
         allow(ResolveAccountService).to receive(:new).and_return(service)
 
         results = subject.call('newuser@remote.com', nil, limit: 10, resolve: false)
-        expect(service).not_to have_received(:call)
+        expect(service).to_not have_received(:call)
       end
     end
 
@@ -76,7 +78,7 @@ describe AccountSearchService, type: :service do
       expect(results).to eq [partial]
     end
 
-    it "does not return suspended remote accounts" do
+    it 'does not return suspended remote accounts' do
       remote  = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true)
       results = subject.call('a@example.com', nil, limit: 2)
 
diff --git a/spec/services/account_statuses_cleanup_service_spec.rb b/spec/services/account_statuses_cleanup_service_spec.rb
index 257655c41..e83063f73 100644
--- a/spec/services/account_statuses_cleanup_service_spec.rb
+++ b/spec/services/account_statuses_cleanup_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 describe AccountStatusesCleanupService, type: :service do
@@ -42,8 +44,8 @@ describe AccountStatusesCleanupService, type: :service do
 
       context 'when called repeatedly with a budget of 2' do
         it 'reports 2 then 1 deleted statuses' do
-         expect(subject.call(account_policy, 2)).to eq 2
-         expect(subject.call(account_policy, 2)).to eq 1
+          expect(subject.call(account_policy, 2)).to eq 2
+          expect(subject.call(account_policy, 2)).to eq 1
         end
 
         it 'actually deletes the statuses in the expected order' do
diff --git a/spec/services/activitypub/fetch_featured_collection_service_spec.rb b/spec/services/activitypub/fetch_featured_collection_service_spec.rb
index e6336dc1b..59d332599 100644
--- a/spec/services/activitypub/fetch_featured_collection_service_spec.rb
+++ b/spec/services/activitypub/fetch_featured_collection_service_spec.rb
@@ -1,6 +1,10 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
+  subject { described_class.new }
+
   let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/account', featured_collection_url: 'https://example.com/account/pinned') }
 
   let!(:known_status) { Fabricate(:status, account: actor, uri: 'https://example.com/account/pinned/1') }
@@ -56,8 +60,6 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
     }.with_indifferent_access
   end
 
-  subject { described_class.new }
-
   shared_examples 'sets pinned posts' do
     before do
       stub_request(:get, 'https://example.com/account/pinned/1').to_return(status: 200, body: Oj.dump(status_json_1))
@@ -109,7 +111,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
             type: 'CollectionPage',
             partOf: actor.featured_collection_url,
             items: items,
-          }
+          },
         }.with_indifferent_access
       end
 
diff --git a/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb b/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb
index 6ca22c9fc..071e4d92d 100644
--- a/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb
+++ b/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb
@@ -1,6 +1,10 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service do
+  subject { described_class.new }
+
   let(:collection_url) { 'https://example.com/account/tags' }
   let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/account') }
 
@@ -21,15 +25,13 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
     }.with_indifferent_access
   end
 
-  subject { described_class.new }
-
   shared_examples 'sets featured tags' do
     before do
       subject.call(actor, collection_url)
     end
 
     it 'sets expected tags as pinned tags' do
-      expect(actor.featured_tags.map(&:display_name)).to match_array ['Foo', 'bar', 'baZ']
+      expect(actor.featured_tags.map(&:display_name)).to match_array %w(Foo bar baZ)
     end
   end
 
@@ -81,7 +83,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
             type: 'CollectionPage',
             partOf: collection_url,
             items: items,
-          }
+          },
         }.with_indifferent_access
       end
 
diff --git a/spec/services/activitypub/fetch_remote_account_service_spec.rb b/spec/services/activitypub/fetch_remote_account_service_spec.rb
index ec6f1f41d..868bc2a58 100644
--- a/spec/services/activitypub/fetch_remote_account_service_spec.rb
+++ b/spec/services/activitypub/fetch_remote_account_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
diff --git a/spec/services/activitypub/fetch_remote_actor_service_spec.rb b/spec/services/activitypub/fetch_remote_actor_service_spec.rb
index 20117c66d..a72c6941e 100644
--- a/spec/services/activitypub/fetch_remote_actor_service_spec.rb
+++ b/spec/services/activitypub/fetch_remote_actor_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
diff --git a/spec/services/activitypub/fetch_remote_key_service_spec.rb b/spec/services/activitypub/fetch_remote_key_service_spec.rb
index 3186c4270..0ec0c2736 100644
--- a/spec/services/activitypub/fetch_remote_key_service_spec.rb
+++ b/spec/services/activitypub/fetch_remote_key_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
diff --git a/spec/services/activitypub/fetch_remote_status_service_spec.rb b/spec/services/activitypub/fetch_remote_status_service_spec.rb
index 7359ca0b4..1c39db21f 100644
--- a/spec/services/activitypub/fetch_remote_status_service_spec.rb
+++ b/spec/services/activitypub/fetch_remote_status_service_spec.rb
@@ -1,8 +1,12 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
   include ActionView::Helpers::TextHelper
 
+  subject { described_class.new }
+
   let!(:sender) { Fabricate(:account, domain: 'foo.bar', uri: 'https://foo.bar') }
   let!(:recipient) { Fabricate(:account) }
 
@@ -11,15 +15,13 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
   let(:note) do
     {
       '@context': 'https://www.w3.org/ns/activitystreams',
-      id: "https://foo.bar/@foo/1234",
+      id: 'https://foo.bar/@foo/1234',
       type: 'Note',
       content: 'Lorem ipsum',
       attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
     }
   end
 
-  subject { described_class.new }
-
   before do
     stub_request(:get, 'https://foo.bar/watch?v=12345').to_return(status: 404, body: '')
     stub_request(:get, object[:id]).to_return(body: Oj.dump(object))
@@ -46,7 +48,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
       let(:object) do
         {
           '@context': 'https://www.w3.org/ns/activitystreams',
-          id: "https://foo.bar/@foo/1234",
+          id: 'https://foo.bar/@foo/1234',
           type: 'Video',
           name: 'Nyan Cat 10 hours remix',
           attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
@@ -54,13 +56,13 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
             {
               type: 'Link',
               mimeType: 'application/x-bittorrent',
-              href: "https://foo.bar/12345.torrent",
+              href: 'https://foo.bar/12345.torrent',
             },
 
             {
               type: 'Link',
               mimeType: 'text/html',
-              href: "https://foo.bar/watch?v=12345",
+              href: 'https://foo.bar/watch?v=12345',
             },
           ],
         }
@@ -70,8 +72,8 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
         status = sender.statuses.first
 
         expect(status).to_not be_nil
-        expect(status.url).to eq "https://foo.bar/watch?v=12345"
-        expect(strip_tags(status.text)).to eq "Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345"
+        expect(status.url).to eq 'https://foo.bar/watch?v=12345'
+        expect(strip_tags(status.text)).to eq 'Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345'
       end
     end
 
@@ -79,7 +81,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
       let(:object) do
         {
           '@context': 'https://www.w3.org/ns/activitystreams',
-          id: "https://foo.bar/@foo/1234",
+          id: 'https://foo.bar/@foo/1234',
           type: 'Audio',
           name: 'Nyan Cat 10 hours remix',
           attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
@@ -87,13 +89,13 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
             {
               type: 'Link',
               mimeType: 'application/x-bittorrent',
-              href: "https://foo.bar/12345.torrent",
+              href: 'https://foo.bar/12345.torrent',
             },
 
             {
               type: 'Link',
               mimeType: 'text/html',
-              href: "https://foo.bar/watch?v=12345",
+              href: 'https://foo.bar/watch?v=12345',
             },
           ],
         }
@@ -103,8 +105,8 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
         status = sender.statuses.first
 
         expect(status).to_not be_nil
-        expect(status.url).to eq "https://foo.bar/watch?v=12345"
-        expect(strip_tags(status.text)).to eq "Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345"
+        expect(status.url).to eq 'https://foo.bar/watch?v=12345'
+        expect(strip_tags(status.text)).to eq 'Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345'
       end
     end
 
@@ -112,10 +114,10 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
       let(:object) do
         {
           '@context': 'https://www.w3.org/ns/activitystreams',
-          id: "https://foo.bar/@foo/1234",
+          id: 'https://foo.bar/@foo/1234',
           type: 'Event',
           name: "Let's change the world",
-          attributedTo: ActivityPub::TagManager.instance.uri_for(sender)
+          attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
         }
       end
 
@@ -123,7 +125,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
         status = sender.statuses.first
 
         expect(status).to_not be_nil
-        expect(status.url).to eq "https://foo.bar/@foo/1234"
+        expect(status.url).to eq 'https://foo.bar/@foo/1234'
         expect(strip_tags(status.text)).to eq "Let's change the worldhttps://foo.bar/@foo/1234"
       end
     end
@@ -132,7 +134,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
       let(:note) do
         {
           '@context': 'https://www.w3.org/ns/activitystreams',
-          id: "https://real.address/@foo/1234",
+          id: 'https://real.address/@foo/1234',
           type: 'Note',
           content: 'Lorem ipsum',
           attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
@@ -154,7 +156,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
       let(:object) do
         {
           '@context': 'https://www.w3.org/ns/activitystreams',
-          id: "https://foo.bar/@foo/1234/create",
+          id: 'https://foo.bar/@foo/1234/create',
           type: 'Create',
           actor: ActivityPub::TagManager.instance.uri_for(sender),
           object: note,
@@ -174,11 +176,11 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
       let(:object) do
         {
           '@context': 'https://www.w3.org/ns/activitystreams',
-          id: "https://foo.bar/@foo/1234/create",
+          id: 'https://foo.bar/@foo/1234/create',
           type: 'Create',
           actor: ActivityPub::TagManager.instance.uri_for(sender),
           object: {
-            id: "https://real.address/@foo/1234",
+            id: 'https://real.address/@foo/1234',
             type: 'Note',
             content: 'Lorem ipsum',
             attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
@@ -208,7 +210,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
         let(:object) do
           {
             '@context': 'https://www.w3.org/ns/activitystreams',
-            id: "https://foo.bar/@foo/1234/create",
+            id: 'https://foo.bar/@foo/1234/create',
             type: 'Create',
             actor: ActivityPub::TagManager.instance.uri_for(sender),
             object: note.merge(updated: '2021-09-08T22:39:25Z'),
@@ -223,4 +225,98 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
       end
     end
   end
+
+  context 'statuses referencing other statuses' do
+    before do
+      stub_const 'ActivityPub::FetchRemoteStatusService::DISCOVERIES_PER_REQUEST', 5
+    end
+
+    context 'using inReplyTo' do
+      let(:object) do
+        {
+          '@context': 'https://www.w3.org/ns/activitystreams',
+          id: 'https://foo.bar/@foo/1',
+          type: 'Note',
+          content: 'Lorem ipsum',
+          inReplyTo: 'https://foo.bar/@foo/2',
+          attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
+        }
+      end
+
+      before do
+        8.times do |i|
+          status_json = {
+            '@context': 'https://www.w3.org/ns/activitystreams',
+            id: "https://foo.bar/@foo/#{i}",
+            type: 'Note',
+            content: 'Lorem ipsum',
+            inReplyTo: "https://foo.bar/@foo/#{i + 1}",
+            attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
+            to: 'as:Public',
+          }.with_indifferent_access
+          stub_request(:get, "https://foo.bar/@foo/#{i}").to_return(status: 200, body: status_json.to_json, headers: { 'Content-Type': 'application/activity+json' })
+        end
+      end
+
+      it 'creates at least some statuses' do
+        expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_least(2)
+      end
+
+      it 'creates no more account than the limit allows' do
+        expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_most(5)
+      end
+    end
+
+    context 'using replies' do
+      let(:object) do
+        {
+          '@context': 'https://www.w3.org/ns/activitystreams',
+          id: 'https://foo.bar/@foo/1',
+          type: 'Note',
+          content: 'Lorem ipsum',
+          replies: {
+            type: 'Collection',
+            id: 'https://foo.bar/@foo/1/replies',
+            first: {
+              type: 'CollectionPage',
+              partOf: 'https://foo.bar/@foo/1/replies',
+              items: ['https://foo.bar/@foo/2'],
+            },
+          },
+          attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
+        }
+      end
+
+      before do
+        8.times do |i|
+          status_json = {
+            '@context': 'https://www.w3.org/ns/activitystreams',
+            id: "https://foo.bar/@foo/#{i}",
+            type: 'Note',
+            content: 'Lorem ipsum',
+            replies: {
+              type: 'Collection',
+              id: "https://foo.bar/@foo/#{i}/replies",
+              first: {
+                type: 'CollectionPage',
+                partOf: "https://foo.bar/@foo/#{i}/replies",
+                items: ["https://foo.bar/@foo/#{i + 1}"],
+              },
+            },
+            attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
+            to: 'as:Public',
+          }.with_indifferent_access
+          stub_request(:get, "https://foo.bar/@foo/#{i}").to_return(status: 200, body: status_json.to_json, headers: { 'Content-Type': 'application/activity+json' })
+        end
+      end
+
+      it 'creates at least some statuses' do
+        expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_least(2)
+      end
+
+      it 'creates no more account than the limit allows' do
+        expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_most(5)
+      end
+    end
+  end
 end
diff --git a/spec/services/activitypub/fetch_replies_service_spec.rb b/spec/services/activitypub/fetch_replies_service_spec.rb
index fe49b18c1..bf8e29676 100644
--- a/spec/services/activitypub/fetch_replies_service_spec.rb
+++ b/spec/services/activitypub/fetch_replies_service_spec.rb
@@ -1,6 +1,10 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::FetchRepliesService, type: :service do
+  subject { described_class.new }
+
   let(:actor)          { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }
   let(:status)         { Fabricate(:status, account: actor) }
   let(:collection_uri) { 'http://example.com/replies/1' }
@@ -28,8 +32,6 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
     }.with_indifferent_access
   end
 
-  subject { described_class.new }
-
   describe '#call' do
     context 'when the payload is a Collection with inlined replies' do
       context 'when passing the collection itself' do
@@ -90,7 +92,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
             type: 'CollectionPage',
             partOf: collection_uri,
             items: items,
-          }
+          },
         }.with_indifferent_access
       end
 
diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb
index 2b20d17b1..491b8ed5a 100644
--- a/spec/services/activitypub/process_account_service_spec.rb
+++ b/spec/services/activitypub/process_account_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::ProcessAccountService, type: :service do
@@ -12,7 +14,7 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
         attachment: [
           { type: 'PropertyValue', name: 'Pronouns', value: 'They/them' },
           { type: 'PropertyValue', name: 'Occupation', value: 'Unit test' },
-          { type: 'PropertyValue', name: 'non-string', value: ['foo', 'bar'] },
+          { type: 'PropertyValue', name: 'non-string', value: %w(foo bar) },
         ],
       }.with_indifferent_access
     end
@@ -31,6 +33,8 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
   end
 
   context 'when account is not suspended' do
+    subject { described_class.new.call('alice', 'example.com', payload) }
+
     let!(:account) { Fabricate(:account, username: 'alice', domain: 'example.com') }
 
     let(:payload) do
@@ -46,8 +50,6 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
       allow(Admin::SuspensionWorker).to receive(:perform_async)
     end
 
-    subject { described_class.new.call('alice', 'example.com', payload) }
-
     it 'suspends account remotely' do
       expect(subject.suspended?).to be true
       expect(subject.suspension_origin_remote?).to be true
@@ -60,6 +62,8 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
   end
 
   context 'when account is suspended' do
+    subject { described_class.new.call('alice', 'example.com', payload) }
+
     let!(:account) { Fabricate(:account, username: 'alice', domain: 'example.com', display_name: '') }
 
     let(:payload) do
@@ -78,8 +82,6 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
       account.suspend!(origin: suspension_origin)
     end
 
-    subject { described_class.new.call('alice', 'example.com', payload) }
-
     context 'locally' do
       let(:suspension_origin) { :local }
 
@@ -172,10 +174,10 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
             {
               type: 'Mention',
               href: "https://foo.test/users/#{i + 1}",
-              name: "@user#{i + 1 }",
-            }
+              name: "@user#{i + 1}",
+            },
           ],
-          to: [ 'as:Public', "https://foo.test/users/#{i + 1}" ]
+          to: ['as:Public', "https://foo.test/users/#{i + 1}"],
         }.with_indifferent_access
         featured_json = {
           '@context': ['https://www.w3.org/ns/activitystreams'],
diff --git a/spec/services/activitypub/process_collection_service_spec.rb b/spec/services/activitypub/process_collection_service_spec.rb
index 093a188a2..1433d0c50 100644
--- a/spec/services/activitypub/process_collection_service_spec.rb
+++ b/spec/services/activitypub/process_collection_service_spec.rb
@@ -1,6 +1,10 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
+  subject { described_class.new }
+
   let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }
 
   let(:payload) do
@@ -19,8 +23,6 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
 
   let(:json) { Oj.dump(payload) }
 
-  subject { described_class.new }
-
   describe '#call' do
     context 'when actor is suspended' do
       before do
@@ -39,7 +41,7 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
           end
 
           it 'does not process payload' do
-            expect(ActivityPub::Activity).not_to receive(:factory)
+            expect(ActivityPub::Activity).to_not receive(:factory)
             subject.call(json, actor)
           end
         end
@@ -69,7 +71,7 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
 
       it 'does not process payload if no signature exists' do
         expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
-        expect(ActivityPub::Activity).not_to receive(:factory)
+        expect(ActivityPub::Activity).to_not receive(:factory)
 
         subject.call(json, forwarder)
       end
@@ -87,7 +89,7 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
         payload['signature'] = { 'type' => 'RsaSignature2017' }
 
         expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
-        expect(ActivityPub::Activity).not_to receive(:factory)
+        expect(ActivityPub::Activity).to_not receive(:factory)
 
         subject.call(json, forwarder)
       end
@@ -95,11 +97,11 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
       context 'when receiving a fabricated status' do
         let!(:actor) do
           Fabricate(:account,
-            username: 'bob',
-            domain: 'example.com',
-            uri: 'https://example.com/users/bob',
-            public_key: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuuYyoyfsRkYnXRotMsId\nW3euBDDfiv9oVqOxUVC7bhel8KednIMrMCRWFAkgJhbrlzbIkjVr68o1MP9qLcn7\nCmH/BXHp7yhuFTr4byjdJKpwB+/i2jNEsvDH5jR8WTAeTCe0x/QHg21V3F7dSI5m\nCCZ/1dSIyOXLRTWVlfDlm3rE4ntlCo+US3/7oSWbg/4/4qEnt1HC32kvklgScxua\n4LR5ATdoXa5bFoopPWhul7MJ6NyWCyQyScUuGdlj8EN4kmKQJvphKHrI9fvhgOuG\nTvhTR1S5InA4azSSchY0tXEEw/VNxraeX0KPjbgr6DPcwhPd/m0nhVDq0zVyVBBD\nMwIDAQAB\n-----END PUBLIC KEY-----\n",
-            private_key: nil)
+                    username: 'bob',
+                    domain: 'example.com',
+                    uri: 'https://example.com/users/bob',
+                    public_key: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuuYyoyfsRkYnXRotMsId\nW3euBDDfiv9oVqOxUVC7bhel8KednIMrMCRWFAkgJhbrlzbIkjVr68o1MP9qLcn7\nCmH/BXHp7yhuFTr4byjdJKpwB+/i2jNEsvDH5jR8WTAeTCe0x/QHg21V3F7dSI5m\nCCZ/1dSIyOXLRTWVlfDlm3rE4ntlCo+US3/7oSWbg/4/4qEnt1HC32kvklgScxua\n4LR5ATdoXa5bFoopPWhul7MJ6NyWCyQyScUuGdlj8EN4kmKQJvphKHrI9fvhgOuG\nTvhTR1S5InA4azSSchY0tXEEw/VNxraeX0KPjbgr6DPcwhPd/m0nhVDq0zVyVBBD\nMwIDAQAB\n-----END PUBLIC KEY-----\n",
+                    private_key: nil)
         end
 
         let(:payload) do
@@ -107,48 +109,48 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
             '@context': [
               'https://www.w3.org/ns/activitystreams',
               nil,
-              {'object': 'https://www.w3.org/ns/activitystreams#object'}
+              { object: 'https://www.w3.org/ns/activitystreams#object' },
             ],
-            'id': 'https://example.com/users/bob/fake-status/activity',
-            'type': 'Create',
-            'actor': 'https://example.com/users/bob',
-            'published': '2022-01-22T15:00:00Z',
-            'to': [
-              'https://www.w3.org/ns/activitystreams#Public'
+            id: 'https://example.com/users/bob/fake-status/activity',
+            type: 'Create',
+            actor: 'https://example.com/users/bob',
+            published: '2022-01-22T15:00:00Z',
+            to: [
+              'https://www.w3.org/ns/activitystreams#Public',
             ],
-            'cc': [
-              'https://example.com/users/bob/followers'
+            cc: [
+              'https://example.com/users/bob/followers',
             ],
-            'signature': {
-              'type': 'RsaSignature2017',
-              'creator': 'https://example.com/users/bob#main-key',
-              'created': '2022-03-09T21:57:25Z',
-              'signatureValue': 'WculK0LelTQ0MvGwU9TPoq5pFzFfGYRDCJqjZ232/Udj4CHqDTGOSw5UTDLShqBOyycCkbZGrQwXG+dpyDpQLSe1UVPZ5TPQtc/9XtI57WlS2nMNpdvRuxGnnb2btPdesXZ7n3pCxo0zjaXrJMe0mqQh5QJO22mahb4bDwwmfTHgbD3nmkD+fBfGi+UV2qWwqr+jlV4L4JqNkh0gWljF5KTePLRRZCuWiQ/FAt7c67636cdIPf7fR+usjuZltTQyLZKEGuK8VUn2Gkfsx5qns7Vcjvlz1JqlAjyO8HPBbzTTHzUG2nUOIgC3PojCSWv6mNTmRGoLZzOscCAYQA6cKw=='
+            signature: {
+              type: 'RsaSignature2017',
+              creator: 'https://example.com/users/bob#main-key',
+              created: '2022-03-09T21:57:25Z',
+              signatureValue: 'WculK0LelTQ0MvGwU9TPoq5pFzFfGYRDCJqjZ232/Udj4CHqDTGOSw5UTDLShqBOyycCkbZGrQwXG+dpyDpQLSe1UVPZ5TPQtc/9XtI57WlS2nMNpdvRuxGnnb2btPdesXZ7n3pCxo0zjaXrJMe0mqQh5QJO22mahb4bDwwmfTHgbD3nmkD+fBfGi+UV2qWwqr+jlV4L4JqNkh0gWljF5KTePLRRZCuWiQ/FAt7c67636cdIPf7fR+usjuZltTQyLZKEGuK8VUn2Gkfsx5qns7Vcjvlz1JqlAjyO8HPBbzTTHzUG2nUOIgC3PojCSWv6mNTmRGoLZzOscCAYQA6cKw==',
             },
             '@id': 'https://example.com/users/bob/statuses/107928807471117876/activity',
             '@type': 'https://www.w3.org/ns/activitystreams#Create',
             'https://www.w3.org/ns/activitystreams#actor': {
-              '@id': 'https://example.com/users/bob'
+              '@id': 'https://example.com/users/bob',
             },
             'https://www.w3.org/ns/activitystreams#cc': {
-              '@id': 'https://example.com/users/bob/followers'
+              '@id': 'https://example.com/users/bob/followers',
             },
-            'object': {
-              'id': 'https://example.com/users/bob/fake-status',
-              'type': 'Note',
-              'published': '2022-01-22T15:00:00Z',
-              'url': 'https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=puck-was-here',
-              'attributedTo': 'https://example.com/users/bob',
-              'to': [
-                'https://www.w3.org/ns/activitystreams#Public'
+            object: {
+              id: 'https://example.com/users/bob/fake-status',
+              type: 'Note',
+              published: '2022-01-22T15:00:00Z',
+              url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=puck-was-here',
+              attributedTo: 'https://example.com/users/bob',
+              to: [
+                'https://www.w3.org/ns/activitystreams#Public',
               ],
-              'cc': [
-                'https://example.com/users/bob/followers'
+              cc: [
+                'https://example.com/users/bob/followers',
               ],
-              'sensitive': false,
-              'atomUri': 'https://example.com/users/bob/fake-status',
-              'conversation': 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation',
-              'content': '<p>puck was here</p>',
+              sensitive: false,
+              atomUri: 'https://example.com/users/bob/fake-status',
+              conversation: 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation',
+              content: '<p>puck was here</p>',
 
               '@id': 'https://example.com/users/bob/statuses/107928807471117876',
               '@type': 'https://www.w3.org/ns/activitystreams#Note',
@@ -156,21 +158,21 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
               'http://ostatus.org#conversation': 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation',
               'https://www.w3.org/ns/activitystreams#attachment': [],
               'https://www.w3.org/ns/activitystreams#attributedTo': {
-                '@id': 'https://example.com/users/bob'
+                '@id': 'https://example.com/users/bob',
               },
               'https://www.w3.org/ns/activitystreams#cc': {
-                '@id': 'https://example.com/users/bob/followers'
+                '@id': 'https://example.com/users/bob/followers',
               },
               'https://www.w3.org/ns/activitystreams#content': [
                 '<p>hello world</p>',
                 {
                   '@value': '<p>hello world</p>',
-                  '@language': 'en'
-                }
+                  '@language': 'en',
+                },
               ],
               'https://www.w3.org/ns/activitystreams#published': {
                 '@type': 'http://www.w3.org/2001/XMLSchema#dateTime',
-                '@value': '2022-03-09T21:55:07Z'
+                '@value': '2022-03-09T21:55:07Z',
               },
               'https://www.w3.org/ns/activitystreams#replies': {
                 '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies',
@@ -179,51 +181,51 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
                   '@type': 'https://www.w3.org/ns/activitystreams#CollectionPage',
                   'https://www.w3.org/ns/activitystreams#items': [],
                   'https://www.w3.org/ns/activitystreams#next': {
-                    '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies?only_other_accounts=true&page=true'
+                    '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies?only_other_accounts=true&page=true',
                   },
                   'https://www.w3.org/ns/activitystreams#partOf': {
-                    '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies'
-                  }
-                }
+                    '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies',
+                  },
+                },
               },
               'https://www.w3.org/ns/activitystreams#sensitive': false,
               'https://www.w3.org/ns/activitystreams#tag': [],
               'https://www.w3.org/ns/activitystreams#to': {
-                '@id': 'https://www.w3.org/ns/activitystreams#Public'
+                '@id': 'https://www.w3.org/ns/activitystreams#Public',
               },
               'https://www.w3.org/ns/activitystreams#url': {
-                '@id': 'https://example.com/@bob/107928807471117876'
-              }
+                '@id': 'https://example.com/@bob/107928807471117876',
+              },
             },
             'https://www.w3.org/ns/activitystreams#published': {
               '@type': 'http://www.w3.org/2001/XMLSchema#dateTime',
-              '@value': '2022-03-09T21:55:07Z'
+              '@value': '2022-03-09T21:55:07Z',
             },
             'https://www.w3.org/ns/activitystreams#to': {
-              '@id': 'https://www.w3.org/ns/activitystreams#Public'
-            }
+              '@id': 'https://www.w3.org/ns/activitystreams#Public',
+            },
           }
         end
 
         it 'does not process forged payload' do
-          expect(ActivityPub::Activity).not_to receive(:factory).with(
+          expect(ActivityPub::Activity).to_not receive(:factory).with(
             hash_including(
               'object' => hash_including(
                 'id' => 'https://example.com/users/bob/fake-status'
               )
             ),
-            anything(),
-            anything()
+            anything,
+            anything
           )
 
-          expect(ActivityPub::Activity).not_to receive(:factory).with(
+          expect(ActivityPub::Activity).to_not receive(:factory).with(
             hash_including(
               'object' => hash_including(
                 'content' => '<p>puck was here</p>'
               )
             ),
-            anything(),
-            anything()
+            anything,
+            anything
           )
 
           subject.call(json, forwarder)
diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb
index 750369d57..e9f23b9cf 100644
--- a/spec/services/activitypub/process_status_update_service_spec.rb
+++ b/spec/services/activitypub/process_status_update_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 def poll_option_json(name, votes)
@@ -5,21 +7,9 @@ def poll_option_json(name, votes)
 end
 
 RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
-  let!(:status) { Fabricate(:status, text: 'Hello world', account: Fabricate(:account, domain: 'example.com')) }
-
-  let(:alice) { Fabricate(:account) }
-  let(:bob) { Fabricate(:account) }
-
-  let(:mentions) { [] }
-  let(:tags) { [] }
-  let(:media_attachments) { [] }
-
-  before do
-    mentions.each { |a| Fabricate(:mention, status: status, account: a) }
-    tags.each { |t| status.tags << t }
-    media_attachments.each { |m| status.media_attachments << m }
-  end
+  subject { described_class.new }
 
+  let!(:status) { Fabricate(:status, text: 'Hello world', account: Fabricate(:account, domain: 'example.com')) }
   let(:payload) do
     {
       '@context': 'https://www.w3.org/ns/activitystreams',
@@ -34,10 +24,20 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
       ],
     }
   end
-
   let(:json) { Oj.load(Oj.dump(payload)) }
 
-  subject { described_class.new }
+  let(:alice) { Fabricate(:account) }
+  let(:bob) { Fabricate(:account) }
+
+  let(:mentions) { [] }
+  let(:tags) { [] }
+  let(:media_attachments) { [] }
+
+  before do
+    mentions.each { |a| Fabricate(:mention, status: status, account: a) }
+    tags.each { |t| status.tags << t }
+    media_attachments.each { |m| status.media_attachments << m }
+  end
 
   describe '#call' do
     it 'updates text' do
@@ -104,20 +104,19 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
     end
 
     context 'when the status has not been explicitly edited and features a poll' do
-      let(:account)    { Fabricate(:account, domain: 'example.com') }
+      let(:account) { Fabricate(:account, domain: 'example.com') }
       let!(:expiration) { 10.days.from_now.utc }
       let!(:status) do
         Fabricate(:status,
-          text: 'Hello world',
-          account: account,
-          poll_attributes: {
-            options: %w(Foo Bar),
-            account: account,
-            multiple: false,
-            hide_totals: false,
-            expires_at: expiration
-          }
-        )
+                  text: 'Hello world',
+                  account: account,
+                  poll_attributes: {
+                    options: %w(Foo Bar),
+                    account: account,
+                    multiple: false,
+                    hide_totals: false,
+                    expires_at: expiration,
+                  })
       end
 
       let(:payload) do
@@ -156,20 +155,19 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
     end
 
     context 'when the status changes a poll despite being not explicitly marked as updated' do
-      let(:account)    { Fabricate(:account, domain: 'example.com') }
+      let(:account) { Fabricate(:account, domain: 'example.com') }
       let!(:expiration) { 10.days.from_now.utc }
       let!(:status) do
         Fabricate(:status,
-          text: 'Hello world',
-          account: account,
-          poll_attributes: {
-            options: %w(Foo Bar),
-            account: account,
-            multiple: false,
-            hide_totals: false,
-            expires_at: expiration
-          }
-        )
+                  text: 'Hello world',
+                  account: account,
+                  poll_attributes: {
+                    options: %w(Foo Bar),
+                    account: account,
+                    multiple: false,
+                    hide_totals: false,
+                    expires_at: expiration,
+                  })
       end
 
       let(:payload) do
@@ -216,11 +214,11 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
       end
 
       it 'does not create any edits' do
-        expect { subject.call(status, json) }.not_to change { status.reload.edits.pluck(&:id) }
+        expect { subject.call(status, json) }.to_not change { status.reload.edits.pluck(&:id) }
       end
 
       it 'does not update the text, spoiler_text or edited_at' do
-        expect { subject.call(status, json) }.not_to change { s = status.reload; [s.text, s.spoiler_text, s.edited_at] }
+        expect { subject.call(status, json) }.to_not change { s = status.reload; [s.text, s.spoiler_text, s.edited_at] }
       end
     end
 
@@ -344,7 +342,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
           updated: '2021-09-08T22:39:25Z',
           attachment: [
             { type: 'Image', mediaType: 'image/png', url: 'https://example.com/foo.png' },
-          ]
+          ],
         }
       end
 
@@ -376,7 +374,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
           updated: '2021-09-08T22:39:25Z',
           attachment: [
             { type: 'Image', mediaType: 'image/png', url: 'https://example.com/foo.png', name: 'A picture' },
-          ]
+          ],
         }
       end
 
@@ -414,7 +412,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
       end
 
       it 'removes poll' do
-        expect(status.reload.poll).to eq nil
+        expect(status.reload.poll).to be_nil
       end
 
       it 'records media change in edit' do
diff --git a/spec/services/activitypub/synchronize_followers_service_spec.rb b/spec/services/activitypub/synchronize_followers_service_spec.rb
index 75dcf204b..c9a513e24 100644
--- a/spec/services/activitypub/synchronize_followers_service_spec.rb
+++ b/spec/services/activitypub/synchronize_followers_service_spec.rb
@@ -1,6 +1,10 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
+  subject { described_class.new }
+
   let(:actor)          { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account', inbox_url: 'http://example.com/inbox') }
   let(:alice)          { Fabricate(:account, username: 'alice') }
   let(:bob)            { Fabricate(:account, username: 'bob') }
@@ -25,8 +29,6 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
     }.with_indifferent_access
   end
 
-  subject { described_class.new }
-
   shared_examples 'synchronizes followers' do
     before do
       alice.follow!(actor)
@@ -91,7 +93,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
             type: 'CollectionPage',
             partOf: collection_uri,
             items: items,
-          }
+          },
         }.with_indifferent_access
       end
 
diff --git a/spec/services/after_block_domain_from_account_service_spec.rb b/spec/services/after_block_domain_from_account_service_spec.rb
index 006e3f4d2..b75f92372 100644
--- a/spec/services/after_block_domain_from_account_service_spec.rb
+++ b/spec/services/after_block_domain_from_account_service_spec.rb
@@ -1,11 +1,13 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe AfterBlockDomainFromAccountService, type: :service do
+  subject { AfterBlockDomainFromAccountService.new }
+
   let!(:wolf) { Fabricate(:account, username: 'wolf', domain: 'evil.org', inbox_url: 'https://evil.org/inbox', protocol: :activitypub) }
   let!(:alice) { Fabricate(:account, username: 'alice') }
 
-  subject { AfterBlockDomainFromAccountService.new }
-
   before do
     stub_jsonld_contexts!
     allow(ActivityPub::DeliveryWorker).to receive(:perform_async)
diff --git a/spec/services/after_block_service_spec.rb b/spec/services/after_block_service_spec.rb
index 337766d06..d81bba1d8 100644
--- a/spec/services/after_block_service_spec.rb
+++ b/spec/services/after_block_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe AfterBlockService, type: :service do
diff --git a/spec/services/app_sign_up_service_spec.rb b/spec/services/app_sign_up_service_spec.rb
index 8ec4d4a7a..253230496 100644
--- a/spec/services/app_sign_up_service_spec.rb
+++ b/spec/services/app_sign_up_service_spec.rb
@@ -1,12 +1,14 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe AppSignUpService, type: :service do
+  subject { described_class.new }
+
   let(:app) { Fabricate(:application, scopes: 'read write') }
   let(:good_params) { { username: 'alice', password: '12345678', email: 'good@email.com', agreement: true } }
   let(:remote_ip) { IPAddr.new('198.0.2.1') }
 
-  subject { described_class.new }
-
   describe '#call' do
     it 'returns nil when registrations are closed' do
       tmp = Setting.registrations_mode
diff --git a/spec/services/authorize_follow_service_spec.rb b/spec/services/authorize_follow_service_spec.rb
index 888d694b6..63d9e2a0f 100644
--- a/spec/services/authorize_follow_service_spec.rb
+++ b/spec/services/authorize_follow_service_spec.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe AuthorizeFollowService, type: :service do
-  let(:sender) { Fabricate(:account, username: 'alice') }
-
   subject { AuthorizeFollowService.new }
 
+  let(:sender) { Fabricate(:account, username: 'alice') }
+
   describe 'local' do
     let(:bob) { Fabricate(:account, username: 'bob') }
 
diff --git a/spec/services/batched_remove_status_service_spec.rb b/spec/services/batched_remove_status_service_spec.rb
index 920edeb13..9bedf3744 100644
--- a/spec/services/batched_remove_status_service_spec.rb
+++ b/spec/services/batched_remove_status_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe BatchedRemoveStatusService, type: :service do
diff --git a/spec/services/block_domain_service_spec.rb b/spec/services/block_domain_service_spec.rb
index 242b02fff..0ab97b8ce 100644
--- a/spec/services/block_domain_service_spec.rb
+++ b/spec/services/block_domain_service_spec.rb
@@ -1,14 +1,16 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe BlockDomainService, type: :service do
+  subject { BlockDomainService.new }
+
   let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
   let!(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }
   let!(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
   let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status2, file: attachment_fixture('attachment.jpg')) }
   let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: 'evil.org', suspended: true, silenced: true) }
 
-  subject { BlockDomainService.new }
-
   describe 'for a suspension' do
     before do
       subject.call(DomainBlock.create!(domain: 'evil.org', severity: :suspend))
@@ -67,9 +69,9 @@ RSpec.describe BlockDomainService, type: :service do
     end
 
     it 'leaves the domains status and attachments, but clears media' do
-      expect { bad_status1.reload }.not_to raise_error
-      expect { bad_status2.reload }.not_to raise_error
-      expect { bad_attachment.reload }.not_to raise_error
+      expect { bad_status1.reload }.to_not raise_error
+      expect { bad_status2.reload }.to_not raise_error
+      expect { bad_attachment.reload }.to_not raise_error
       expect(bad_attachment.file.exists?).to be false
     end
   end
diff --git a/spec/services/block_service_spec.rb b/spec/services/block_service_spec.rb
index a53e1f928..75f07f5ad 100644
--- a/spec/services/block_service_spec.rb
+++ b/spec/services/block_service_spec.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe BlockService, type: :service do
-  let(:sender) { Fabricate(:account, username: 'alice') }
-
   subject { BlockService.new }
 
+  let(:sender) { Fabricate(:account, username: 'alice') }
+
   describe 'local' do
     let(:bob) { Fabricate(:account, username: 'bob') }
 
diff --git a/spec/services/bootstrap_timeline_service_spec.rb b/spec/services/bootstrap_timeline_service_spec.rb
index 16f3e9962..670ac652f 100644
--- a/spec/services/bootstrap_timeline_service_spec.rb
+++ b/spec/services/bootstrap_timeline_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe BootstrapTimelineService, type: :service do
@@ -32,6 +34,5 @@ RSpec.describe BootstrapTimelineService, type: :service do
         expect(service).to_not have_received(:call)
       end
     end
-
   end
 end
diff --git a/spec/services/clear_domain_media_service_spec.rb b/spec/services/clear_domain_media_service_spec.rb
index 45b92e2c9..987507579 100644
--- a/spec/services/clear_domain_media_service_spec.rb
+++ b/spec/services/clear_domain_media_service_spec.rb
@@ -1,22 +1,24 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ClearDomainMediaService, type: :service do
+  subject { ClearDomainMediaService.new }
+
   let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
   let!(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }
   let!(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
   let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status2, file: attachment_fixture('attachment.jpg')) }
 
-  subject { ClearDomainMediaService.new }
-
   describe 'for a silence with reject media' do
     before do
       subject.call(DomainBlock.create!(domain: 'evil.org', severity: :silence, reject_media: true))
     end
 
     it 'leaves the domains status and attachments, but clears media' do
-      expect { bad_status1.reload }.not_to raise_error
-      expect { bad_status2.reload }.not_to raise_error
-      expect { bad_attachment.reload }.not_to raise_error
+      expect { bad_status1.reload }.to_not raise_error
+      expect { bad_status2.reload }.to_not raise_error
+      expect { bad_attachment.reload }.to_not raise_error
       expect(bad_attachment.file.exists?).to be false
     end
   end
diff --git a/spec/services/delete_account_service_spec.rb b/spec/services/delete_account_service_spec.rb
index 1fbe4d07c..61e5c3c9b 100644
--- a/spec/services/delete_account_service_spec.rb
+++ b/spec/services/delete_account_service_spec.rb
@@ -1,7 +1,11 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe DeleteAccountService, type: :service do
   shared_examples 'common behavior' do
+    subject { described_class.new.call(account) }
+
     let!(:status) { Fabricate(:status, account: account) }
     let!(:mention) { Fabricate(:mention, account: local_follower) }
     let!(:status_with_mention) { Fabricate(:status, account: account, mentions: [mention]) }
@@ -23,8 +27,6 @@ RSpec.describe DeleteAccountService, type: :service do
 
     let!(:account_note) { Fabricate(:account_note, account: account) }
 
-    subject { described_class.new.call(account) }
-
     it 'deletes associated owned records' do
       expect { subject }.to change {
         [
@@ -50,17 +52,17 @@ RSpec.describe DeleteAccountService, type: :service do
 
     it 'deletes associated target notifications' do
       expect { subject }.to change {
-        [
-          'poll', 'favourite', 'status', 'mention', 'follow'
-        ].map { |type| Notification.where(type: type).count }
+        %w(
+          poll favourite status mention follow
+        ).map { |type| Notification.where(type: type).count }
       }.from([1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0])
     end
   end
 
   describe '#call on local account' do
     before do
-      stub_request(:post, "https://alice.com/inbox").to_return(status: 201)
-      stub_request(:post, "https://bob.com/inbox").to_return(status: 201)
+      stub_request(:post, 'https://alice.com/inbox').to_return(status: 201)
+      stub_request(:post, 'https://bob.com/inbox').to_return(status: 201)
     end
 
     let!(:remote_alice) { Fabricate(:account, inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }
@@ -72,16 +74,16 @@ RSpec.describe DeleteAccountService, type: :service do
 
       it 'sends a delete actor activity to all known inboxes' do
         subject
-        expect(a_request(:post, "https://alice.com/inbox")).to have_been_made.once
-        expect(a_request(:post, "https://bob.com/inbox")).to have_been_made.once
+        expect(a_request(:post, 'https://alice.com/inbox')).to have_been_made.once
+        expect(a_request(:post, 'https://bob.com/inbox')).to have_been_made.once
       end
     end
   end
 
   describe '#call on remote account' do
     before do
-      stub_request(:post, "https://alice.com/inbox").to_return(status: 201)
-      stub_request(:post, "https://bob.com/inbox").to_return(status: 201)
+      stub_request(:post, 'https://alice.com/inbox').to_return(status: 201)
+      stub_request(:post, 'https://bob.com/inbox').to_return(status: 201)
     end
 
     include_examples 'common behavior' do
diff --git a/spec/services/fan_out_on_write_service_spec.rb b/spec/services/fan_out_on_write_service_spec.rb
index 59e15d230..3b554f9ea 100644
--- a/spec/services/fan_out_on_write_service_spec.rb
+++ b/spec/services/fan_out_on_write_service_spec.rb
@@ -1,16 +1,17 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe FanOutOnWriteService, type: :service do
+  subject { described_class.new }
+
   let(:last_active_at) { Time.now.utc }
+  let(:status) { Fabricate(:status, account: alice, visibility: visibility, text: 'Hello @bob #hoge') }
 
   let!(:alice) { Fabricate(:user, current_sign_in_at: last_active_at).account }
   let!(:bob)   { Fabricate(:user, current_sign_in_at: last_active_at, account_attributes: { username: 'bob' }).account }
   let!(:tom)   { Fabricate(:user, current_sign_in_at: last_active_at).account }
 
-  subject { described_class.new }
-
-  let(:status) { Fabricate(:status, account: alice, visibility: visibility, text: 'Hello @bob #hoge') }
-
   before do
     bob.follow!(alice)
     tom.follow!(alice)
diff --git a/spec/services/favourite_service_spec.rb b/spec/services/favourite_service_spec.rb
index 9781f0d78..613ae203e 100644
--- a/spec/services/favourite_service_spec.rb
+++ b/spec/services/favourite_service_spec.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe FavouriteService, type: :service do
-  let(:sender) { Fabricate(:account, username: 'alice') }
-
   subject { FavouriteService.new }
 
+  let(:sender) { Fabricate(:account, username: 'alice') }
+
   describe 'local' do
     let(:bob)    { Fabricate(:account) }
     let(:status) { Fabricate(:status, account: bob) }
@@ -23,7 +25,7 @@ RSpec.describe FavouriteService, type: :service do
     let(:status) { Fabricate(:status, account: bob) }
 
     before do
-      stub_request(:post, "http://example.com/inbox").to_return(status: 200, body: "", headers: {})
+      stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {})
       subject.call(sender, status)
     end
 
@@ -32,7 +34,7 @@ RSpec.describe FavouriteService, type: :service do
     end
 
     it 'sends a like activity' do
-      expect(a_request(:post, "http://example.com/inbox")).to have_been_made.once
+      expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
     end
   end
 end
diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb
index 4914c2753..d79ab7a43 100644
--- a/spec/services/fetch_link_card_service_spec.rb
+++ b/spec/services/fetch_link_card_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe FetchLinkCardService, type: :service do
@@ -30,7 +32,7 @@ RSpec.describe FetchLinkCardService, type: :service do
 
       it 'works with SJIS' do
         expect(a_request(:get, 'http://example.com/sjis')).to have_been_made.at_least_once
-        expect(status.preview_cards.first.title).to eq("SJISのページ")
+        expect(status.preview_cards.first.title).to eq('SJISのページ')
       end
     end
 
@@ -39,7 +41,7 @@ RSpec.describe FetchLinkCardService, type: :service do
 
       it 'works with SJIS even with wrong charset header' do
         expect(a_request(:get, 'http://example.com/sjis_with_wrong_charset')).to have_been_made.at_least_once
-        expect(status.preview_cards.first.title).to eq("SJISのページ")
+        expect(status.preview_cards.first.title).to eq('SJISのページ')
       end
     end
 
@@ -48,7 +50,7 @@ RSpec.describe FetchLinkCardService, type: :service do
 
       it 'works with koi8-r' do
         expect(a_request(:get, 'http://example.com/koi8-r')).to have_been_made.at_least_once
-        expect(status.preview_cards.first.title).to eq("Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.")
+        expect(status.preview_cards.first.title).to eq('Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.')
       end
     end
 
@@ -66,7 +68,7 @@ RSpec.describe FetchLinkCardService, type: :service do
 
       it 'works with Japanese path string' do
         expect(a_request(:get, 'http://example.com/日本語')).to have_been_made.at_least_once
-        expect(status.preview_cards.first.title).to eq("SJISのページ")
+        expect(status.preview_cards.first.title).to eq('SJISのページ')
       end
     end
 
diff --git a/spec/services/fetch_oembed_service_spec.rb b/spec/services/fetch_oembed_service_spec.rb
index 88f0113ed..8a0b49222 100644
--- a/spec/services/fetch_oembed_service_spec.rb
+++ b/spec/services/fetch_oembed_service_spec.rb
@@ -6,9 +6,9 @@ describe FetchOEmbedService, type: :service do
   subject { described_class.new }
 
   before do
-    stub_request(:get, "https://host.test/provider.json").to_return(status: 404)
-    stub_request(:get, "https://host.test/provider.xml").to_return(status: 404)
-    stub_request(:get, "https://host.test/empty_provider.json").to_return(status: 200)
+    stub_request(:get, 'https://host.test/provider.json').to_return(status: 404)
+    stub_request(:get, 'https://host.test/provider.xml').to_return(status: 404)
+    stub_request(:get, 'https://host.test/empty_provider.json').to_return(status: 200)
   end
 
   describe 'discover_provider' do
@@ -18,7 +18,7 @@ describe FetchOEmbedService, type: :service do
           stub_request(:get, 'https://www.youtube.com/watch?v=IPSbNdBmWKE').to_return(
             status: 200,
             headers: { 'Content-Type': 'text/html' },
-            body: request_fixture('oembed_youtube.html'),
+            body: request_fixture('oembed_youtube.html')
           )
           stub_request(:get, 'https://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DIPSbNdBmWKE').to_return(
             status: 200,
@@ -62,7 +62,7 @@ describe FetchOEmbedService, type: :service do
 
         it 'does not cache OEmbed endpoint' do
           subject.call('https://host.test/oembed.html', format: :xml)
-          expect(Rails.cache.exist?('oembed_endpoint:host.test')).to eq false
+          expect(Rails.cache.exist?('oembed_endpoint:host.test')).to be false
         end
       end
 
@@ -83,7 +83,7 @@ describe FetchOEmbedService, type: :service do
 
         it 'does not cache OEmbed endpoint' do
           subject.call('https://host.test/oembed.html')
-          expect(Rails.cache.exist?('oembed_endpoint:host.test')).to eq false
+          expect(Rails.cache.exist?('oembed_endpoint:host.test')).to be false
         end
       end
 
@@ -104,7 +104,7 @@ describe FetchOEmbedService, type: :service do
 
         it 'does not cache OEmbed endpoint' do
           subject.call('https://host.test/oembed.html')
-          expect(Rails.cache.exist?('oembed_endpoint:host.test')).to eq false
+          expect(Rails.cache.exist?('oembed_endpoint:host.test')).to be false
         end
       end
 
@@ -151,7 +151,6 @@ describe FetchOEmbedService, type: :service do
           expect(subject.format).to eq :json
         end
       end
-
     end
 
     context 'when endpoint is cached' do
diff --git a/spec/services/fetch_remote_status_service_spec.rb b/spec/services/fetch_remote_status_service_spec.rb
index fe5f1aed1..694a75dc2 100644
--- a/spec/services/fetch_remote_status_service_spec.rb
+++ b/spec/services/fetch_remote_status_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe FetchRemoteStatusService, type: :service do
@@ -7,7 +9,7 @@ RSpec.describe FetchRemoteStatusService, type: :service do
   let(:note) do
     {
       '@context': 'https://www.w3.org/ns/activitystreams',
-      id: "https://example.org/@foo/1234",
+      id: 'https://example.org/@foo/1234',
       type: 'Note',
       content: 'Lorem ipsum',
       attributedTo: ActivityPub::TagManager.instance.uri_for(account),
@@ -15,7 +17,8 @@ RSpec.describe FetchRemoteStatusService, type: :service do
   end
 
   context 'protocol is :activitypub' do
-    subject { described_class.new.call(note[:id], prefetched_body) }
+    subject { described_class.new.call(note[:id], prefetched_body: prefetched_body) }
+
     let(:prefetched_body) { Oj.dump(note) }
 
     before do
diff --git a/spec/services/fetch_resource_service_spec.rb b/spec/services/fetch_resource_service_spec.rb
index c0c96ab69..da7e42351 100644
--- a/spec/services/fetch_resource_service_spec.rb
+++ b/spec/services/fetch_resource_service_spec.rb
@@ -1,13 +1,16 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe FetchResourceService, type: :service do
   describe '#call' do
-    let(:url) { 'http://example.com' }
-
     subject { described_class.new.call(url) }
 
+    let(:url) { 'http://example.com' }
+
     context 'with blank url' do
       let(:url) { '' }
+
       it { is_expected.to be_nil }
     end
 
@@ -21,7 +24,7 @@ RSpec.describe FetchResourceService, type: :service do
 
     context 'when OpenSSL::SSL::SSLError is raised' do
       before do
-        request = double()
+        request = double
         allow(Request).to receive(:new).and_return(request)
         allow(request).to receive(:add_headers)
         allow(request).to receive(:on_behalf_of)
@@ -33,7 +36,7 @@ RSpec.describe FetchResourceService, type: :service do
 
     context 'when HTTP::ConnectionError is raised' do
       before do
-        request = double()
+        request = double
         allow(Request).to receive(:new).and_return(request)
         allow(request).to receive(:add_headers)
         allow(request).to receive(:on_behalf_of)
@@ -62,6 +65,7 @@ RSpec.describe FetchResourceService, type: :service do
 
       before do
         stub_request(:get, url).to_return(status: 200, body: body, headers: headers)
+        stub_request(:get, 'http://example.com/foo').to_return(status: 200, body: json, headers: { 'Content-Type' => 'application/activity+json' })
       end
 
       it 'signs request' do
@@ -72,7 +76,7 @@ RSpec.describe FetchResourceService, type: :service do
       context 'when content type is application/atom+xml' do
         let(:content_type) { 'application/atom+xml' }
 
-        it { is_expected.to eq nil }
+        it { is_expected.to be_nil }
       end
 
       context 'when content type is activity+json' do
@@ -89,13 +93,8 @@ RSpec.describe FetchResourceService, type: :service do
         it { is_expected.to eq [1, { prefetched_body: body, id: true }] }
       end
 
-      before do
-        stub_request(:get, url).to_return(status: 200, body: body, headers: headers)
-        stub_request(:get, 'http://example.com/foo').to_return(status: 200, body: json, headers: { 'Content-Type' => 'application/activity+json' })
-      end
-
       context 'when link header is present' do
-        let(:headers) { { 'Link' => '<http://example.com/foo>; rel="alternate"; type="application/activity+json"', } }
+        let(:headers) { { 'Link' => '<http://example.com/foo>; rel="alternate"; type="application/activity+json"' } }
 
         it { is_expected.to eq [1, { prefetched_body: json, id: true }] }
       end
diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb
index 412c04d76..67a8b2c54 100644
--- a/spec/services/follow_service_spec.rb
+++ b/spec/services/follow_service_spec.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe FollowService, type: :service do
-  let(:sender) { Fabricate(:account, username: 'alice') }
-
   subject { FollowService.new }
 
+  let(:sender) { Fabricate(:account, username: 'alice') }
+
   context 'local account' do
     describe 'locked account' do
       let(:bob) { Fabricate(:account, locked: true, username: 'bob') }
@@ -140,7 +142,7 @@ RSpec.describe FollowService, type: :service do
     let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') }
 
     before do
-      stub_request(:post, "http://example.com/inbox").to_return(status: 200, body: "", headers: {})
+      stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {})
       subject.call(sender, bob)
     end
 
diff --git a/spec/services/import_service_spec.rb b/spec/services/import_service_spec.rb
index e2d182920..f081f2d9d 100644
--- a/spec/services/import_service_spec.rb
+++ b/spec/services/import_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ImportService, type: :service do
@@ -8,7 +10,7 @@ RSpec.describe ImportService, type: :service do
   let!(:eve)     { Fabricate(:account, username: 'eve', domain: 'example.com', locked: false, protocol: :activitypub, inbox_url: 'https://example.com/inbox') }
 
   before do
-    stub_request(:post, "https://example.com/inbox").to_return(status: 200)
+    stub_request(:post, 'https://example.com/inbox').to_return(status: 200)
   end
 
   context 'import old-style list of muted users' do
@@ -18,6 +20,7 @@ RSpec.describe ImportService, type: :service do
 
     describe 'when no accounts are muted' do
       let(:import) { Import.create(account: account, type: 'muting', data: csv) }
+
       it 'mutes the listed accounts, including notifications' do
         subject.call(import)
         expect(account.muting.count).to eq 2
@@ -55,6 +58,7 @@ RSpec.describe ImportService, type: :service do
 
     describe 'when no accounts are muted' do
       let(:import) { Import.create(account: account, type: 'muting', data: csv) }
+
       it 'mutes the listed accounts, respecting notifications' do
         subject.call(import)
         expect(account.muting.count).to eq 2
@@ -95,6 +99,7 @@ RSpec.describe ImportService, type: :service do
 
     describe 'when no accounts are followed' do
       let(:import) { Import.create(account: account, type: 'following', data: csv) }
+
       it 'follows the listed accounts, including boosts' do
         subject.call(import)
 
@@ -136,6 +141,7 @@ RSpec.describe ImportService, type: :service do
 
     describe 'when no accounts are followed' do
       let(:import) { Import.create(account: account, type: 'following', data: csv) }
+
       it 'follows the listed accounts, respecting boosts' do
         subject.call(import)
         expect(account.following.count).to eq 1
@@ -178,18 +184,17 @@ RSpec.describe ImportService, type: :service do
   context 'utf-8 encoded domains' do
     subject { ImportService.new }
 
-    let!(:nare)     { Fabricate(:account, username: 'nare', domain: 'թութ.հայ', locked: false, protocol: :activitypub, inbox_url: 'https://թութ.հայ/inbox') }
+    let!(:nare) { Fabricate(:account, username: 'nare', domain: 'թութ.հայ', locked: false, protocol: :activitypub, inbox_url: 'https://թութ.հայ/inbox') }
+    let(:csv) { attachment_fixture('utf8-followers.txt') }
+    let(:import) { Import.create(account: account, type: 'following', data: csv) }
 
     # Make sure to not actually go to the remote server
     before do
-      stub_request(:post, "https://թութ.հայ/inbox").to_return(status: 200)
+      stub_request(:post, 'https://թութ.հայ/inbox').to_return(status: 200)
     end
 
-    let(:csv) { attachment_fixture('utf8-followers.txt') }
-    let(:import) { Import.create(account: account, type: 'following', data: csv) }
-
     it 'follows the listed account' do
-    expect(account.follow_requests.count).to eq 0
+      expect(account.follow_requests.count).to eq 0
       subject.call(import)
       expect(account.follow_requests.count).to eq 1
     end
@@ -199,6 +204,9 @@ RSpec.describe ImportService, type: :service do
     subject { ImportService.new }
 
     let(:csv) { attachment_fixture('bookmark-imports.txt') }
+    let(:local_account)  { Fabricate(:account, username: 'foo', domain: '') }
+    let!(:remote_status) { Fabricate(:status, uri: 'https://example.com/statuses/1312') }
+    let!(:direct_status) { Fabricate(:status, uri: 'https://example.com/statuses/direct', visibility: :direct) }
 
     around(:each) do |example|
       local_before = Rails.configuration.x.local_domain
@@ -210,10 +218,6 @@ RSpec.describe ImportService, type: :service do
       Rails.configuration.x.local_domain = local_before
     end
 
-    let(:local_account)  { Fabricate(:account, username: 'foo', domain: '') }
-    let!(:remote_status) { Fabricate(:status, uri: 'https://example.com/statuses/1312') }
-    let!(:direct_status) { Fabricate(:status, uri: 'https://example.com/statuses/direct', visibility: :direct) }
-
     before do
       service = double
       allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service)
@@ -224,12 +228,13 @@ RSpec.describe ImportService, type: :service do
 
     describe 'when no bookmarks are set' do
       let(:import) { Import.create(account: account, type: 'bookmarks', data: csv) }
+
       it 'adds the toots the user has access to to bookmarks' do
         local_status = Fabricate(:status, account: local_account, uri: 'https://local.com/users/foo/statuses/42', id: 42, local: true)
         subject.call(import)
         expect(account.bookmarks.map(&:status).map(&:id)).to include(local_status.id)
         expect(account.bookmarks.map(&:status).map(&:id)).to include(remote_status.id)
-        expect(account.bookmarks.map(&:status).map(&:id)).not_to include(direct_status.id)
+        expect(account.bookmarks.map(&:status).map(&:id)).to_not include(direct_status.id)
         expect(account.bookmarks.count).to eq 3
       end
     end
diff --git a/spec/services/mute_service_spec.rb b/spec/services/mute_service_spec.rb
index 57d8c41de..50f74ff27 100644
--- a/spec/services/mute_service_spec.rb
+++ b/spec/services/mute_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe MuteService, type: :service do
diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb
index 67dd0483b..616a7aa20 100644
--- a/spec/services/notify_service_spec.rb
+++ b/spec/services/notify_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe NotifyService, type: :service do
@@ -46,13 +48,14 @@ RSpec.describe NotifyService, type: :service do
     recipient.suspend!
     expect { subject }.to_not change(Notification, :count)
   end
-  
+
   context 'for direct messages' do
     let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct)) }
     let(:type)     { :mention }
 
     before do
-      user.settings.interactions = user.settings.interactions.merge('must_be_following_dm' => enabled)
+      user.settings.update('interactions.must_be_following_dm': enabled)
+      user.save
     end
 
     context 'if recipient is supposed to be following sender' do
@@ -153,8 +156,8 @@ RSpec.describe NotifyService, type: :service do
     before do
       ActionMailer::Base.deliveries.clear
 
-      notification_emails = user.settings.notification_emails
-      user.settings.notification_emails = notification_emails.merge('follow' => enabled)
+      user.settings.update('notification_emails.follow': enabled)
+      user.save
     end
 
     context 'when email notification is enabled' do
diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb
index d21270c79..33153c3d0 100644
--- a/spec/services/post_status_service_spec.rb
+++ b/spec/services/post_status_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe PostStatusService, type: :service do
@@ -5,7 +7,7 @@ RSpec.describe PostStatusService, type: :service do
 
   it 'creates a new status' do
     account = Fabricate(:account)
-    text = "test status update"
+    text = 'test status update'
 
     status = subject.call(account, text: text)
 
@@ -16,7 +18,7 @@ RSpec.describe PostStatusService, type: :service do
   it 'creates a new response status' do
     in_reply_to_status = Fabricate(:status)
     account = Fabricate(:account)
-    text = "test status update"
+    text = 'test status update'
 
     status = subject.call(account, text: text, thread: in_reply_to_status)
 
@@ -50,7 +52,7 @@ RSpec.describe PostStatusService, type: :service do
     end
 
     it 'does not change statuses count' do
-      expect { subject.call(account, text: 'Hi future!', scheduled_at: future, thread: previous_status) }.not_to change { [account.statuses_count, previous_status.replies_count] }
+      expect { subject.call(account, text: 'Hi future!', scheduled_at: future, thread: previous_status) }.to_not change { [account.statuses_count, previous_status.replies_count] }
     end
   end
 
@@ -58,7 +60,7 @@ RSpec.describe PostStatusService, type: :service do
     boosted_status = Fabricate(:status)
     in_reply_to_status = Fabricate(:status, reblog: boosted_status)
     account = Fabricate(:account)
-    text = "test status update"
+    text = 'test status update'
 
     status = subject.call(account, text: text, thread: in_reply_to_status)
 
@@ -75,7 +77,7 @@ RSpec.describe PostStatusService, type: :service do
   end
 
   it 'creates a status with spoiler text' do
-    spoiler_text = "spoiler text"
+    spoiler_text = 'spoiler text'
 
     status = create_status_with_options(spoiler_text: spoiler_text)
 
@@ -101,14 +103,14 @@ RSpec.describe PostStatusService, type: :service do
     status = create_status_with_options(visibility: :private)
 
     expect(status).to be_persisted
-    expect(status.visibility).to eq "private"
+    expect(status.visibility).to eq 'private'
   end
 
   it 'creates a status with limited visibility for silenced users' do
     status = subject.call(Fabricate(:account, silenced: true), text: 'test', visibility: :public)
 
     expect(status).to be_persisted
-    expect(status.visibility).to eq "unlisted"
+    expect(status.visibility).to eq 'unlisted'
   end
 
   it 'creates a status for the given application' do
@@ -135,10 +137,29 @@ RSpec.describe PostStatusService, type: :service do
     allow(ProcessMentionsService).to receive(:new).and_return(mention_service)
     account = Fabricate(:account)
 
-    status = subject.call(account, text: "test status update")
+    status = subject.call(account, text: 'test status update')
 
     expect(ProcessMentionsService).to have_received(:new)
-    expect(mention_service).to have_received(:call).with(status)
+    expect(mention_service).to have_received(:call).with(status, save_records: false)
+  end
+
+  it 'safeguards mentions' do
+    account = Fabricate(:account)
+    mentioned_account = Fabricate(:account, username: 'alice')
+    unexpected_mentioned_account = Fabricate(:account, username: 'bob')
+
+    expect do
+      subject.call(account, text: '@alice hm, @bob is really annoying lately', allowed_mentions: [mentioned_account.id])
+    end.to raise_error(an_instance_of(PostStatusService::UnexpectedMentionsError).and(having_attributes(accounts: [unexpected_mentioned_account])))
+  end
+
+  it 'processes duplicate mentions correctly' do
+    account = Fabricate(:account)
+    mentioned_account = Fabricate(:account, username: 'alice')
+
+    expect do
+      subject.call(account, text: '@alice @alice @alice hey @alice')
+    end.to_not raise_error
   end
 
   it 'processes hashtags' do
@@ -147,7 +168,7 @@ RSpec.describe PostStatusService, type: :service do
     allow(ProcessHashtagsService).to receive(:new).and_return(hashtags_service)
     account = Fabricate(:account)
 
-    status = subject.call(account, text: "test status update")
+    status = subject.call(account, text: 'test status update')
 
     expect(ProcessHashtagsService).to have_received(:new)
     expect(hashtags_service).to have_received(:call).with(status)
@@ -159,7 +180,7 @@ RSpec.describe PostStatusService, type: :service do
 
     account = Fabricate(:account)
 
-    status = subject.call(account, text: "test status update")
+    status = subject.call(account, text: 'test status update')
 
     expect(DistributionWorker).to have_received(:perform_async).with(status.id)
     expect(ActivityPub::DistributionWorker).to have_received(:perform_async).with(status.id)
@@ -169,7 +190,7 @@ RSpec.describe PostStatusService, type: :service do
     allow(LinkCrawlWorker).to receive(:perform_async)
     account = Fabricate(:account)
 
-    status = subject.call(account, text: "test status update")
+    status = subject.call(account, text: 'test status update')
 
     expect(LinkCrawlWorker).to have_received(:perform_async).with(status.id)
   end
@@ -180,8 +201,8 @@ RSpec.describe PostStatusService, type: :service do
 
     status = subject.call(
       account,
-      text: "test status update",
-      media_ids: [media.id],
+      text: 'test status update',
+      media_ids: [media.id]
     )
 
     expect(media.reload.status).to eq status
@@ -193,11 +214,11 @@ RSpec.describe PostStatusService, type: :service do
 
     status = subject.call(
       account,
-      text: "test status update",
-      media_ids: [media.id],
+      text: 'test status update',
+      media_ids: [media.id]
     )
 
-    expect(media.reload.status).to eq nil
+    expect(media.reload.status).to be_nil
   end
 
   it 'does not allow attaching more than 4 files' do
@@ -206,18 +227,18 @@ RSpec.describe PostStatusService, type: :service do
     expect do
       subject.call(
         account,
-        text: "test status update",
+        text: 'test status update',
         media_ids: [
           Fabricate(:media_attachment, account: account),
           Fabricate(:media_attachment, account: account),
           Fabricate(:media_attachment, account: account),
           Fabricate(:media_attachment, account: account),
           Fabricate(:media_attachment, account: account),
-        ].map(&:id),
+        ].map(&:id)
       )
     end.to raise_error(
       Mastodon::ValidationError,
-      I18n.t('media_attachments.validations.too_many'),
+      I18n.t('media_attachments.validations.too_many')
     )
   end
 
@@ -231,15 +252,15 @@ RSpec.describe PostStatusService, type: :service do
     expect do
       subject.call(
         account,
-        text: "test status update",
+        text: 'test status update',
         media_ids: [
           video,
           image,
-        ].map(&:id),
+        ].map(&:id)
       )
     end.to raise_error(
       Mastodon::ValidationError,
-      I18n.t('media_attachments.validations.images_and_video'),
+      I18n.t('media_attachments.validations.images_and_video')
     )
   end
 
diff --git a/spec/services/precompute_feed_service_spec.rb b/spec/services/precompute_feed_service_spec.rb
index 86b93b5d2..86ab59b29 100644
--- a/spec/services/precompute_feed_service_spec.rb
+++ b/spec/services/precompute_feed_service_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe PrecomputeFeedService, type: :service do
 
   describe 'call' do
     let(:account) { Fabricate(:account) }
+
     it 'fills a user timeline with statuses' do
       account = Fabricate(:account)
       status = Fabricate(:status, account: account)
@@ -30,7 +31,7 @@ RSpec.describe PrecomputeFeedService, type: :service do
 
       subject.call(account)
 
-      expect(redis.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to eq nil
+      expect(redis.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to be_nil
     end
   end
 end
diff --git a/spec/services/process_mentions_service_spec.rb b/spec/services/process_mentions_service_spec.rb
index 5b9d17a4c..adc45c60a 100644
--- a/spec/services/process_mentions_service_spec.rb
+++ b/spec/services/process_mentions_service_spec.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ProcessMentionsService, type: :service do
-  let(:account) { Fabricate(:account, username: 'alice') }
-
   subject { ProcessMentionsService.new }
 
+  let(:account) { Fabricate(:account, username: 'alice') }
+
   context 'when mentions contain blocked accounts' do
     let(:non_blocked_account)          { Fabricate(:account) }
     let(:individually_blocked_account) { Fabricate(:account) }
@@ -47,9 +49,22 @@ RSpec.describe ProcessMentionsService, type: :service do
         end
       end
 
+      context 'mentioning a user several times when not saving records' do
+        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) }
+
+        before do
+          subject.call(status, save_records: false)
+        end
+
+        it 'creates exactly one mention' do
+          expect(status.mentions.size).to eq 1
+        end
+      end
+
       context 'with an IDN domain' do
         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)
@@ -62,7 +77,7 @@ RSpec.describe ProcessMentionsService, type: :service do
 
       context 'with an IDN TLD' do
         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)
@@ -78,8 +93,8 @@ RSpec.describe ProcessMentionsService, type: :service do
       let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox', last_webfingered_at: nil) }
 
       before do
-        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/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)
         subject.call(status)
       end
 
diff --git a/spec/services/purge_domain_service_spec.rb b/spec/services/purge_domain_service_spec.rb
index 59285f126..310affa5e 100644
--- a/spec/services/purge_domain_service_spec.rb
+++ b/spec/services/purge_domain_service_spec.rb
@@ -1,13 +1,15 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe PurgeDomainService, type: :service do
+  subject { PurgeDomainService.new }
+
   let!(:old_account) { Fabricate(:account, domain: 'obsolete.org') }
   let!(:old_status1) { Fabricate(:status, account: old_account) }
   let!(:old_status2) { Fabricate(:status, account: old_account) }
   let!(:old_attachment) { Fabricate(:media_attachment, account: old_account, status: old_status2, file: attachment_fixture('attachment.jpg')) }
 
-  subject { PurgeDomainService.new }
-
   describe 'for a suspension' do
     before do
       subject.call('obsolete.org')
diff --git a/spec/services/reblog_service_spec.rb b/spec/services/reblog_service_spec.rb
index c0ae5eedc..c00472229 100644
--- a/spec/services/reblog_service_spec.rb
+++ b/spec/services/reblog_service_spec.rb
@@ -1,15 +1,17 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ReblogService, type: :service do
   let(:alice)  { Fabricate(:account, username: 'alice') }
 
   context 'creates a reblog with appropriate visibility' do
+    subject { ReblogService.new }
+
     let(:visibility)        { :public }
     let(:reblog_visibility) { :public }
     let(:status)            { Fabricate(:status, account: alice, visibility: visibility) }
 
-    subject { ReblogService.new }
-
     before do
       subject.call(alice, status, visibility: reblog_visibility)
     end
@@ -45,11 +47,11 @@ RSpec.describe ReblogService, type: :service do
   end
 
   context 'ActivityPub' do
+    subject { ReblogService.new }
+
     let(:bob)    { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
     let(:status) { Fabricate(:status, account: bob) }
 
-    subject { ReblogService.new }
-
     before do
       stub_request(:post, bob.inbox_url)
       allow(ActivityPub::DistributionWorker).to receive(:perform_async)
diff --git a/spec/services/reject_follow_service_spec.rb b/spec/services/reject_follow_service_spec.rb
index e14bfa78d..be9363d84 100644
--- a/spec/services/reject_follow_service_spec.rb
+++ b/spec/services/reject_follow_service_spec.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe RejectFollowService, type: :service do
-  let(:sender) { Fabricate(:account, username: 'alice') }
-
   subject { RejectFollowService.new }
 
+  let(:sender) { Fabricate(:account, username: 'alice') }
+
   describe 'local' do
     let(:bob) { Fabricate(:account) }
 
diff --git a/spec/services/remove_from_follwers_service_spec.rb b/spec/services/remove_from_followers_service_spec.rb
index a83f6f49a..21cea2e4f 100644
--- a/spec/services/remove_from_follwers_service_spec.rb
+++ b/spec/services/remove_from_followers_service_spec.rb
@@ -1,13 +1,15 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe RemoveFromFollowersService, type: :service do
-  let(:bob) { Fabricate(:account, username: 'bob') }
-
   subject { RemoveFromFollowersService.new }
 
+  let(:bob) { Fabricate(:account, username: 'bob') }
+
   describe 'local' do
     let(:sender) { Fabricate(:account, username: 'alice') }
- 
+
     before do
       Follow.create(account: sender, target_account: bob)
       subject.call(bob, sender)
diff --git a/spec/services/remove_status_service_spec.rb b/spec/services/remove_status_service_spec.rb
index 482068d58..a836109a0 100644
--- a/spec/services/remove_status_service_spec.rb
+++ b/spec/services/remove_status_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe RemoveStatusService, type: :service do
@@ -37,29 +39,29 @@ RSpec.describe RemoveStatusService, type: :service do
     it 'sends Delete activity to followers' do
       subject.call(@status)
       expect(a_request(:post, 'http://example.com/inbox').with(
-        body: hash_including({
-          'type' => 'Delete',
-          'object' => {
-            'type' => 'Tombstone',
-            'id' => ActivityPub::TagManager.instance.uri_for(@status),
-            'atomUri' => OStatus::TagManager.instance.uri_for(@status),
-          },
-        })
-      )).to have_been_made.once
+               body: hash_including({
+                 'type' => 'Delete',
+                 'object' => {
+                   'type' => 'Tombstone',
+                   'id' => ActivityPub::TagManager.instance.uri_for(@status),
+                   'atomUri' => OStatus::TagManager.instance.uri_for(@status),
+                 },
+               })
+             )).to have_been_made.once
     end
 
     it 'sends Delete activity to rebloggers' do
       subject.call(@status)
       expect(a_request(:post, 'http://example2.com/inbox').with(
-        body: hash_including({
-          'type' => 'Delete',
-          'object' => {
-            'type' => 'Tombstone',
-            'id' => ActivityPub::TagManager.instance.uri_for(@status),
-            'atomUri' => OStatus::TagManager.instance.uri_for(@status),
-          },
-        })
-      )).to have_been_made.once
+               body: hash_including({
+                 'type' => 'Delete',
+                 'object' => {
+                   'type' => 'Tombstone',
+                   'id' => ActivityPub::TagManager.instance.uri_for(@status),
+                   'atomUri' => OStatus::TagManager.instance.uri_for(@status),
+                 },
+               })
+             )).to have_been_made.once
     end
 
     it 'remove status from notifications' do
@@ -78,14 +80,14 @@ RSpec.describe RemoveStatusService, type: :service do
     it 'sends Undo activity to followers' do
       subject.call(@status)
       expect(a_request(:post, 'http://example.com/inbox').with(
-        body: hash_including({
-          'type' => 'Undo',
-          'object' => hash_including({
-            'type' => 'Announce',
-            'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
-          }),
-        })
-      )).to have_been_made.once
+               body: hash_including({
+                 'type' => 'Undo',
+                 'object' => hash_including({
+                   'type' => 'Announce',
+                   'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
+                 }),
+               })
+             )).to have_been_made.once
     end
   end
 
@@ -98,14 +100,14 @@ RSpec.describe RemoveStatusService, type: :service do
     it 'sends Undo activity to followers' do
       subject.call(@status)
       expect(a_request(:post, 'http://example.com/inbox').with(
-        body: hash_including({
-          'type' => 'Undo',
-          'object' => hash_including({
-            'type' => 'Announce',
-            'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
-          }),
-        })
-      )).to have_been_made.once
+               body: hash_including({
+                 'type' => 'Undo',
+                 'object' => hash_including({
+                   'type' => 'Announce',
+                   'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
+                 }),
+               })
+             )).to have_been_made.once
     end
   end
 end
diff --git a/spec/services/report_service_spec.rb b/spec/services/report_service_spec.rb
index 02bc42ac1..452400f72 100644
--- a/spec/services/report_service_spec.rb
+++ b/spec/services/report_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ReportService, type: :service do
@@ -29,13 +31,13 @@ RSpec.describe ReportService, type: :service do
   end
 
   context 'when the reported status is a DM' do
-    let(:target_account) { Fabricate(:account) }
-    let(:status) { Fabricate(:status, account: target_account, visibility: :direct) }
-
     subject do
       -> { described_class.new.call(source_account, target_account, status_ids: [status.id]) }
     end
 
+    let(:target_account) { Fabricate(:account) }
+    let(:status) { Fabricate(:status, account: target_account, visibility: :direct) }
+
     context 'when it is addressed to the reporter' do
       before do
         status.mentions.create(account: source_account)
@@ -85,16 +87,17 @@ RSpec.describe ReportService, type: :service do
   end
 
   context 'when other reports already exist for the same target' do
-    let!(:target_account) { Fabricate(:account) }
-    let!(:other_report)   { Fabricate(:report, target_account: target_account) }
-
     subject do
       -> {  described_class.new.call(source_account, target_account) }
     end
 
+    let!(:target_account) { Fabricate(:account) }
+    let!(:other_report)   { Fabricate(:report, target_account: target_account) }
+
     before do
       ActionMailer::Base.deliveries.clear
-      source_account.user.settings.notification_emails['report'] = true
+      source_account.user.settings['notification_emails.report'] = true
+      source_account.user.save
     end
 
     it 'does not send an e-mail' do
diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb
index 654606bea..3ce1f7f2b 100644
--- a/spec/services/resolve_account_service_spec.rb
+++ b/spec/services/resolve_account_service_spec.rb
@@ -1,14 +1,16 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe ResolveAccountService, type: :service do
   subject { described_class.new }
 
   before do
-    stub_request(:get, "https://example.com/.well-known/host-meta").to_return(status: 404)
-    stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
-    stub_request(:get, "https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com").to_return(request_fixture('activitypub-webfinger.txt'))
-    stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor.txt'))
-    stub_request(:get, "https://ap.example.com/users/foo.atom").to_return(request_fixture('activitypub-feed.txt'))
+    stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 404)
+    stub_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png').to_return(request_fixture('avatar.txt'))
+    stub_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com').to_return(request_fixture('activitypub-webfinger.txt'))
+    stub_request(:get, 'https://ap.example.com/users/foo').to_return(request_fixture('activitypub-actor.txt'))
+    stub_request(:get, 'https://ap.example.com/users/foo.atom').to_return(request_fixture('activitypub-feed.txt'))
     stub_request(:get, %r{https://ap.example.com/users/foo/\w+}).to_return(status: 404)
     stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:hoge@example.com').to_return(status: 410)
   end
@@ -56,8 +58,8 @@ RSpec.describe ResolveAccountService, type: :service do
 
   context 'when there is an LRDD endpoint but no resolvable account' do
     before do
-      stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
-      stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no").to_return(status: 404)
+      stub_request(:get, 'https://quitter.no/.well-known/host-meta').to_return(request_fixture('.host-meta.txt'))
+      stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no').to_return(status: 404)
     end
 
     it 'returns nil' do
@@ -67,7 +69,7 @@ RSpec.describe ResolveAccountService, type: :service do
 
   context 'when there is no LRDD endpoint nor resolvable account' do
     before do
-      stub_request(:get, "https://example.com/.well-known/webfinger?resource=acct:catsrgr8@example.com").to_return(status: 404)
+      stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:catsrgr8@example.com').to_return(status: 404)
     end
 
     it 'returns nil' do
@@ -108,7 +110,7 @@ RSpec.describe ResolveAccountService, type: :service do
     it 'returns new remote account' do
       account = subject.call('Foo@redirected.example.com')
 
-      expect(account.activitypub?).to eq true
+      expect(account.activitypub?).to be true
       expect(account.acct).to eq 'foo@ap.example.com'
       expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
     end
@@ -123,7 +125,7 @@ RSpec.describe ResolveAccountService, type: :service do
     it 'returns new remote account' do
       account = subject.call('Foo@redirected.example.com')
 
-      expect(account.activitypub?).to eq true
+      expect(account.activitypub?).to be true
       expect(account.acct).to eq 'foo@ap.example.com'
       expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
     end
@@ -146,20 +148,20 @@ RSpec.describe ResolveAccountService, type: :service do
     it 'returns new remote account' do
       account = subject.call('foo@ap.example.com')
 
-      expect(account.activitypub?).to eq true
+      expect(account.activitypub?).to be true
       expect(account.domain).to eq 'ap.example.com'
       expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
     end
 
     context 'with multiple types' do
       before do
-        stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor-individual.txt'))
+        stub_request(:get, 'https://ap.example.com/users/foo').to_return(request_fixture('activitypub-actor-individual.txt'))
       end
 
       it 'returns new remote account' do
         account = subject.call('foo@ap.example.com')
 
-        expect(account.activitypub?).to eq true
+        expect(account.activitypub?).to be true
         expect(account.domain).to eq 'ap.example.com'
         expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
         expect(account.actor_type).to eq 'Person'
@@ -174,7 +176,7 @@ RSpec.describe ResolveAccountService, type: :service do
     it 'returns new remote account' do
       account = subject.call('foo@ap.example.com')
 
-      expect(account.activitypub?).to eq true
+      expect(account.activitypub?).to be true
       expect(account.domain).to eq 'ap.example.com'
       expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
       expect(account.uri).to eq 'https://ap.example.com/users/foo'
@@ -190,12 +192,12 @@ RSpec.describe ResolveAccountService, type: :service do
 
   context 'with an already-known acct: URI changing ActivityPub id' do
     let!(:old_account) { Fabricate(:account, username: 'foo', domain: 'ap.example.com', uri: 'https://old.example.com/users/foo', last_webfingered_at: nil) }
-    let!(:status)    { Fabricate(:status, account: old_account, text: 'foo') }
+    let!(:status) { Fabricate(:status, account: old_account, text: 'foo') }
 
     it 'returns new remote account' do
       account = subject.call('foo@ap.example.com')
 
-      expect(account.activitypub?).to eq true
+      expect(account.activitypub?).to be true
       expect(account.domain).to eq 'ap.example.com'
       expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
       expect(account.uri).to eq 'https://ap.example.com/users/foo'
diff --git a/spec/services/resolve_url_service_spec.rb b/spec/services/resolve_url_service_spec.rb
index b3e3defbf..3598311ee 100644
--- a/spec/services/resolve_url_service_spec.rb
+++ b/spec/services/resolve_url_service_spec.rb
@@ -133,7 +133,7 @@ describe ResolveURLService, type: :service do
       let!(:status) { Fabricate(:status, account: poster, visibility: :public) }
       let(:url)     { 'https://link.to/foobar' }
       let(:status_url) { ActivityPub::TagManager.instance.url_for(status) }
-      let(:uri)     { ActivityPub::TagManager.instance.uri_for(status) }
+      let(:uri) { ActivityPub::TagManager.instance.uri_for(status) }
 
       before do
         stub_request(:get, url).to_return(status: 302, headers: { 'Location' => status_url })
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index 5b52662ba..1ad0efe0a 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -13,8 +13,8 @@ describe SearchService, type: :service do
         results = subject.call('', nil, 10)
 
         expect(results).to eq(empty_results)
-        expect(AccountSearchService).not_to have_received(:new)
-        expect(Tag).not_to have_received(:search_for)
+        expect(AccountSearchService).to_not have_received(:new)
+        expect(Tag).to_not have_received(:search_for)
       end
     end
 
@@ -77,20 +77,22 @@ describe SearchService, type: :service do
         it 'includes the tag in the results' do
           query = '#tag'
           tag = Tag.new
-          allow(Tag).to receive(:search_for).with('tag', 10, 0, exclude_unreviewed: nil).and_return([tag])
+          allow(Tag).to receive(:search_for).with('tag', 10, 0, { exclude_unreviewed: nil }).and_return([tag])
 
           results = subject.call(query, nil, 10)
           expect(Tag).to have_received(:search_for).with('tag', 10, 0, exclude_unreviewed: nil)
           expect(results).to eq empty_results.merge(hashtags: [tag])
         end
+
         it 'does not include tag when starts with @ character' do
           query = '@username'
           allow(Tag).to receive(:search_for)
 
           results = subject.call(query, nil, 10)
-          expect(Tag).not_to have_received(:search_for)
+          expect(Tag).to_not have_received(:search_for)
           expect(results).to eq empty_results
         end
+
         it 'does not include account when starts with # character' do
           query = '#tag'
           allow(AccountSearchService).to receive(:new)
diff --git a/spec/services/suspend_account_service_spec.rb b/spec/services/suspend_account_service_spec.rb
index 126b13986..4489bfed5 100644
--- a/spec/services/suspend_account_service_spec.rb
+++ b/spec/services/suspend_account_service_spec.rb
@@ -1,12 +1,14 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe SuspendAccountService, type: :service do
   shared_examples 'common behavior' do
+    subject { described_class.new.call(account) }
+
     let!(:local_follower) { Fabricate(:user, current_sign_in_at: 1.hour.ago).account }
     let!(:list)           { Fabricate(:list, account: local_follower) }
 
-    subject { described_class.new.call(account) }
-
     before do
       allow(FeedManager.instance).to receive(:unmerge_from_home).and_return(nil)
       allow(FeedManager.instance).to receive(:unmerge_from_list).and_return(nil)
diff --git a/spec/services/unallow_domain_service_spec.rb b/spec/services/unallow_domain_service_spec.rb
index b93945b9a..48e310a9d 100644
--- a/spec/services/unallow_domain_service_spec.rb
+++ b/spec/services/unallow_domain_service_spec.rb
@@ -1,6 +1,10 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe UnallowDomainService, type: :service do
+  subject { UnallowDomainService.new }
+
   let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
   let!(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }
   let!(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
@@ -8,8 +12,6 @@ RSpec.describe UnallowDomainService, type: :service do
   let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: 'evil.org', suspended: true, silenced: true) }
   let!(:domain_allow) { Fabricate(:domain_allow, domain: 'evil.org') }
 
-  subject { UnallowDomainService.new }
-
   context 'in limited federation mode' do
     before do
       allow(subject).to receive(:whitelist_mode?).and_return(true)
diff --git a/spec/services/unblock_service_spec.rb b/spec/services/unblock_service_spec.rb
index 10448b340..8098d7e6d 100644
--- a/spec/services/unblock_service_spec.rb
+++ b/spec/services/unblock_service_spec.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe UnblockService, type: :service do
-  let(:sender) { Fabricate(:account, username: 'alice') }
-
   subject { UnblockService.new }
 
+  let(:sender) { Fabricate(:account, username: 'alice') }
+
   describe 'local' do
     let(:bob) { Fabricate(:account) }
 
diff --git a/spec/services/unfollow_service_spec.rb b/spec/services/unfollow_service_spec.rb
index bb5bef5c9..a12f01fa5 100644
--- a/spec/services/unfollow_service_spec.rb
+++ b/spec/services/unfollow_service_spec.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe UnfollowService, type: :service do
-  let(:sender) { Fabricate(:account, username: 'alice') }
-
   subject { UnfollowService.new }
 
+  let(:sender) { Fabricate(:account, username: 'alice') }
+
   describe 'local' do
     let(:bob) { Fabricate(:account, username: 'bob') }
 
diff --git a/spec/services/unmute_service_spec.rb b/spec/services/unmute_service_spec.rb
index 8463eb283..2edb6cfc2 100644
--- a/spec/services/unmute_service_spec.rb
+++ b/spec/services/unmute_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe UnmuteService, type: :service do
diff --git a/spec/services/unsuspend_account_service_spec.rb b/spec/services/unsuspend_account_service_spec.rb
index 987eb09e2..5d7012093 100644
--- a/spec/services/unsuspend_account_service_spec.rb
+++ b/spec/services/unsuspend_account_service_spec.rb
@@ -1,12 +1,14 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe UnsuspendAccountService, type: :service do
   shared_examples 'common behavior' do
+    subject { described_class.new.call(account) }
+
     let!(:local_follower) { Fabricate(:user, current_sign_in_at: 1.hour.ago).account }
     let!(:list)           { Fabricate(:list, account: local_follower) }
 
-    subject { described_class.new.call(account) }
-
     before do
       allow(FeedManager.instance).to receive(:merge_into_home).and_return(nil)
       allow(FeedManager.instance).to receive(:merge_into_list).and_return(nil)
diff --git a/spec/services/update_account_service_spec.rb b/spec/services/update_account_service_spec.rb
index c2dc791e4..a711a8ae7 100644
--- a/spec/services/update_account_service_spec.rb
+++ b/spec/services/update_account_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe UpdateAccountService, type: :service do
diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb
index 71a73be5b..d6923722a 100644
--- a/spec/services/update_status_service_spec.rb
+++ b/spec/services/update_status_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe UpdateStatusService, type: :service do
@@ -87,16 +89,40 @@ RSpec.describe UpdateStatusService, type: :service do
     end
   end
 
+  context 'when already-attached media changes' do
+    let!(:status) { Fabricate(:status, text: 'Foo') }
+    let!(:media_attachment) { Fabricate(:media_attachment, account: status.account, description: 'Old description') }
+
+    before do
+      status.media_attachments << media_attachment
+      subject.call(status, status.account_id, text: 'Foo', media_ids: [media_attachment.id], media_attributes: [{ id: media_attachment.id, description: 'New description' }])
+    end
+
+    it 'does not detach media attachment' do
+      expect(media_attachment.reload.status_id).to eq status.id
+    end
+
+    it 'updates the media attachment description' do
+      expect(media_attachment.reload.description).to eq 'New description'
+    end
+
+    it 'saves edit history' do
+      expect(status.edits.map { |edit| edit.ordered_media_attachments.map(&:description) }).to eq [['Old description'], ['New description']]
+    end
+  end
+
   context 'when poll changes' do
     let(:account) { Fabricate(:account) }
-    let!(:status) { Fabricate(:status, text: 'Foo', account: account, poll_attributes: {options: %w(Foo Bar), account: account, multiple: false, hide_totals: false, expires_at: 7.days.from_now }) }
+    let!(:status) { Fabricate(:status, text: 'Foo', account: account, poll_attributes: { options: %w(Foo Bar), account: account, multiple: false, hide_totals: false, expires_at: 7.days.from_now }) }
     let!(:poll)   { status.poll }
     let!(:voter) { Fabricate(:account) }
 
     before do
       status.update(poll: poll)
       VoteService.new.call(voter, poll, [0])
-      subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i })
+      Sidekiq::Testing.fake! do
+        subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i })
+      end
     end
 
     it 'updates poll' do
@@ -114,6 +140,11 @@ RSpec.describe UpdateStatusService, type: :service do
     it 'saves edit history' do
       expect(status.edits.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)]
     end
+
+    it 'requeues expiration notification' do
+      poll = status.poll.reload
+      expect(PollExpirationNotifyWorker).to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes)
+    end
   end
 
   context 'when mentions in text change' do
diff --git a/spec/services/verify_link_service_spec.rb b/spec/services/verify_link_service_spec.rb
index 391560f1c..ea9ccc3fc 100644
--- a/spec/services/verify_link_service_spec.rb
+++ b/spec/services/verify_link_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rails_helper'
 
 RSpec.describe VerifyLinkService, type: :service do
@@ -150,5 +152,27 @@ RSpec.describe VerifyLinkService, type: :service do
         expect(field.verified?).to be true
       end
     end
+
+    context 'when the link contains a link with a missing protocol slash' do
+      # This was seen in the wild where a user had three pages:
+      # 1. their mastodon profile, which linked to github and the personal website
+      # 2. their personal website correctly linking back to mastodon
+      # 3. a github profile that was linking to the personal website, but with
+      #    a malformed protocol of http:/
+      #
+      # This caused link verification between the mastodon profile and the
+      # website to fail.
+      #
+      # apparently github allows the user to enter website URLs with a single
+      # slash and makes no attempts to correct that.
+      let(:html) { '<a href="http:/unrelated.example">Hello</a>' }
+
+      it 'does not crash' do
+        # We could probably put more effort into perhaps auto-correcting the
+        # link and following it anyway, but at the very least we shouldn't let
+        # exceptions bubble up
+        expect(field.verified?).to be false
+      end
+    end
   end
 end