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.rb122
-rw-r--r--spec/services/activitypub/fetch_remote_status_service_spec.rb33
-rw-r--r--spec/services/app_sign_up_service_spec.rb9
-rw-r--r--spec/services/authorize_follow_service_spec.rb7
-rw-r--r--spec/services/batched_remove_status_service_spec.rb16
-rw-r--r--spec/services/block_service_spec.rb7
-rw-r--r--spec/services/bootstrap_timeline_service_spec.rb7
-rw-r--r--spec/services/favourite_service_spec.rb7
-rw-r--r--spec/services/fetch_link_card_service_spec.rb15
-rw-r--r--spec/services/fetch_oembed_service_spec.rb18
-rw-r--r--spec/services/fetch_remote_account_service_spec.rb41
-rw-r--r--spec/services/fetch_resource_service_spec.rb (renamed from spec/services/fetch_atom_service_spec.rb)69
-rw-r--r--spec/services/follow_service_spec.rb95
-rw-r--r--spec/services/import_service_spec.rb30
-rw-r--r--spec/services/post_status_service_spec.rb2
-rw-r--r--spec/services/process_feed_service_spec.rb252
-rw-r--r--spec/services/process_interaction_service_spec.rb151
-rw-r--r--spec/services/process_mentions_service_spec.rb8
-rw-r--r--spec/services/pubsubhubbub/subscribe_service_spec.rb71
-rw-r--r--spec/services/pubsubhubbub/unsubscribe_service_spec.rb46
-rw-r--r--spec/services/reblog_service_spec.rb4
-rw-r--r--spec/services/reject_follow_service_spec.rb7
-rw-r--r--spec/services/remove_status_service_spec.rb16
-rw-r--r--spec/services/resolve_account_service_spec.rb93
-rw-r--r--spec/services/resolve_url_service_spec.rb44
-rw-r--r--spec/services/search_service_spec.rb10
-rw-r--r--spec/services/send_interaction_service_spec.rb7
-rw-r--r--spec/services/subscribe_service_spec.rb43
-rw-r--r--spec/services/suspend_account_service_spec.rb10
-rw-r--r--spec/services/unblock_domain_service_spec.rb2
-rw-r--r--spec/services/unblock_service_spec.rb7
-rw-r--r--spec/services/unfollow_service_spec.rb7
-rw-r--r--spec/services/unsubscribe_service_spec.rb37
-rw-r--r--spec/services/update_account_service_spec.rb38
-rw-r--r--spec/services/update_remote_profile_service_spec.rb84
-rw-r--r--spec/services/verify_link_service_spec.rb4
36 files changed, 249 insertions, 1170 deletions
diff --git a/spec/services/account_search_service_spec.rb b/spec/services/account_search_service_spec.rb
index 7b071b378..5b7182586 100644
--- a/spec/services/account_search_service_spec.rb
+++ b/spec/services/account_search_service_spec.rb
@@ -1,126 +1,56 @@
 require 'rails_helper'
 
 describe AccountSearchService, type: :service do
-  describe '.call' do
-    describe 'with a query to ignore' do
+  describe '#call' do
+    context 'with a query to ignore' do
       it 'returns empty array for missing query' do
         results = subject.call('', nil, limit: 10)
 
         expect(results).to eq []
       end
-      it 'returns empty array for hashtag query' do
-        results = subject.call('#tag', nil, limit: 10)
 
-        expect(results).to eq []
-      end
       it 'returns empty array for limit zero' do
         Fabricate(:account, username: 'match')
+
         results = subject.call('match', nil, limit: 0)
 
         expect(results).to eq []
       end
     end
 
-    describe 'searching for a simple term that is not an exact match' do
+    context 'searching for a simple term that is not an exact match' do
       it 'does not return a nil entry in the array for the exact match' do
-        match = Fabricate(:account, username: 'matchingusername')
-
+        account = Fabricate(:account, username: 'matchingusername')
         results = subject.call('match', nil, limit: 5)
-        expect(results).to eq [match]
-      end
-    end
 
-    describe 'searching local and remote users' do
-      describe "when only '@'" do
-        before do
-          allow(Account).to receive(:find_local)
-          allow(Account).to receive(:search_for)
-          subject.call('@', nil, limit: 10)
-        end
-
-        it 'uses find_local with empty query to look for local accounts' do
-          expect(Account).to have_received(:find_local).with('')
-        end
-      end
-
-      describe 'when no domain' do
-        before do
-          allow(Account).to receive(:find_local)
-          allow(Account).to receive(:search_for)
-          subject.call('one', nil, limit: 10)
-        end
-
-        it 'uses find_local to look for local accounts' do
-          expect(Account).to have_received(:find_local).with('one')
-        end
-
-        it 'uses search_for to find matches' do
-          expect(Account).to have_received(:search_for).with('one', 10, 0)
-        end
-      end
-
-      describe 'when there is a domain' do
-        before do
-          allow(Account).to receive(:find_remote)
-        end
-
-        it 'uses find_remote to look for remote accounts' do
-          subject.call('two@example.com', nil, limit: 10)
-          expect(Account).to have_received(:find_remote).with('two', 'example.com')
-        end
-
-        describe 'and there is no account provided' do
-          it 'uses search_for to find matches' do
-            allow(Account).to receive(:search_for)
-            subject.call('two@example.com', nil, limit: 10, resolve: false)
-
-            expect(Account).to have_received(:search_for).with('two example.com', 10, 0)
-          end
-        end
-
-        describe 'and there is an account provided' do
-          it 'uses advanced_search_for to find matches' do
-            account = Fabricate(:account)
-            allow(Account).to receive(:advanced_search_for)
-            subject.call('two@example.com', account, limit: 10, resolve: false)
-
-            expect(Account).to have_received(:advanced_search_for).with('two example.com', account, 10, nil, 0)
-          end
-        end
+        expect(results).to eq [account]
       end
     end
 
-    describe 'with an exact match' do
-      it 'returns exact match first, and does not return duplicates' do
-        partial = Fabricate(:account, username: 'exactness')
-        exact = Fabricate(:account, username: 'exact')
-
-        results = subject.call('exact', nil, limit: 10)
-        expect(results.size).to eq 2
-        expect(results).to eq [exact, partial]
-      end
-    end
-
-    describe 'when there is a local domain' do
+    context 'when there is a local domain' do
       around do |example|
         before = Rails.configuration.x.local_domain
+
         example.run
+
         Rails.configuration.x.local_domain = before
       end
 
       it 'returns exact match first' do
         remote     = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e')
         remote_too = Fabricate(:account, username: 'b', domain: 'remote', display_name: 'e')
-        exact = Fabricate(:account, username: 'e')
+        exact      = Fabricate(:account, username: 'e')
+
         Rails.configuration.x.local_domain = 'example.com'
 
         results = subject.call('e@example.com', nil, limit: 2)
+
         expect(results.size).to eq 2
         expect(results).to eq([exact, remote]).or eq([exact, remote_too])
       end
     end
 
-    describe 'when there is a domain but no exact match' do
+    context 'when there is a domain but no exact match' do
       it 'follows the remote account when resolve is true' do
         service = double(call: nil)
         allow(ResolveAccountService).to receive(:new).and_return(service)
@@ -138,23 +68,21 @@ describe AccountSearchService, type: :service do
       end
     end
 
-    describe 'should not include suspended accounts' do
-      it 'returns the fuzzy match first, and does not return suspended exacts' do
-        partial = Fabricate(:account, username: 'exactness')
-        exact = Fabricate(:account, username: 'exact', suspended: true)
+    it 'returns the fuzzy match first, and does not return suspended exacts' do
+      partial = Fabricate(:account, username: 'exactness')
+      exact   = Fabricate(:account, username: 'exact', suspended: true)
+      results = subject.call('exact', nil, limit: 10)
 
-        results = subject.call('exact', nil, limit: 10)
-        expect(results.size).to eq 1
-        expect(results).to eq [partial]
-      end
+      expect(results.size).to eq 1
+      expect(results).to eq [partial]
+    end
 
-      it "does not return suspended remote accounts" do
-        remote = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true)
+    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)
 
-        results = subject.call('a@example.com', nil, limit: 2)
-        expect(results.size).to eq 0
-        expect(results).to eq []
-      end
+      expect(results.size).to eq 0
+      expect(results).to eq []
     end
   end
 end
diff --git a/spec/services/activitypub/fetch_remote_status_service_spec.rb b/spec/services/activitypub/fetch_remote_status_service_spec.rb
index 9ae409996..78dd59e3b 100644
--- a/spec/services/activitypub/fetch_remote_status_service_spec.rb
+++ b/spec/services/activitypub/fetch_remote_status_service_spec.rb
@@ -71,6 +71,39 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
       end
     end
 
+    context 'with Audio object' do
+      let(:object) do
+        {
+          '@context': 'https://www.w3.org/ns/activitystreams',
+          id: "https://#{valid_domain}/@foo/1234",
+          type: 'Audio',
+          name: 'Nyan Cat 10 hours remix',
+          attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
+          url: [
+            {
+              type: 'Link',
+              mimeType: 'application/x-bittorrent',
+              href: "https://#{valid_domain}/12345.torrent",
+            },
+
+            {
+              type: 'Link',
+              mimeType: 'text/html',
+              href: "https://#{valid_domain}/watch?v=12345",
+            },
+          ],
+        }
+      end
+
+      it 'creates status' do
+        status = sender.statuses.first
+
+        expect(status).to_not be_nil
+        expect(status.url).to eq "https://#{valid_domain}/watch?v=12345"
+        expect(strip_tags(status.text)).to eq "Nyan Cat 10 hours remix https://#{valid_domain}/watch?v=12345"
+      end
+    end
+
     context 'with wrong id' do
       let(:note) do
         {
diff --git a/spec/services/app_sign_up_service_spec.rb b/spec/services/app_sign_up_service_spec.rb
index 7948bb53b..e7c7f3ba1 100644
--- a/spec/services/app_sign_up_service_spec.rb
+++ b/spec/services/app_sign_up_service_spec.rb
@@ -38,6 +38,15 @@ RSpec.describe AppSignUpService, type: :service do
       user = User.find_by(id: access_token.resource_owner_id)
       expect(user).to_not be_nil
       expect(user.account).to_not be_nil
+      expect(user.invite_request).to be_nil
+    end
+
+    it 'creates an account with invite request text' do
+      access_token = subject.call(app, good_params.merge(reason: 'Foo bar'))
+      expect(access_token).to_not be_nil
+      user = User.find_by(id: access_token.resource_owner_id)
+      expect(user).to_not be_nil
+      expect(user.invite_request&.text).to eq 'Foo bar'
     end
   end
 end
diff --git a/spec/services/authorize_follow_service_spec.rb b/spec/services/authorize_follow_service_spec.rb
index 562ef0041..ce56d57a6 100644
--- a/spec/services/authorize_follow_service_spec.rb
+++ b/spec/services/authorize_follow_service_spec.rb
@@ -38,13 +38,6 @@ RSpec.describe AuthorizeFollowService, type: :service do
     it 'creates follow relation' do
       expect(bob.following?(sender)).to be true
     end
-
-    it 'sends a follow request authorization salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:authorize])
-      }).to have_been_made.once
-    end
   end
 
   describe 'remote ActivityPub' do
diff --git a/spec/services/batched_remove_status_service_spec.rb b/spec/services/batched_remove_status_service_spec.rb
index e53623449..f84256f18 100644
--- a/spec/services/batched_remove_status_service_spec.rb
+++ b/spec/services/batched_remove_status_service_spec.rb
@@ -14,11 +14,8 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
   before do
     allow(Redis.current).to receive_messages(publish: nil)
 
-    stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})
-    stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})
     stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
 
-    Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)
     jeff.user.update(current_sign_in_at: Time.zone.now)
     jeff.follow!(alice)
     hank.follow!(alice)
@@ -49,19 +46,6 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
     expect(Redis.current).to have_received(:publish).with('timeline:public', any_args).at_least(:once)
   end
 
-  it 'sends PuSH update to PuSH subscribers' do
-    expect(a_request(:post, 'http://example.com/push').with { |req|
-      matches = req.body.match(OStatus::TagManager::VERBS[:delete])
-    }).to have_been_made.at_least_once
-  end
-
-  it 'sends Salmon slap to previously mentioned users' do
-    expect(a_request(:post, "http://example.com/salmon").with { |req|
-      xml = OStatus2::Salmon.new.unpack(req.body)
-      xml.match(OStatus::TagManager::VERBS[:delete])
-    }).to have_been_made.once
-  end
-
   it 'sends delete activity to followers' do
     expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.at_least_once
   end
diff --git a/spec/services/block_service_spec.rb b/spec/services/block_service_spec.rb
index 6584bb90e..de20dd026 100644
--- a/spec/services/block_service_spec.rb
+++ b/spec/services/block_service_spec.rb
@@ -28,13 +28,6 @@ RSpec.describe BlockService, type: :service do
     it 'creates a blocking relation' do
       expect(sender.blocking?(bob)).to be true
     end
-
-    it 'sends a block salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:block])
-      }).to have_been_made.once
-    end
   end
 
   describe 'remote ActivityPub' do
diff --git a/spec/services/bootstrap_timeline_service_spec.rb b/spec/services/bootstrap_timeline_service_spec.rb
index a765de791..a28d2407c 100644
--- a/spec/services/bootstrap_timeline_service_spec.rb
+++ b/spec/services/bootstrap_timeline_service_spec.rb
@@ -22,9 +22,10 @@ RSpec.describe BootstrapTimelineService, type: :service do
     context 'when setting is set' do
       let!(:alice) { Fabricate(:account, username: 'alice') }
       let!(:bob)   { Fabricate(:account, username: 'bob') }
+      let!(:eve)   { Fabricate(:account, username: 'eve', suspended: true) }
 
       before do
-        Setting.bootstrap_timeline_accounts = 'alice, bob'
+        Setting.bootstrap_timeline_accounts = 'alice, @bob, eve, unknown'
         subject.call(source_account)
       end
 
@@ -32,6 +33,10 @@ RSpec.describe BootstrapTimelineService, type: :service do
         expect(source_account.following?(alice)).to be true
         expect(source_account.following?(bob)).to be true
       end
+
+      it 'does not follow suspended account' do
+        expect(source_account.following?(eve)).to be false
+      end
     end
   end
 end
diff --git a/spec/services/favourite_service_spec.rb b/spec/services/favourite_service_spec.rb
index 0a20ccf6e..4c29ea77b 100644
--- a/spec/services/favourite_service_spec.rb
+++ b/spec/services/favourite_service_spec.rb
@@ -30,13 +30,6 @@ RSpec.describe FavouriteService, type: :service do
     it 'creates a favourite' do
       expect(status.favourites.first).to_not be_nil
     end
-
-    it 'sends a salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:favorite])
-      }).to have_been_made.once
-    end
   end
 
   describe 'remote ActivityPub' do
diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb
index 50c60aafd..8b296cc70 100644
--- a/spec/services/fetch_link_card_service_spec.rb
+++ b/spec/services/fetch_link_card_service_spec.rb
@@ -4,20 +4,13 @@ RSpec.describe FetchLinkCardService, type: :service do
   subject { FetchLinkCardService.new }
 
   before do
-    stub_request(:head, 'http://example.xn--fiqs8s/').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
     stub_request(:get, 'http://example.xn--fiqs8s/').to_return(request_fixture('idn.txt'))
-    stub_request(:head, 'http://example.com/sjis').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
     stub_request(:get, 'http://example.com/sjis').to_return(request_fixture('sjis.txt'))
-    stub_request(:head, 'http://example.com/sjis_with_wrong_charset').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
     stub_request(:get, 'http://example.com/sjis_with_wrong_charset').to_return(request_fixture('sjis_with_wrong_charset.txt'))
-    stub_request(:head, 'http://example.com/koi8-r').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
     stub_request(:get, 'http://example.com/koi8-r').to_return(request_fixture('koi8-r.txt'))
-    stub_request(:head, 'http://example.com/日本語').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
     stub_request(:get, 'http://example.com/日本語').to_return(request_fixture('sjis.txt'))
-    stub_request(:head, 'https://github.com/qbi/WannaCry').to_return(status: 404)
-    stub_request(:head, 'http://example.com/test-').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
+    stub_request(:get, 'https://github.com/qbi/WannaCry').to_return(status: 404)
     stub_request(:get, 'http://example.com/test-').to_return(request_fixture('idn.txt'))
-    stub_request(:head, 'http://example.com/windows-1251').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
     stub_request(:get, 'http://example.com/windows-1251').to_return(request_fixture('windows-1251.txt'))
 
     subject.call(status)
@@ -87,14 +80,14 @@ RSpec.describe FetchLinkCardService, type: :service do
   end
 
   context 'in a remote status' do
-    let(:status) { Fabricate(:status, account: Fabricate(:account, domain: 'example.com'), text: 'Habt ihr ein paar gute Links zu #<span class="tag"><a href="https://quitter.se/tag/wannacry" target="_blank" rel="tag noopener" title="https://quitter.se/tag/wannacry">Wannacry</a></span> herumfliegen?   Ich will mal unter <br> <a href="https://github.com/qbi/WannaCry" target="_blank" rel="noopener" title="https://github.com/qbi/WannaCry">https://github.com/qbi/WannaCry</a> was sammeln. !<a href="http://sn.jonkman.ca/group/416/id" target="_blank" rel="noopener" title="http://sn.jonkman.ca/group/416/id">security</a>&nbsp;') }
+    let(:status) { Fabricate(:status, account: Fabricate(:account, domain: 'example.com'), text: 'Habt ihr ein paar gute Links zu <a>foo</a> #<span class="tag"><a href="https://quitter.se/tag/wannacry" target="_blank" rel="tag noopener noreferrer" title="https://quitter.se/tag/wannacry">Wannacry</a></span> herumfliegen?   Ich will mal unter <br> <a href="https://github.com/qbi/WannaCry" target="_blank" rel="noopener noreferrer" title="https://github.com/qbi/WannaCry">https://github.com/qbi/WannaCry</a> was sammeln. !<a href="http://sn.jonkman.ca/group/416/id" target="_blank" rel="noopener noreferrer" title="http://sn.jonkman.ca/group/416/id">security</a>&nbsp;') }
 
     it 'parses out URLs' do
-      expect(a_request(:head, 'https://github.com/qbi/WannaCry')).to have_been_made.at_least_once
+      expect(a_request(:get, 'https://github.com/qbi/WannaCry')).to have_been_made.at_least_once
     end
 
     it 'ignores URLs to hashtags' do
-      expect(a_request(:head, 'https://quitter.se/tag/wannacry')).to_not have_been_made
+      expect(a_request(:get, 'https://quitter.se/tag/wannacry')).to_not have_been_made
     end
   end
 end
diff --git a/spec/services/fetch_oembed_service_spec.rb b/spec/services/fetch_oembed_service_spec.rb
index 5789fb53b..a4262b040 100644
--- a/spec/services/fetch_oembed_service_spec.rb
+++ b/spec/services/fetch_oembed_service_spec.rb
@@ -113,6 +113,24 @@ describe FetchOEmbedService, type: :service do
 
     end
 
+    context 'when endpoint is cached' do
+      before do
+        stub_request(:get, 'http://www.youtube.com/oembed?format=json&url=https://www.youtube.com/watch?v=dqwpQarrDwk').to_return(
+          status: 200,
+          headers: { 'Content-Type': 'text/html' },
+          body: request_fixture('oembed_json_empty.html')
+        )
+      end
+
+      it 'returns new provider without fetching original URL first' do
+        subject.call('https://www.youtube.com/watch?v=dqwpQarrDwk', cached_endpoint: { endpoint: 'http://www.youtube.com/oembed?format=json&url={url}', format: :json })
+        expect(a_request(:get, 'https://www.youtube.com/watch?v=dqwpQarrDwk')).to_not have_been_made
+        expect(subject.endpoint_url).to eq 'http://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdqwpQarrDwk'
+        expect(subject.format).to eq :json
+        expect(a_request(:get, 'http://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdqwpQarrDwk')).to have_been_made
+      end
+    end
+
     context 'when status code is not 200' do
       before do
         stub_request(:get, 'https://host.test/oembed.html').to_return(
diff --git a/spec/services/fetch_remote_account_service_spec.rb b/spec/services/fetch_remote_account_service_spec.rb
index 3cd86708b..ee7325be2 100644
--- a/spec/services/fetch_remote_account_service_spec.rb
+++ b/spec/services/fetch_remote_account_service_spec.rb
@@ -4,6 +4,7 @@ RSpec.describe FetchRemoteAccountService, type: :service do
   let(:url) { 'https://example.com/alice' }
   let(:prefetched_body) { nil }
   let(:protocol) { :ostatus }
+
   subject { FetchRemoteAccountService.new.call(url, prefetched_body, protocol) }
 
   let(:actor) do
@@ -36,36 +37,6 @@ RSpec.describe FetchRemoteAccountService, type: :service do
     include_examples 'return Account'
   end
 
-  context 'protocol is :ostatus' do
-    let(:prefetched_body) { xml }
-    let(:protocol) { :ostatus }
-
-    before do
-      stub_request(:get, "https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone").to_return(request_fixture('webfinger-hacker3.txt'))
-      stub_request(:get, "https://kickass.zone/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
-    end
-
-    include_examples 'return Account'
-
-    it 'does not update account information if XML comes from an unverified domain' do
-      feed_xml = <<-XML.squish
-        <?xml version="1.0" encoding="UTF-8"?>
-        <feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
-          <author>
-            <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-            <uri>http://kickass.zone/users/localhost</uri>
-            <name>localhost</name>
-            <poco:preferredUsername>localhost</poco:preferredUsername>
-            <poco:displayName>Villain!!!</poco:displayName>
-          </author>
-        </feed>
-      XML
-
-      returned_account = described_class.new.call('https://real-fake-domains.com/alice', feed_xml, :ostatus)
-      expect(returned_account.display_name).to_not eq 'Villain!!!'
-    end
-  end
-
   context 'when prefetched_body is nil' do
     context 'protocol is :activitypub' do
       before do
@@ -75,15 +46,5 @@ RSpec.describe FetchRemoteAccountService, type: :service do
 
       include_examples 'return Account'
     end
-
-    context 'protocol is :ostatus' do
-      before do
-        stub_request(:get, url).to_return(status: 200, body: xml, headers: { 'Content-Type' => 'application/atom+xml' })
-        stub_request(:get, "https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone").to_return(request_fixture('webfinger-hacker3.txt'))
-        stub_request(:get, "https://kickass.zone/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
-      end
-
-      include_examples 'return Account'
-    end
   end
 end
diff --git a/spec/services/fetch_atom_service_spec.rb b/spec/services/fetch_resource_service_spec.rb
index 495540004..f836147d3 100644
--- a/spec/services/fetch_atom_service_spec.rb
+++ b/spec/services/fetch_resource_service_spec.rb
@@ -1,73 +1,80 @@
 require 'rails_helper'
 
-RSpec.describe FetchAtomService, type: :service do
+RSpec.describe FetchResourceService, type: :service do
   describe '#call' do
     let(:url) { 'http://example.com' }
-    subject { FetchAtomService.new.call(url) }
 
-    context 'url is blank' do
+    subject { described_class.new.call(url) }
+
+    context 'with blank url' do
       let(:url) { '' }
       it { is_expected.to be_nil }
     end
 
-    context 'request failed' do
+    context 'when request fails' do
       before do
-        WebMock.stub_request(:get, url).to_return(status: 500, body: '', headers: {})
+        stub_request(:get, url).to_return(status: 500, body: '', headers: {})
       end
 
       it { is_expected.to be_nil }
     end
 
-    context 'raise OpenSSL::SSL::SSLError' do
+    context 'when OpenSSL::SSL::SSLError is raised' do
       before do
-        allow(Request).to receive_message_chain(:new, :add_headers, :perform).and_raise(OpenSSL::SSL::SSLError)
+        allow(Request).to receive_message_chain(:new, :add_headers, :on_behalf_of, :perform).and_raise(OpenSSL::SSL::SSLError)
       end
 
-      it 'output log and return nil' do
-        expect_any_instance_of(ActiveSupport::Logger).to receive(:debug).with('SSL error: OpenSSL::SSL::SSLError')
-        is_expected.to be_nil
-      end
+      it { is_expected.to be_nil }
     end
 
-    context 'raise HTTP::ConnectionError' do
+    context 'when HTTP::ConnectionError is raised' do
       before do
-        allow(Request).to receive_message_chain(:new, :add_headers, :perform).and_raise(HTTP::ConnectionError)
+        allow(Request).to receive_message_chain(:new, :add_headers, :on_behalf_of, :perform).and_raise(HTTP::ConnectionError)
       end
 
-      it 'output log and return nil' do
-        expect_any_instance_of(ActiveSupport::Logger).to receive(:debug).with('HTTP ConnectionError: HTTP::ConnectionError')
-        is_expected.to be_nil
-      end
+      it { is_expected.to be_nil }
     end
 
-    context 'response success' do
+    context 'when request succeeds' do
       let(:body) { '' }
-      let(:headers) { { 'Content-Type' => content_type } }
-      let(:json) {
-        { id: 1,
+
+      let(:content_type) { 'application/json' }
+
+      let(:headers) do
+        { 'Content-Type' => content_type }
+      end
+
+      let(:json) do
+        {
+          id: 1,
           '@context': ActivityPub::TagManager::CONTEXT,
           type: 'Note',
         }.to_json
-      }
+      end
 
       before do
-        WebMock.stub_request(:get, url).to_return(status: 200, body: body, headers: headers)
+        stub_request(:get, url).to_return(status: 200, body: body, headers: headers)
+      end
+
+      it 'signs request' do
+        subject
+        expect(a_request(:get, url).with(headers: { 'Signature' => /keyId="#{Regexp.escape(ActivityPub::TagManager.instance.uri_for(Account.representative) + '#main-key')}"/ })).to have_been_made
       end
 
-      context 'content type is application/atom+xml' do
+      context 'when content type is application/atom+xml' do
         let(:content_type) { 'application/atom+xml' }
 
-        it { is_expected.to eq [url, { :prefetched_body => "" }, :ostatus] }
+        it { is_expected.to eq nil }
       end
 
-      context 'content_type is activity+json' do
+      context 'when content type is activity+json' do
         let(:content_type) { 'application/activity+json; charset=utf-8' }
         let(:body) { json }
 
         it { is_expected.to eq [1, { prefetched_body: body, id: true }, :activitypub] }
       end
 
-      context 'content_type is ld+json with profile' do
+      context 'when content type is ld+json with profile' do
         let(:content_type) { 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' }
         let(:body) { json }
 
@@ -75,17 +82,17 @@ RSpec.describe FetchAtomService, type: :service do
       end
 
       before do
-        WebMock.stub_request(:get, url).to_return(status: 200, body: body, headers: headers)
-        WebMock.stub_request(:get, 'http://example.com/foo').to_return(status: 200, body: json, headers: { 'Content-Type' => 'application/activity+json' })
+        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 'has link header' do
+      context 'when link header is present' do
         let(:headers) { { 'Link' => '<http://example.com/foo>; rel="alternate"; type="application/activity+json"', } }
 
         it { is_expected.to eq [1, { prefetched_body: json, id: true }, :activitypub] }
       end
 
-      context 'content type is text/html' do
+      context 'when content type is text/html' do
         let(:content_type) { 'text/html' }
         let(:body) { '<html><head><link rel="alternate" href="http://example.com/foo" type="application/activity+json"/></head></html>' }
 
diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb
index 3c4ec59be..ae863a9f0 100644
--- a/spec/services/follow_service_spec.rb
+++ b/spec/services/follow_service_spec.rb
@@ -30,6 +30,33 @@ RSpec.describe FollowService, type: :service do
       end
     end
 
+    describe 'unlocked account, from silenced account' do
+      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+
+      before do
+        sender.touch(:silenced_at)
+        subject.call(sender, bob.acct)
+      end
+
+      it 'creates a follow request with reblogs' do
+        expect(FollowRequest.find_by(account: sender, target_account: bob, show_reblogs: true)).to_not be_nil
+      end
+    end
+
+    describe 'unlocked account, from a muted account' do
+      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+
+      before do
+        bob.mute!(sender)
+        subject.call(sender, bob.acct)
+      end
+
+      it 'creates a following relation with reblogs' do
+        expect(sender.following?(bob)).to be true
+        expect(sender.muting_reblogs?(bob)).to be false
+      end
+    end
+
     describe 'unlocked account' do
       let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
 
@@ -96,74 +123,6 @@ RSpec.describe FollowService, type: :service do
     end
   end
 
-  context 'remote OStatus account' do
-    describe 'locked account' do
-      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, locked: true, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }
-
-      before do
-        stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
-        subject.call(sender, bob.acct)
-      end
-
-      it 'creates a follow request' do
-        expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil
-      end
-
-      it 'sends a follow request salmon slap' do
-        expect(a_request(:post, "http://salmon.example.com/").with { |req|
-          xml = OStatus2::Salmon.new.unpack(req.body)
-          xml.match(OStatus::TagManager::VERBS[:request_friend])
-        }).to have_been_made.once
-      end
-    end
-
-    describe 'unlocked account' do
-      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com', hub_url: 'http://hub.example.com')).account }
-
-      before do
-        stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
-        stub_request(:post, "http://hub.example.com/").to_return(status: 202)
-        subject.call(sender, bob.acct)
-      end
-
-      it 'creates a following relation' do
-        expect(sender.following?(bob)).to be true
-      end
-
-      it 'sends a follow salmon slap' do
-        expect(a_request(:post, "http://salmon.example.com/").with { |req|
-          xml = OStatus2::Salmon.new.unpack(req.body)
-          xml.match(OStatus::TagManager::VERBS[:follow])
-        }).to have_been_made.once
-      end
-
-      it 'subscribes to PuSH' do
-        expect(a_request(:post, "http://hub.example.com/")).to have_been_made.once
-      end
-    end
-
-    describe 'already followed account' do
-      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com', hub_url: 'http://hub.example.com')).account }
-
-      before do
-        sender.follow!(bob)
-        subject.call(sender, bob.acct)
-      end
-
-      it 'keeps a following relation' do
-        expect(sender.following?(bob)).to be true
-      end
-
-      it 'does not send a follow salmon slap' do
-        expect(a_request(:post, "http://salmon.example.com/")).not_to have_been_made
-      end
-
-      it 'does not subscribe to PuSH' do
-        expect(a_request(:post, "http://hub.example.com/")).not_to have_been_made
-      end
-    end
-  end
-
   context 'remote ActivityPub account' do
     let(:bob) { Fabricate(:user, account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account }
 
diff --git a/spec/services/import_service_spec.rb b/spec/services/import_service_spec.rb
index 5cf2dadf0..5355133f4 100644
--- a/spec/services/import_service_spec.rb
+++ b/spec/services/import_service_spec.rb
@@ -3,7 +3,11 @@ require 'rails_helper'
 RSpec.describe ImportService, type: :service do
   let!(:account) { Fabricate(:account, locked: false) }
   let!(:bob)     { Fabricate(:account, username: 'bob', locked: false) }
-  let!(:eve)     { Fabricate(:account, username: 'eve', domain: 'example.com', locked: false) }
+  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)
+  end
 
   context 'import old-style list of muted users' do
     subject { ImportService.new }
@@ -95,7 +99,8 @@ RSpec.describe ImportService, type: :service do
       let(:import) { Import.create(account: account, type: 'following', data: csv) }
       it 'follows the listed accounts, including boosts' do
         subject.call(import)
-        expect(account.following.count).to eq 2
+        expect(account.following.count).to eq 1
+        expect(account.follow_requests.count).to eq 1
         expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
       end
     end
@@ -106,7 +111,8 @@ RSpec.describe ImportService, type: :service do
       it 'follows the listed accounts, including notifications' do
         account.follow!(bob, reblogs: false)
         subject.call(import)
-        expect(account.following.count).to eq 2
+        expect(account.following.count).to eq 1
+        expect(account.follow_requests.count).to eq 1
         expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
       end
     end
@@ -117,7 +123,8 @@ RSpec.describe ImportService, type: :service do
       it 'mutes the listed accounts, including notifications' do
         account.follow!(bob, reblogs: false)
         subject.call(import)
-        expect(account.following.count).to eq 2
+        expect(account.following.count).to eq 1
+        expect(account.follow_requests.count).to eq 1
         expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
       end
     end
@@ -136,9 +143,10 @@ RSpec.describe ImportService, type: :service 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 2
+        expect(account.following.count).to eq 1
+        expect(account.follow_requests.count).to eq 1
         expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
-        expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false
+        expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false
       end
     end
 
@@ -148,9 +156,10 @@ RSpec.describe ImportService, type: :service do
       it 'mutes the listed accounts, respecting notifications' do
         account.follow!(bob, reblogs: true)
         subject.call(import)
-        expect(account.following.count).to eq 2
+        expect(account.following.count).to eq 1
+        expect(account.follow_requests.count).to eq 1
         expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
-        expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false
+        expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false
       end
     end
 
@@ -160,9 +169,10 @@ RSpec.describe ImportService, type: :service do
       it 'mutes the listed accounts, respecting notifications' do
         account.follow!(bob, reblogs: true)
         subject.call(import)
-        expect(account.following.count).to eq 2
+        expect(account.following.count).to eq 1
+        expect(account.follow_requests.count).to eq 1
         expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
-        expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false
+        expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false
       end
     end
   end
diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb
index facbe977f..bf06f50e9 100644
--- a/spec/services/post_status_service_spec.rb
+++ b/spec/services/post_status_service_spec.rb
@@ -144,7 +144,6 @@ RSpec.describe PostStatusService, type: :service do
 
   it 'gets distributed' do
     allow(DistributionWorker).to receive(:perform_async)
-    allow(Pubsubhubbub::DistributionWorker).to receive(:perform_async)
     allow(ActivityPub::DistributionWorker).to receive(:perform_async)
 
     account = Fabricate(:account)
@@ -152,7 +151,6 @@ RSpec.describe PostStatusService, type: :service do
     status = subject.call(account, text: "test status update")
 
     expect(DistributionWorker).to have_received(:perform_async).with(status.id)
-    expect(Pubsubhubbub::DistributionWorker).to have_received(:perform_async).with(status.stream_entry.id)
     expect(ActivityPub::DistributionWorker).to have_received(:perform_async).with(status.id)
   end
 
diff --git a/spec/services/process_feed_service_spec.rb b/spec/services/process_feed_service_spec.rb
deleted file mode 100644
index 9d3465f3f..000000000
--- a/spec/services/process_feed_service_spec.rb
+++ /dev/null
@@ -1,252 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe ProcessFeedService, type: :service do
-  subject { ProcessFeedService.new }
-
-  describe 'processing a feed' do
-    let(:body) { File.read(Rails.root.join('spec', 'fixtures', 'xml', 'mastodon.atom')) }
-    let(:account) { Fabricate(:account, username: 'localhost', domain: 'kickass.zone') }
-
-    before do
-      stub_request(:post, "https://pubsubhubbub.superfeedr.com/").to_return(:status => 200, :body => "", :headers => {})
-      stub_request(:head, "http://kickass.zone/media/2").to_return(:status => 404)
-      stub_request(:head, "http://kickass.zone/media/3").to_return(:status => 404)
-      stub_request(:get, "http://kickass.zone/system/accounts/avatars/000/000/001/large/eris.png").to_return(request_fixture('avatar.txt'))
-      stub_request(:get, "http://kickass.zone/system/media_attachments/files/000/000/002/original/morpheus_linux.jpg?1476059910").to_return(request_fixture('attachment1.txt'))
-      stub_request(:get, "http://kickass.zone/system/media_attachments/files/000/000/003/original/gizmo.jpg?1476060065").to_return(request_fixture('attachment2.txt'))
-    end
-
-    context 'when domain does not reject media' do
-      before do
-        subject.call(body, account)
-      end
-
-      it 'updates remote user\'s account information' do
-        account.reload
-        expect(account.display_name).to eq '::1'
-        expect(account).to have_attached_file(:avatar)
-        expect(account.avatar_file_name).not_to be_nil
-      end
-
-      it 'creates posts' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Status')).to_not be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')).to_not be_nil
-      end
-
-      it 'marks replies as replies' do
-        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')
-        expect(status.reply?).to be true
-      end
-
-      it 'sets account being replied to when possible' do
-        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')
-        expect(status.in_reply_to_account_id).to eq status.account_id
-      end
-
-      it 'ignores delete statuses unless they existed before' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=3:objectType=Status')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=12:objectType=Status')).to be_nil
-      end
-
-      it 'does not create statuses for follows' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Follow')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Follow')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=4:objectType=Follow')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=7:objectType=Follow')).to be_nil
-      end
-
-      it 'does not create statuses for favourites' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Favourite')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=3:objectType=Favourite')).to be_nil
-      end
-
-      it 'creates posts with media' do
-        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=14:objectType=Status')
-
-        expect(status).to_not be_nil
-        expect(status.media_attachments.first).to have_attached_file(:file)
-        expect(status.media_attachments.first.image?).to be true
-        expect(status.media_attachments.first.file_file_name).not_to be_nil
-      end
-    end
-
-    context 'when domain is set to reject media' do
-      let!(:domain_block) { Fabricate(:domain_block, domain: 'kickass.zone', reject_media: true) }
-
-      before do
-        subject.call(body, account)
-      end
-
-      it 'updates remote user\'s account information' do
-        account.reload
-        expect(account.display_name).to eq '::1'
-      end
-
-      it 'rejects remote user\'s avatar' do
-        account.reload
-        expect(account.display_name).to eq '::1'
-        expect(account.avatar_file_name).to be_nil
-      end
-
-      it 'creates posts' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Status')).to_not be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')).to_not be_nil
-      end
-
-      it 'creates posts with remote-only media' do
-        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=14:objectType=Status')
-
-        expect(status).to_not be_nil
-        expect(status.media_attachments.first.file_file_name).to be_nil
-        expect(status.media_attachments.first.unknown?).to be true
-      end
-    end
-  end
-
-  it 'does not accept tampered reblogs' do
-    good_actor = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')
-
-    real_body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-  <author>
-    <id>https://overwatch.com/users/tracer</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://overwatch.com/users/tracer</uri>
-    <name>tracer</name>
-  </author>
-  <content type="html">Overwatch rocks</content>
-</entry>
-XML
-
-    stub_request(:get, 'https://overwatch.com/users/tracer/updates/1').to_return(status: 200, body: real_body, headers: { 'Content-Type' => 'application/atom+xml' })
-
-    bad_actor = Fabricate(:account, username: 'sombra', domain: 'talon.xyz')
-
-    body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:talon.xyz,2017-04-27:objectId=4467137:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <author>
-    <id>https://talon.xyz/users/sombra</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://talon.xyz/users/sombra</uri>
-    <name>sombra</name>
-  </author>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
-  <content type="html">Overwatch SUCKS AHAHA</content>
-  <activity:object>
-    <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-    <author>
-      <id>https://overwatch.com/users/tracer</id>
-      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-      <uri>https://overwatch.com/users/tracer</uri>
-      <name>tracer</name>
-    </author>
-    <content type="html">Overwatch SUCKS AHAHA</content>
-    <link rel="alternate" type="text/html" href="https://overwatch.com/users/tracer/updates/1" />
-  </activity:object>
-</entry>
-XML
-    created_statuses = subject.call(body, bad_actor)
-
-    expect(created_statuses.first.reblog?).to be true
-    expect(created_statuses.first.account_id).to eq bad_actor.id
-    expect(created_statuses.first.reblog.account_id).to eq good_actor.id
-    expect(created_statuses.first.reblog.text).to eq 'Overwatch rocks'
-  end
-
-  it 'ignores reblogs if it failed to retrieve reblogged statuses' do
-    stub_request(:get, 'https://overwatch.com/users/tracer/updates/1').to_return(status: 404)
-
-    actor = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')
-
-    body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <author>
-    <id>https://overwatch.com/users/tracer</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://overwatch.com/users/tracer</uri>
-    <name>tracer</name>
-  </author>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
-  <content type="html">Overwatch rocks</content>
-  <activity:object>
-    <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-    <author>
-      <id>https://overwatch.com/users/tracer</id>
-      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-      <uri>https://overwatch.com/users/tracer</uri>
-      <name>tracer</name>
-    </author>
-    <content type="html">Overwatch rocks</content>
-    <link rel="alternate" type="text/html" href="https://overwatch.com/users/tracer/updates/1" />
-  </activity:object>
-XML
-
-    created_statuses = subject.call(body, actor)
-
-    expect(created_statuses).to eq []
-  end
-
-  it 'ignores statuses with an out-of-order delete' do
-    sender = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')
-
-    delete_body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:overwatch.com,2017-04-27:objectId=4487555:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>
-  <author>
-    <id>https://overwatch.com/users/tracer</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://overwatch.com/users/tracer</uri>
-    <name>tracer</name>
-  </author>
-</entry>
-XML
-
-    status_body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:overwatch.com,2017-04-27:objectId=4487555:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-  <author>
-    <id>https://overwatch.com/users/tracer</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://overwatch.com/users/tracer</uri>
-    <name>tracer</name>
-  </author>
-  <content type="html">Overwatch rocks</content>
-</entry>
-XML
-
-    subject.call(delete_body, sender)
-    created_statuses = subject.call(status_body, sender)
-
-    expect(created_statuses).to be_empty
-  end
-end
diff --git a/spec/services/process_interaction_service_spec.rb b/spec/services/process_interaction_service_spec.rb
deleted file mode 100644
index b858c19d0..000000000
--- a/spec/services/process_interaction_service_spec.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe ProcessInteractionService, type: :service do
-  let(:receiver) { Fabricate(:user, email: 'alice@example.com', account: Fabricate(:account, username: 'alice')).account }
-  let(:sender)   { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
-  let(:remote_sender) { Fabricate(:account, username: 'carol', domain: 'localdomain.com', uri: 'https://webdomain.com/users/carol') }
-
-  subject { ProcessInteractionService.new }
-
-  describe 'status delete slap' do
-    let(:remote_status) { Fabricate(:status, account: remote_sender) }
-    let(:envelope) { OStatus2::Salmon.new.pack(payload, sender.keypair) }
-    let(:payload) {
-      <<~XML
-        <entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-          <author>
-            <email>carol@localdomain.com</email>
-            <name>carol</name>
-            <uri>https://webdomain.com/users/carol</uri>
-          </author>
-
-          <id>#{remote_status.id}</id>
-          <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>
-        </entry>
-      XML
-    }
-
-    before do
-      receiver.update(locked: true)
-      remote_sender.update(private_key: sender.private_key, public_key: remote_sender.public_key)
-    end
-
-    it 'deletes a record' do
-      expect(RemovalWorker).to receive(:perform_async).with(remote_status.id)
-      subject.call(envelope, receiver)
-    end
-  end
-
-  describe 'follow request slap' do
-    before do
-      receiver.update(locked: true)
-
-      payload = <<XML
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-  <author>
-    <name>bob</name>
-    <uri>https://cb6e6126.ngrok.io/users/bob</uri>
-  </author>
-
-  <id>someIdHere</id>
-  <activity:verb>http://activitystrea.ms/schema/1.0/request-friend</activity:verb>
-</entry>
-XML
-
-      envelope = OStatus2::Salmon.new.pack(payload, sender.keypair)
-      subject.call(envelope, receiver)
-    end
-
-    it 'creates a record' do
-      expect(FollowRequest.find_by(account: sender, target_account: receiver)).to_not be_nil
-    end
-  end
-
-  describe 'follow request slap from known remote user identified by email' do
-    before do
-      receiver.update(locked: true)
-      # Copy already-generated key
-      remote_sender.update(private_key: sender.private_key, public_key: remote_sender.public_key)
-
-      payload = <<XML
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-  <author>
-    <email>carol@localdomain.com</email>
-    <name>carol</name>
-    <uri>https://webdomain.com/users/carol</uri>
-  </author>
-
-  <id>someIdHere</id>
-  <activity:verb>http://activitystrea.ms/schema/1.0/request-friend</activity:verb>
-</entry>
-XML
-
-      envelope = OStatus2::Salmon.new.pack(payload, remote_sender.keypair)
-      subject.call(envelope, receiver)
-    end
-
-    it 'creates a record' do
-      expect(FollowRequest.find_by(account: remote_sender, target_account: receiver)).to_not be_nil
-    end
-  end
-
-  describe 'follow request authorization slap' do
-    before do
-      receiver.update(locked: true)
-      FollowRequest.create(account: sender, target_account: receiver)
-
-      payload = <<XML
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-  <author>
-    <name>alice</name>
-    <uri>https://cb6e6126.ngrok.io/users/alice</uri>
-  </author>
-
-  <id>someIdHere</id>
-  <activity:verb>http://activitystrea.ms/schema/1.0/authorize</activity:verb>
-</entry>
-XML
-
-      envelope = OStatus2::Salmon.new.pack(payload, receiver.keypair)
-      subject.call(envelope, sender)
-    end
-
-    it 'creates a follow relationship' do
-      expect(Follow.find_by(account: sender, target_account: receiver)).to_not be_nil
-    end
-
-    it 'removes the follow request' do
-      expect(FollowRequest.find_by(account: sender, target_account: receiver)).to be_nil
-    end
-  end
-
-  describe 'follow request rejection slap' do
-    before do
-      receiver.update(locked: true)
-      FollowRequest.create(account: sender, target_account: receiver)
-
-      payload = <<XML
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-  <author>
-    <name>alice</name>
-    <uri>https://cb6e6126.ngrok.io/users/alice</uri>
-  </author>
-
-  <id>someIdHere</id>
-  <activity:verb>http://activitystrea.ms/schema/1.0/reject</activity:verb>
-</entry>
-XML
-
-      envelope = OStatus2::Salmon.new.pack(payload, receiver.keypair)
-      subject.call(envelope, sender)
-    end
-
-    it 'does not create a follow relationship' do
-      expect(Follow.find_by(account: sender, target_account: receiver)).to be_nil
-    end
-
-    it 'removes the follow request' do
-      expect(FollowRequest.find_by(account: sender, target_account: receiver)).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 8a6bb44ac..b1abd79b0 100644
--- a/spec/services/process_mentions_service_spec.rb
+++ b/spec/services/process_mentions_service_spec.rb
@@ -15,12 +15,8 @@ RSpec.describe ProcessMentionsService, type: :service do
       subject.call(status)
     end
 
-    it 'creates a mention' do
-      expect(remote_user.mentions.where(status: status).count).to eq 1
-    end
-
-    it 'posts to remote user\'s Salmon end point' do
-      expect(a_request(:post, remote_user.salmon_url)).to have_been_made.once
+    it 'does not create a mention' do
+      expect(remote_user.mentions.where(status: status).count).to eq 0
     end
   end
 
diff --git a/spec/services/pubsubhubbub/subscribe_service_spec.rb b/spec/services/pubsubhubbub/subscribe_service_spec.rb
deleted file mode 100644
index 01c956230..000000000
--- a/spec/services/pubsubhubbub/subscribe_service_spec.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe Pubsubhubbub::SubscribeService, type: :service do
-  describe '#call' do
-    subject { described_class.new }
-    let(:user_account) { Fabricate(:account) }
-
-    context 'with a nil account' do
-      it 'returns the invalid topic status results' do
-        result = service_call(account: nil)
-
-        expect(result).to eq invalid_topic_status
-      end
-    end
-
-    context 'with an invalid callback url' do
-      it 'returns invalid callback status when callback is blank' do
-        result = service_call(callback: '')
-
-        expect(result).to eq invalid_callback_status
-      end
-      it 'returns invalid callback status when callback is not a URI' do
-        result = service_call(callback: 'invalid-hostname')
-
-        expect(result).to eq invalid_callback_status
-      end
-    end
-
-    context 'with a blocked domain in the callback' do
-      it 'returns callback not allowed' do
-        Fabricate(:domain_block, domain: 'test.host', severity: :suspend)
-        result = service_call(callback: 'https://test.host/api')
-
-        expect(result).to eq not_allowed_callback_status
-      end
-    end
-
-    context 'with a valid account and callback' do
-      it 'returns success status and confirms subscription' do
-        allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil)
-        subscription = Fabricate(:subscription, account: user_account)
-
-        result = service_call(callback: subscription.callback_url)
-        expect(result).to eq success_status
-        expect(Pubsubhubbub::ConfirmationWorker).to have_received(:perform_async).with(subscription.id, 'subscribe', 'asdf', 3600)
-      end
-    end
-  end
-
-  def service_call(account: user_account, callback: 'https://callback.host', secret: 'asdf', lease_seconds: 3600)
-    subject.call(account, callback, secret, lease_seconds)
-  end
-
-  def invalid_topic_status
-    ['Invalid topic URL', 422]
-  end
-
-  def invalid_callback_status
-    ['Invalid callback URL', 422]
-  end
-
-  def not_allowed_callback_status
-    ['Callback URL not allowed', 403]
-  end
-
-  def success_status
-    ['', 202]
-  end
-end
diff --git a/spec/services/pubsubhubbub/unsubscribe_service_spec.rb b/spec/services/pubsubhubbub/unsubscribe_service_spec.rb
deleted file mode 100644
index 7ed9fc5af..000000000
--- a/spec/services/pubsubhubbub/unsubscribe_service_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe Pubsubhubbub::UnsubscribeService, type: :service do
-  describe '#call' do
-    subject { described_class.new }
-
-    context 'with a nil account' do
-      it 'returns an invalid topic status' do
-        result = subject.call(nil, 'callback.host')
-
-        expect(result).to eq invalid_topic_status
-      end
-    end
-
-    context 'with a valid account' do
-      let(:account) { Fabricate(:account) }
-
-      it 'returns a valid topic status and does not run confirm when no subscription' do
-        allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil)
-        result = subject.call(account, 'callback.host')
-
-        expect(result).to eq valid_topic_status
-        expect(Pubsubhubbub::ConfirmationWorker).not_to have_received(:perform_async)
-      end
-
-      it 'returns a valid topic status and does run confirm when there is a subscription' do
-        subscription = Fabricate(:subscription, account: account, callback_url: 'callback.host')
-        allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil)
-        result = subject.call(account, 'callback.host')
-
-        expect(result).to eq valid_topic_status
-        expect(Pubsubhubbub::ConfirmationWorker).to have_received(:perform_async).with(subscription.id, 'unsubscribe')
-      end
-    end
-
-    def invalid_topic_status
-      ['Invalid topic URL', 422]
-    end
-
-    def valid_topic_status
-      ['', 202]
-    end
-  end
-end
diff --git a/spec/services/reblog_service_spec.rb b/spec/services/reblog_service_spec.rb
index 9d84c41d5..58fb46f0f 100644
--- a/spec/services/reblog_service_spec.rb
+++ b/spec/services/reblog_service_spec.rb
@@ -46,10 +46,6 @@ RSpec.describe ReblogService, type: :service do
     it 'creates a reblog' do
       expect(status.reblogs.count).to eq 1
     end
-
-    it 'sends a Salmon slap for a remote reblog' do
-      expect(a_request(:post, 'http://salmon.example.com')).to have_been_made
-    end
   end
 
   context 'ActivityPub' do
diff --git a/spec/services/reject_follow_service_spec.rb b/spec/services/reject_follow_service_spec.rb
index e5ac37ed9..1aec060db 100644
--- a/spec/services/reject_follow_service_spec.rb
+++ b/spec/services/reject_follow_service_spec.rb
@@ -38,13 +38,6 @@ RSpec.describe RejectFollowService, type: :service do
     it 'does not create follow relation' do
       expect(bob.following?(sender)).to be false
     end
-
-    it 'sends a follow request rejection salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:reject])
-      }).to have_been_made.once
-    end
   end
 
   describe 'remote ActivityPub' do
diff --git a/spec/services/remove_status_service_spec.rb b/spec/services/remove_status_service_spec.rb
index 7bba83a60..06676ec45 100644
--- a/spec/services/remove_status_service_spec.rb
+++ b/spec/services/remove_status_service_spec.rb
@@ -10,12 +10,9 @@ RSpec.describe RemoveStatusService, type: :service do
   let!(:bill)   { Fabricate(:account, username: 'bill', protocol: :activitypub, domain: 'example2.com', inbox_url: 'http://example2.com/inbox') }
 
   before do
-    stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})
-    stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})
     stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
     stub_request(:post, 'http://example2.com/inbox').to_return(status: 200)
 
-    Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)
     jeff.follow!(alice)
     hank.follow!(alice)
 
@@ -32,23 +29,10 @@ RSpec.describe RemoveStatusService, type: :service do
     expect(HomeFeed.new(jeff).get(10)).to_not include(@status.id)
   end
 
-  it 'sends PuSH update to PuSH subscribers' do
-    expect(a_request(:post, 'http://example.com/push').with { |req|
-      req.body.match(OStatus::TagManager::VERBS[:delete])
-    }).to have_been_made
-  end
-
   it 'sends delete activity to followers' do
     expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.twice
   end
 
-  it 'sends Salmon slap to previously mentioned users' do
-    expect(a_request(:post, "http://example.com/salmon").with { |req|
-      xml = OStatus2::Salmon.new.unpack(req.body)
-      xml.match(OStatus::TagManager::VERBS[:delete])
-    }).to have_been_made.once
-  end
-
   it 'sends delete activity to rebloggers' do
     expect(a_request(:post, 'http://example2.com/inbox')).to have_been_made
   end
diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb
index 27a85af7c..cea942e39 100644
--- a/spec/services/resolve_account_service_spec.rb
+++ b/spec/services/resolve_account_service_spec.rb
@@ -6,19 +6,13 @@ RSpec.describe ResolveAccountService, type: :service do
   before do
     stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
     stub_request(:get, "https://example.com/.well-known/webfinger?resource=acct:catsrgr8@example.com").to_return(status: 404)
-    stub_request(:get, "https://redirected.com/.well-known/host-meta").to_return(request_fixture('redirected.host-meta.txt'))
     stub_request(:get, "https://example.com/.well-known/host-meta").to_return(status: 404)
-    stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
-    stub_request(:get, "https://redirected.com/.well-known/webfinger?resource=acct:gargron@redirected.com").to_return(request_fixture('webfinger.txt'))
-    stub_request(:get, "https://redirected.com/.well-known/webfinger?resource=acct:hacker1@redirected.com").to_return(request_fixture('webfinger-hacker1.txt'))
-    stub_request(:get, "https://redirected.com/.well-known/webfinger?resource=acct:hacker2@redirected.com").to_return(request_fixture('webfinger-hacker2.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/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
     stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
-    stub_request(:get, "https://localdomain.com/.well-known/host-meta").to_return(request_fixture('localdomain-hostmeta.txt'))
-    stub_request(:get, "https://localdomain.com/.well-known/webfinger?resource=acct:foo@localdomain.com").to_return(status: 404)
-    stub_request(:get, "https://webdomain.com/.well-known/webfinger?resource=acct:foo@localdomain.com").to_return(request_fixture('localdomain-webfinger.txt'))
-    stub_request(:get, "https://webdomain.com/users/foo.atom").to_return(request_fixture('localdomain-feed.txt'))
+    stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no").to_return(status: 404)
+    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)
   end
 
   it 'raises error if no such user can be resolved via webfinger' do
@@ -29,74 +23,7 @@ RSpec.describe ResolveAccountService, type: :service do
     expect(subject.call('catsrgr8@example.com')).to be_nil
   end
 
-  it 'prevents hijacking existing accounts' do
-    account = subject.call('hacker1@redirected.com')
-    expect(account.salmon_url).to_not eq 'https://hacker.com/main/salmon/user/7477'
-  end
-
-  it 'prevents hijacking inexisting accounts' do
-    expect(subject.call('hacker2@redirected.com')).to be_nil
-  end
-
-  context 'with an OStatus account' do
-    it 'returns an already existing remote account' do
-      old_account      = Fabricate(:account, username: 'gargron', domain: 'quitter.no')
-      returned_account = subject.call('gargron@quitter.no')
-
-      expect(old_account.id).to eq returned_account.id
-    end
-
-    it 'returns a new remote account' do
-      account = subject.call('gargron@quitter.no')
-
-      expect(account.username).to eq 'gargron'
-      expect(account.domain).to eq 'quitter.no'
-      expect(account.remote_url).to eq 'https://quitter.no/api/statuses/user_timeline/7477.atom'
-    end
-
-    it 'follows a legitimate account redirection' do
-      account = subject.call('gargron@redirected.com')
-
-      expect(account.username).to eq 'gargron'
-      expect(account.domain).to eq 'quitter.no'
-      expect(account.remote_url).to eq 'https://quitter.no/api/statuses/user_timeline/7477.atom'
-    end
-
-    it 'returns a new remote account' do
-      account = subject.call('foo@localdomain.com')
-
-      expect(account.username).to eq 'foo'
-      expect(account.domain).to eq 'localdomain.com'
-      expect(account.remote_url).to eq 'https://webdomain.com/users/foo.atom'
-    end
-  end
-
   context 'with an ActivityPub account' do
-    before do
-      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)
-    end
-
-    it 'fallback to OStatus if actor json could not be fetched' do
-      stub_request(:get, "https://ap.example.com/users/foo").to_return(status: 404)
-
-      account = subject.call('foo@ap.example.com')
-
-      expect(account.ostatus?).to eq true
-      expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'
-    end
-
-    it 'fallback to OStatus if actor json did not have inbox_url' do
-      stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor-noinbox.txt'))
-
-      account = subject.call('foo@ap.example.com')
-
-      expect(account.ostatus?).to eq true
-      expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'
-    end
-
     it 'returns new remote account' do
       account = subject.call('foo@ap.example.com')
 
@@ -124,13 +51,19 @@ RSpec.describe ResolveAccountService, type: :service do
   it 'processes one remote account at a time using locks' do
     wait_for_start = true
     fail_occurred  = false
-    return_values  = []
+    return_values  = Concurrent::Array.new
+
+    # Preload classes that throw circular dependency errors in threads
+    Account
+    TagManager
+    DomainBlock
 
     threads = Array.new(5) do
       Thread.new do
         true while wait_for_start
+
         begin
-          return_values << described_class.new.call('foo@localdomain.com')
+          return_values << described_class.new.call('foo@ap.example.com')
         rescue ActiveRecord::RecordNotUnique
           fail_occurred = true
         end
diff --git a/spec/services/resolve_url_service_spec.rb b/spec/services/resolve_url_service_spec.rb
index 7bb5d1940..aa4204637 100644
--- a/spec/services/resolve_url_service_spec.rb
+++ b/spec/services/resolve_url_service_spec.rb
@@ -6,48 +6,14 @@ describe ResolveURLService, type: :service do
   subject { described_class.new }
 
   describe '#call' do
-    it 'returns nil when there is no atom url' do
-      url = 'http://example.com/missing-atom'
+    it 'returns nil when there is no resource url' do
+      url     = 'http://example.com/missing-resource'
       service = double
-      allow(FetchAtomService).to receive(:new).and_return service
-      allow(service).to receive(:call).with(url).and_return(nil)
-
-      result = subject.call(url)
-      expect(result).to be_nil
-    end
-
-    it 'fetches remote accounts for feed types' do
-      url = 'http://example.com/atom-feed'
-      service = double
-      allow(FetchAtomService).to receive(:new).and_return service
-      feed_url = 'http://feed-url'
-      feed_content = '<feed>contents</feed>'
-      allow(service).to receive(:call).with(url).and_return([feed_url, { prefetched_body: feed_content }])
-
-      account_service = double
-      allow(FetchRemoteAccountService).to receive(:new).and_return(account_service)
-      allow(account_service).to receive(:call)
-
-      _result = subject.call(url)
 
-      expect(account_service).to have_received(:call).with(feed_url, feed_content, nil)
-    end
-
-    it 'fetches remote statuses for entry types' do
-      url = 'http://example.com/atom-entry'
-      service = double
-      allow(FetchAtomService).to receive(:new).and_return service
-      feed_url = 'http://feed-url'
-      feed_content = '<entry>contents</entry>'
-      allow(service).to receive(:call).with(url).and_return([feed_url, { prefetched_body: feed_content }])
-
-      account_service = double
-      allow(FetchRemoteStatusService).to receive(:new).and_return(account_service)
-      allow(account_service).to receive(:call)
-
-      _result = subject.call(url)
+      allow(FetchResourceService).to receive(:new).and_return service
+      allow(service).to receive(:call).with(url).and_return(nil)
 
-      expect(account_service).to have_received(:call).with(feed_url, feed_content, nil)
+      expect(subject.call(url)).to be_nil
     end
   end
 end
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index d064cd9b8..739bb9cf5 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -27,7 +27,7 @@ describe SearchService, type: :service do
         it 'returns the empty results' do
           service = double(call: nil)
           allow(ResolveURLService).to receive(:new).and_return(service)
-          results = subject.call(@query, nil, 10)
+          results = subject.call(@query, nil, 10, resolve: true)
 
           expect(service).to have_received(:call).with(@query, on_behalf_of: nil)
           expect(results).to eq empty_results
@@ -40,7 +40,7 @@ describe SearchService, type: :service do
           service = double(call: account)
           allow(ResolveURLService).to receive(:new).and_return(service)
 
-          results = subject.call(@query, nil, 10)
+          results = subject.call(@query, nil, 10, resolve: true)
           expect(service).to have_received(:call).with(@query, on_behalf_of: nil)
           expect(results).to eq empty_results.merge(accounts: [account])
         end
@@ -52,7 +52,7 @@ describe SearchService, type: :service do
           service = double(call: status)
           allow(ResolveURLService).to receive(:new).and_return(service)
 
-          results = subject.call(@query, nil, 10)
+          results = subject.call(@query, nil, 10, resolve: true)
           expect(service).to have_received(:call).with(@query, on_behalf_of: nil)
           expect(results).to eq empty_results.merge(statuses: [status])
         end
@@ -77,10 +77,10 @@ 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).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)
+          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
diff --git a/spec/services/send_interaction_service_spec.rb b/spec/services/send_interaction_service_spec.rb
deleted file mode 100644
index 710d8184c..000000000
--- a/spec/services/send_interaction_service_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe SendInteractionService, type: :service do
-  subject { SendInteractionService.new }
-
-  it 'sends an XML envelope to the Salmon end point of remote user'
-end
diff --git a/spec/services/subscribe_service_spec.rb b/spec/services/subscribe_service_spec.rb
deleted file mode 100644
index 10bdb1ba8..000000000
--- a/spec/services/subscribe_service_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe SubscribeService, type: :service do
-  let(:account) { Fabricate(:account, username: 'bob', domain: 'example.com', hub_url: 'http://hub.example.com') }
-  subject { SubscribeService.new }
-
-  it 'sends subscription request to PuSH hub' do
-    stub_request(:post, 'http://hub.example.com/').to_return(status: 202)
-    subject.call(account)
-    expect(a_request(:post, 'http://hub.example.com/')).to have_been_made.once
-  end
-
-  it 'generates and keeps PuSH secret on successful call' do
-    stub_request(:post, 'http://hub.example.com/').to_return(status: 202)
-    subject.call(account)
-    expect(account.secret).to_not be_blank
-  end
-
-  it 'fails silently if PuSH hub forbids subscription' do
-    stub_request(:post, 'http://hub.example.com/').to_return(status: 403)
-    subject.call(account)
-  end
-
-  it 'fails silently if PuSH hub is not found' do
-    stub_request(:post, 'http://hub.example.com/').to_return(status: 404)
-    subject.call(account)
-  end
-
-  it 'fails loudly if there is a network error' do
-    stub_request(:post, 'http://hub.example.com/').to_raise(HTTP::Error)
-    expect { subject.call(account) }.to raise_error HTTP::Error
-  end
-
-  it 'fails loudly if PuSH hub is unavailable' do
-    stub_request(:post, 'http://hub.example.com/').to_return(status: 503)
-    expect { subject.call(account) }.to raise_error Mastodon::UnexpectedResponseError
-  end
-
-  it 'fails loudly if rate limited' do
-    stub_request(:post, 'http://hub.example.com/').to_return(status: 429)
-    expect { subject.call(account) }.to raise_error Mastodon::UnexpectedResponseError
-  end
-end
diff --git a/spec/services/suspend_account_service_spec.rb b/spec/services/suspend_account_service_spec.rb
index 6f45762aa..eebbbc12a 100644
--- a/spec/services/suspend_account_service_spec.rb
+++ b/spec/services/suspend_account_service_spec.rb
@@ -18,7 +18,6 @@ RSpec.describe SuspendAccountService, type: :service do
     let!(:favourite) { Fabricate(:favourite, account: account) }
     let!(:active_relationship) { Fabricate(:follow, account: account) }
     let!(:passive_relationship) { Fabricate(:follow, target_account: account) }
-    let!(:subscription) { Fabricate(:subscription, account: account) }
     let!(:remote_alice) { Fabricate(:account, inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }
     let!(:remote_bob) { Fabricate(:account, inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
 
@@ -27,14 +26,12 @@ RSpec.describe SuspendAccountService, type: :service do
         [
           account.statuses,
           account.media_attachments,
-          account.stream_entries,
           account.notifications,
           account.favourites,
           account.active_relationships,
           account.passive_relationships,
-          account.subscriptions
         ].map(&:count)
-      }.from([1, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0])
+      }.from([1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0])
     end
 
     it 'sends a delete actor activity to all known inboxes' do
@@ -63,21 +60,18 @@ RSpec.describe SuspendAccountService, type: :service do
     let!(:favourite) { Fabricate(:favourite, account: remote_bob) }
     let!(:active_relationship) { Fabricate(:follow, account: remote_bob, target_account: account) }
     let!(:passive_relationship) { Fabricate(:follow, target_account: remote_bob) }
-    let!(:subscription) { Fabricate(:subscription, account: remote_bob) }
 
     it 'deletes associated records' do
       is_expected.to change {
         [
           remote_bob.statuses,
           remote_bob.media_attachments,
-          remote_bob.stream_entries,
           remote_bob.notifications,
           remote_bob.favourites,
           remote_bob.active_relationships,
           remote_bob.passive_relationships,
-          remote_bob.subscriptions
         ].map(&:count)
-      }.from([1, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0])
+      }.from([1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0])
     end
 
     it 'sends a reject follow to follwer inboxes' do
diff --git a/spec/services/unblock_domain_service_spec.rb b/spec/services/unblock_domain_service_spec.rb
index 619aefb5c..27dbc92ad 100644
--- a/spec/services/unblock_domain_service_spec.rb
+++ b/spec/services/unblock_domain_service_spec.rb
@@ -31,7 +31,7 @@ describe UnblockDomainService, type: :service do
       subject.call(@domain_block)
       expect_deleted_domain_block
       expect(@suspended.reload.suspended?).to be false
-      expect(@silenced.reload.silenced?).to be true
+      expect(@silenced.reload.silenced?).to be false
       expect(@independently_suspended.reload.suspended?).to be true
       expect(@independently_silenced.reload.silenced?).to be true
     end
diff --git a/spec/services/unblock_service_spec.rb b/spec/services/unblock_service_spec.rb
index 5835b912b..6350c6834 100644
--- a/spec/services/unblock_service_spec.rb
+++ b/spec/services/unblock_service_spec.rb
@@ -30,13 +30,6 @@ RSpec.describe UnblockService, type: :service do
     it 'destroys the blocking relation' do
       expect(sender.blocking?(bob)).to be false
     end
-
-    it 'sends an unblock salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:unblock])
-      }).to have_been_made.once
-    end
   end
 
   describe 'remote ActivityPub' do
diff --git a/spec/services/unfollow_service_spec.rb b/spec/services/unfollow_service_spec.rb
index 8a2881ab1..84b5dafbc 100644
--- a/spec/services/unfollow_service_spec.rb
+++ b/spec/services/unfollow_service_spec.rb
@@ -30,13 +30,6 @@ RSpec.describe UnfollowService, type: :service do
     it 'destroys the following relation' do
       expect(sender.following?(bob)).to be false
     end
-
-    it 'sends an unfollow salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:unfollow])
-      }).to have_been_made.once
-    end
   end
 
   describe 'remote ActivityPub' do
diff --git a/spec/services/unsubscribe_service_spec.rb b/spec/services/unsubscribe_service_spec.rb
deleted file mode 100644
index 54d4b1b53..000000000
--- a/spec/services/unsubscribe_service_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe UnsubscribeService, type: :service do
-  let(:account) { Fabricate(:account, username: 'bob', domain: 'example.com', hub_url: 'http://hub.example.com') }
-  subject { UnsubscribeService.new }
-
-  it 'removes the secret and resets expiration on account' do
-    stub_request(:post, 'http://hub.example.com/').to_return(status: 204)
-    subject.call(account)
-    account.reload
-
-    expect(account.secret).to be_blank
-    expect(account.subscription_expires_at).to be_blank
-  end
-
-  it 'logs error on subscription failure' do
-    logger = stub_logger
-    stub_request(:post, 'http://hub.example.com/').to_return(status: 404)
-    subject.call(account)
-
-    expect(logger).to have_received(:debug).with(/unsubscribe for bob@example.com failed/)
-  end
-
-  it 'logs error on connection failure' do
-    logger = stub_logger
-    stub_request(:post, 'http://hub.example.com/').to_raise(HTTP::Error)
-    subject.call(account)
-
-    expect(logger).to have_received(:debug).with(/unsubscribe for bob@example.com failed/)
-  end
-
-  def stub_logger
-    double(debug: nil).tap do |logger|
-      allow(Rails).to receive(:logger).and_return(logger)
-    end
-  end
-end
diff --git a/spec/services/update_account_service_spec.rb b/spec/services/update_account_service_spec.rb
new file mode 100644
index 000000000..960b26891
--- /dev/null
+++ b/spec/services/update_account_service_spec.rb
@@ -0,0 +1,38 @@
+require 'rails_helper'
+
+RSpec.describe UpdateAccountService, type: :service do
+  subject { UpdateAccountService.new }
+
+  describe 'switching form locked to unlocked accounts' do
+    let(:account) { Fabricate(:account, locked: true) }
+    let(:alice)   { Fabricate(:user, email: 'alice@example.com', account: Fabricate(:account, username: 'alice')).account }
+    let(:bob)     { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+    let(:eve)     { Fabricate(:user, email: 'eve@example.com', account: Fabricate(:account, username: 'eve')).account }
+
+    before do
+      bob.touch(:silenced_at)
+      account.mute!(eve)
+
+      FollowService.new.call(alice, account)
+      FollowService.new.call(bob, account)
+      FollowService.new.call(eve, account)
+
+      subject.call(account, { locked: false })
+    end
+
+    it 'auto-accepts pending follow requests' do
+      expect(alice.following?(account)).to be true
+      expect(alice.requested?(account)).to be false
+    end
+
+    it 'does not auto-accept pending follow requests from silenced users' do
+      expect(bob.following?(account)).to be false
+      expect(bob.requested?(account)).to be true
+    end
+
+    it 'auto-accepts pending follow requests from muted users so as to not leak mute' do
+      expect(eve.following?(account)).to be true
+      expect(eve.requested?(account)).to be false
+    end
+  end
+end
diff --git a/spec/services/update_remote_profile_service_spec.rb b/spec/services/update_remote_profile_service_spec.rb
deleted file mode 100644
index f3ea70b80..000000000
--- a/spec/services/update_remote_profile_service_spec.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe UpdateRemoteProfileService, type: :service do
-  let(:xml) { File.read(Rails.root.join('spec', 'fixtures', 'push', 'feed.atom')) }
-
-  subject { UpdateRemoteProfileService.new }
-
-  before do
-    stub_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png').to_return(request_fixture('avatar.txt'))
-  end
-
-  context 'with updated details' do
-    let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com') }
-
-    before do
-      subject.call(xml, remote_account)
-    end
-
-    it 'downloads new avatar' do
-      expect(a_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png')).to have_been_made
-    end
-
-    it 'sets the avatar remote url' do
-      expect(remote_account.reload.avatar_remote_url).to eq 'https://quitter.no/avatar/7477-300-20160211190340.png'
-    end
-
-    it 'sets display name' do
-      expect(remote_account.reload.display_name).to eq 'DIGITAL CAT'
-    end
-
-    it 'sets note' do
-      expect(remote_account.reload.note).to eq 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes'
-    end
-  end
-
-  context 'with unchanged details' do
-    let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com', display_name: 'DIGITAL CAT', note: 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes', avatar_remote_url: 'https://quitter.no/avatar/7477-300-20160211190340.png') }
-
-    before do
-      subject.call(xml, remote_account)
-    end
-
-    it 'does not re-download avatar' do
-      expect(a_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png')).to have_been_made.once
-    end
-
-    it 'sets the avatar remote url' do
-      expect(remote_account.reload.avatar_remote_url).to eq 'https://quitter.no/avatar/7477-300-20160211190340.png'
-    end
-
-    it 'sets display name' do
-      expect(remote_account.reload.display_name).to eq 'DIGITAL CAT'
-    end
-
-    it 'sets note' do
-      expect(remote_account.reload.note).to eq 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes'
-    end
-  end
-
-  context 'with updated details from a domain set to reject media' do
-    let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com') }
-    let!(:domain_block) { Fabricate(:domain_block, domain: 'example.com', reject_media: true) }
-
-    before do
-      subject.call(xml, remote_account)
-    end
-
-    it 'does not the avatar remote url' do
-      expect(remote_account.reload.avatar_remote_url).to be_nil
-    end
-
-    it 'sets display name' do
-      expect(remote_account.reload.display_name).to eq 'DIGITAL CAT'
-    end
-
-    it 'sets note' do
-      expect(remote_account.reload.note).to eq 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes'
-    end
-
-    it 'does not set store the avatar' do
-      expect(remote_account.reload.avatar_file_name).to be_nil
-    end
-  end
-end
diff --git a/spec/services/verify_link_service_spec.rb b/spec/services/verify_link_service_spec.rb
index 2edcdb75f..3fc88e60e 100644
--- a/spec/services/verify_link_service_spec.rb
+++ b/spec/services/verify_link_service_spec.rb
@@ -28,12 +28,12 @@ RSpec.describe VerifyLinkService, type: :service do
       end
     end
 
-    context 'when a link contains an <a rel="noopener"> back' do
+    context 'when a link contains an <a rel="noopener noreferrer"> back' do
       let(:html) do
         <<-HTML
           <!doctype html>
           <body>
-            <a href="#{ActivityPub::TagManager.instance.url_for(account)}" rel="noopener me" target="_blank">Follow me on Mastodon</a>
+            <a href="#{ActivityPub::TagManager.instance.url_for(account)}" rel="me noopener noreferrer" target="_blank">Follow me on Mastodon</a>
           </body>
         HTML
       end