about summary refs log tree commit diff
path: root/spec/controllers
diff options
context:
space:
mode:
authorDavid Yip <yipdw@member.fsf.org>2017-09-09 14:27:47 -0500
committerDavid Yip <yipdw@member.fsf.org>2017-09-09 14:27:47 -0500
commitb9f7bc149b2a6abfbdaee83e6992b617b8bdb18e (patch)
tree355225f4424a6ea1b40c66c5540ccab42096e3bf /spec/controllers
parente18ed4bbc7ab4e258d05a3e2a5db0790f67a8f37 (diff)
parent5d170587e3b6c1a3b3ebe0910b62a4c526e2900d (diff)
Merge branch 'origin/master' into sync/upstream
 Conflicts:
	app/javascript/mastodon/components/status_list.js
	app/javascript/mastodon/features/notifications/index.js
	app/javascript/mastodon/features/ui/components/modal_root.js
	app/javascript/mastodon/features/ui/components/onboarding_modal.js
	app/javascript/mastodon/features/ui/index.js
	app/javascript/styles/about.scss
	app/javascript/styles/accounts.scss
	app/javascript/styles/components.scss
	app/presenters/instance_presenter.rb
	app/services/post_status_service.rb
	app/services/reblog_service.rb
	app/views/about/more.html.haml
	app/views/about/show.html.haml
	app/views/accounts/_header.html.haml
	config/webpack/loaders/babel.js
	spec/controllers/api/v1/accounts/credentials_controller_spec.rb
Diffstat (limited to 'spec/controllers')
-rw-r--r--spec/controllers/accounts_controller_spec.rb19
-rw-r--r--spec/controllers/activitypub/inboxes_controller_spec.rb7
-rw-r--r--spec/controllers/activitypub/outboxes_controller_spec.rb23
-rw-r--r--spec/controllers/api/oembed_controller_spec.rb1
-rw-r--r--spec/controllers/api/subscriptions_controller_spec.rb26
-rw-r--r--spec/controllers/api/v1/accounts/credentials_controller_spec.rb93
-rw-r--r--spec/controllers/api/v1/accounts/relationships_controller_spec.rb4
-rw-r--r--spec/controllers/api/v1/accounts/statuses_controller_spec.rb36
-rw-r--r--spec/controllers/api/v1/favourites_controller_spec.rb3
-rw-r--r--spec/controllers/api/v1/statuses/pins_controller_spec.rb57
-rw-r--r--spec/controllers/concerns/account_controller_concern_spec.rb2
-rw-r--r--spec/controllers/concerns/signature_verification_spec.rb78
-rw-r--r--spec/controllers/remote_follow_controller_spec.rb8
-rw-r--r--spec/controllers/settings/applications_controller_spec.rb188
-rw-r--r--spec/controllers/settings/profiles_controller_spec.rb2
-rw-r--r--spec/controllers/statuses_controller_spec.rb12
-rw-r--r--spec/controllers/stream_entries_controller_spec.rb8
17 files changed, 482 insertions, 85 deletions
diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index d61c8c9bd..4e37b1b5f 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -10,6 +10,13 @@ RSpec.describe AccountsController, type: :controller do
     let!(:status2) { Status.create!(account: alice, text: 'Boop', thread: status1) }
     let!(:status3) { Status.create!(account: alice, text: 'Picture!') }
     let!(:status4) { Status.create!(account: alice, text: 'Mentioning @alice') }
+    let!(:status5) { Status.create!(account: alice, text: 'Kitsune') }
+    let!(:status6) { Status.create!(account: alice, text: 'Neko') }
+    let!(:status7) { Status.create!(account: alice, text: 'Tanuki') }
+
+    let!(:status_pin1) { StatusPin.create!(account: alice, status: status5, created_at: 5.days.ago) }
+    let!(:status_pin2) { StatusPin.create!(account: alice, status: status6, created_at: 2.years.ago) }
+    let!(:status_pin3) { StatusPin.create!(account: alice, status: status7, created_at: 10.minutes.ago) }
 
     before do
       status3.media_attachments.create!(account: alice, file: fixture_file_upload('files/attachment.jpg', 'image/jpeg'))
@@ -48,6 +55,10 @@ RSpec.describe AccountsController, type: :controller do
       it 'returns http success with Activity Streams 2.0' do
         expect(response).to have_http_status(:success)
       end
+
+      it 'returns application/activity+json' do
+        expect(response.content_type).to eq 'application/activity+json'
+      end
     end
 
     context 'html' do
@@ -66,6 +77,14 @@ RSpec.describe AccountsController, type: :controller do
         expect(statuses[1]).to eq status2
       end
 
+      it 'assigns @pinned_statuses' do
+        pinned_statuses = assigns(:pinned_statuses).to_a
+        expect(pinned_statuses.size).to eq 3
+        expect(pinned_statuses[0]).to eq status7
+        expect(pinned_statuses[1]).to eq status5
+        expect(pinned_statuses[2]).to eq status6
+      end
+
       it 'returns http success' do
         expect(response).to have_http_status(:success)
       end
diff --git a/spec/controllers/activitypub/inboxes_controller_spec.rb b/spec/controllers/activitypub/inboxes_controller_spec.rb
new file mode 100644
index 000000000..5c12fea7d
--- /dev/null
+++ b/spec/controllers/activitypub/inboxes_controller_spec.rb
@@ -0,0 +1,7 @@
+require 'rails_helper'
+
+RSpec.describe ActivityPub::InboxesController, type: :controller do
+  describe 'POST #create' do
+    pending
+  end
+end
diff --git a/spec/controllers/activitypub/outboxes_controller_spec.rb b/spec/controllers/activitypub/outboxes_controller_spec.rb
new file mode 100644
index 000000000..a25998021
--- /dev/null
+++ b/spec/controllers/activitypub/outboxes_controller_spec.rb
@@ -0,0 +1,23 @@
+require 'rails_helper'
+
+RSpec.describe ActivityPub::OutboxesController, type: :controller do
+  let!(:account) { Fabricate(:account) }
+
+  before do
+    Fabricate(:status, account: account)
+  end
+
+  describe 'GET #show' do
+    before do
+      get :show, params: { account_username: account.username }
+    end
+
+    it 'returns http success' do
+      expect(response).to have_http_status(:success)
+    end
+
+    it 'returns application/activity+json' do
+      expect(response.content_type).to eq 'application/activity+json'
+    end
+  end
+end
diff --git a/spec/controllers/api/oembed_controller_spec.rb b/spec/controllers/api/oembed_controller_spec.rb
index 43631a7e5..7af4a6a5b 100644
--- a/spec/controllers/api/oembed_controller_spec.rb
+++ b/spec/controllers/api/oembed_controller_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe Api::OEmbedController, type: :controller do
 
   describe 'GET #show' do
     before do
+      request.host = Rails.configuration.x.local_domain
       get :show, params: { url: account_stream_entry_url(alice, status.stream_entry) }, format: :json
     end
 
diff --git a/spec/controllers/api/subscriptions_controller_spec.rb b/spec/controllers/api/subscriptions_controller_spec.rb
index 76f9740ca..d90da9e32 100644
--- a/spec/controllers/api/subscriptions_controller_spec.rb
+++ b/spec/controllers/api/subscriptions_controller_spec.rb
@@ -38,19 +38,19 @@ RSpec.describe Api::SubscriptionsController, type: :controller do
     before do
       stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {})
       stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
-      stub_request(:head, "https://quitter.no/notice/1269244").to_return(status: 404)
-      stub_request(:head, "https://quitter.no/notice/1265331").to_return(status: 404)
-      stub_request(:head, "https://community.highlandarrow.com/notice/54411").to_return(status: 404)
-      stub_request(:head, "https://community.highlandarrow.com/notice/53857").to_return(status: 404)
-      stub_request(:head, "https://community.highlandarrow.com/notice/51852").to_return(status: 404)
-      stub_request(:head, "https://social.umeahackerspace.se/notice/424348").to_return(status: 404)
-      stub_request(:head, "https://community.highlandarrow.com/notice/50467").to_return(status: 404)
-      stub_request(:head, "https://quitter.no/notice/1243309").to_return(status: 404)
-      stub_request(:head, "https://quitter.no/user/7477").to_return(status: 404)
-      stub_request(:head, "https://community.highlandarrow.com/user/1").to_return(status: 404)
-      stub_request(:head, "https://social.umeahackerspace.se/user/2").to_return(status: 404)
-      stub_request(:head, "https://gs.kawa-kun.com/user/2").to_return(status: 404)
-      stub_request(:head, "https://mastodon.social/users/Gargron").to_return(status: 404)
+      stub_request(:get, "https://quitter.no/notice/1269244").to_return(status: 404)
+      stub_request(:get, "https://quitter.no/notice/1265331").to_return(status: 404)
+      stub_request(:get, "https://community.highlandarrow.com/notice/54411").to_return(status: 404)
+      stub_request(:get, "https://community.highlandarrow.com/notice/53857").to_return(status: 404)
+      stub_request(:get, "https://community.highlandarrow.com/notice/51852").to_return(status: 404)
+      stub_request(:get, "https://social.umeahackerspace.se/notice/424348").to_return(status: 404)
+      stub_request(:get, "https://community.highlandarrow.com/notice/50467").to_return(status: 404)
+      stub_request(:get, "https://quitter.no/notice/1243309").to_return(status: 404)
+      stub_request(:get, "https://quitter.no/user/7477").to_return(status: 404)
+      stub_request(:any, "https://community.highlandarrow.com/user/1").to_return(status: 404)
+      stub_request(:any, "https://social.umeahackerspace.se/user/2").to_return(status: 404)
+      stub_request(:any, "https://gs.kawa-kun.com/user/2").to_return(status: 404)
+      stub_request(:any, "https://mastodon.social/users/Gargron").to_return(status: 404)
 
       request.env['HTTP_X_HUB_SIGNATURE'] = "sha1=#{OpenSSL::HMAC.hexdigest('sha1', 'abc', feed)}"
       request.env['RAW_POST_DATA'] = feed
diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
index 3f655c7b2..461b8b34b 100644
--- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
@@ -4,52 +4,79 @@ describe Api::V1::Accounts::CredentialsController do
   render_views
 
   let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
-  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write') }
+  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read write') }
 
-  before do
-    allow(controller).to receive(:doorkeeper_token) { token }
-  end
-
-  describe 'GET #show' do
-    it 'returns http success' do
-      get :show
-      expect(response).to have_http_status(:success)
+  context 'with an oauth token' do
+    before do
+      allow(controller).to receive(:doorkeeper_token) { token }
     end
-  end
-
-  describe 'PATCH #update' do
-    describe 'with valid data' do
-      before do
-        patch :update, params: {
-          display_name: "Alice Isn't Dead",
-          note: "Hi!\n\nToot toot!",
-          avatar: fixture_file_upload('files/avatar.gif', 'image/gif'),
-          header: fixture_file_upload('files/attachment.jpg', 'image/jpeg'),
-        }
-      end
 
+    describe 'GET #show' do
       it 'returns http success' do
+        get :show
         expect(response).to have_http_status(:success)
       end
+    end
+
+    describe 'PATCH #update' do
+      describe 'with valid data' do
+        before do
+          allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
+
+          patch :update, params: {
+            display_name: "Alice Isn't Dead",
+            note: "Hi!\n\nToot toot!",
+            avatar: fixture_file_upload('files/avatar.gif', 'image/gif'),
+            header: fixture_file_upload('files/attachment.jpg', 'image/jpeg'),
+          }
+        end
+
+        it 'returns http success' do
+          expect(response).to have_http_status(:success)
+        end
 
-      it 'updates account info' do
-        user.account.reload
+        it 'updates account info' do
+          user.account.reload
 
-        expect(user.account.display_name).to eq("Alice Isn't Dead")
-        expect(user.account.note).to eq("Hi!\n\nToot toot!")
-        expect(user.account.avatar).to exist
-        expect(user.account.header).to exist
+          expect(user.account.display_name).to eq("Alice Isn't Dead")
+          expect(user.account.note).to eq("Hi!\n\nToot toot!")
+          expect(user.account.avatar).to exist
+          expect(user.account.header).to exist
+        end
+
+        it 'queues up an account update distribution' do
+          expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(user.account_id)
+        end
+      end
+
+      describe 'with invalid data' do
+        before do
+          patch :update, params: { note: 'This is too long. ' * 10 }
+        end
+
+        it 'returns http unprocessable entity' do
+          expect(response).to have_http_status(:unprocessable_entity)
+        end
       end
     end
+  end
+
+  context 'without an oauth token' do
+    before do
+      allow(controller).to receive(:doorkeeper_token) { nil }
+    end
 
-    describe 'with invalid data' do
-      before do
-        # note length limit is 501, presently hardcoded, so give it 510 to fail
-        patch :update, params: { note: '1234567890' * 51 }
+    describe 'GET #show' do
+      it 'returns http unauthorized' do
+        get :show
+        expect(response).to have_http_status(:unauthorized)
       end
+    end
 
-      it 'returns http unprocessable entity' do
-        expect(response).to have_http_status(:unprocessable_entity)
+    describe 'PATCH #update' do
+      it 'returns http unauthorized' do
+        patch :update, params: { note: 'Foo' }
+        expect(response).to have_http_status(:unauthorized)
       end
     end
   end
diff --git a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb
index 3a9607317..a9073b197 100644
--- a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb
@@ -50,14 +50,14 @@ describe Api::V1::Accounts::RelationshipsController do
         json = body_as_json
 
         expect(json).to be_a Enumerable
-        expect(json.first[:id]).to be simon.id
+        expect(json.first[:id]).to eq simon.id
         expect(json.first[:following]).to be true
         expect(json.first[:followed_by]).to be false
         expect(json.first[:muting]).to be false
         expect(json.first[:requested]).to be false
         expect(json.first[:domain_blocking]).to be false
 
-        expect(json.second[:id]).to be lewis.id
+        expect(json.second[:id]).to eq lewis.id
         expect(json.second[:following]).to be false
         expect(json.second[:followed_by]).to be true
         expect(json.second[:muting]).to be false
diff --git a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
index 8b4fd6a5b..c49a77ac3 100644
--- a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
@@ -18,21 +18,37 @@ describe Api::V1::Accounts::StatusesController do
       expect(response).to have_http_status(:success)
       expect(response.headers['Link'].links.size).to eq(2)
     end
-  end
 
-  describe 'GET #index with only media' do
-    it 'returns http success' do
-      get :index, params: { account_id: user.account.id, only_media: true }
+    context 'with only media' do
+      it 'returns http success' do
+        get :index, params: { account_id: user.account.id, only_media: true }
 
-      expect(response).to have_http_status(:success)
+        expect(response).to have_http_status(:success)
+      end
     end
-  end
 
-  describe 'GET #index with exclude replies' do
-    it 'returns http success' do
-      get :index, params: { account_id: user.account.id, exclude_replies: true }
+    context 'with exclude replies' do
+      before do
+        Fabricate(:status, account: user.account, thread: Fabricate(:status))
+      end
 
-      expect(response).to have_http_status(:success)
+      it 'returns http success' do
+        get :index, params: { account_id: user.account.id, exclude_replies: true }
+
+        expect(response).to have_http_status(:success)
+      end
+    end
+
+    context 'with only pinned' do
+      before do
+        Fabricate(:status_pin, account: user.account, status: Fabricate(:status, account: user.account))
+      end
+
+      it 'returns http success' do
+        get :index, params: { account_id: user.account.id, pinned: true }
+
+        expect(response).to have_http_status(:success)
+      end
     end
   end
 end
diff --git a/spec/controllers/api/v1/favourites_controller_spec.rb b/spec/controllers/api/v1/favourites_controller_spec.rb
index 3de045377..46cf70f4d 100644
--- a/spec/controllers/api/v1/favourites_controller_spec.rb
+++ b/spec/controllers/api/v1/favourites_controller_spec.rb
@@ -70,8 +70,7 @@ RSpec.describe Api::V1::FavouritesController, type: :controller do
         it 'does not add pagination headers if not necessary' do
           get :index
 
-          expect(response.headers['Link'].find_link(['rel', 'next'])).to eq nil
-          expect(response.headers['Link'].find_link(['rel', 'prev'])).to eq nil
+          expect(response.headers['Link']).to eq nil
         end
       end
     end
diff --git a/spec/controllers/api/v1/statuses/pins_controller_spec.rb b/spec/controllers/api/v1/statuses/pins_controller_spec.rb
new file mode 100644
index 000000000..2e170da24
--- /dev/null
+++ b/spec/controllers/api/v1/statuses/pins_controller_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Api::V1::Statuses::PinsController do
+  render_views
+
+  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
+  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write', application: app) }
+
+  context 'with an oauth token' do
+    before do
+      allow(controller).to receive(:doorkeeper_token) { token }
+    end
+
+    describe 'POST #create' do
+      let(:status) { Fabricate(:status, account: user.account) }
+
+      before do
+        post :create, params: { status_id: status.id }
+      end
+
+      it 'returns http success' do
+        expect(response).to have_http_status(:success)
+      end
+
+      it 'updates the pinned attribute' do
+        expect(user.account.pinned?(status)).to be true
+      end
+
+      it 'return json with updated attributes' do
+        hash_body = body_as_json
+
+        expect(hash_body[:id]).to eq status.id
+        expect(hash_body[:pinned]).to be true
+      end
+    end
+
+    describe 'POST #destroy' do
+      let(:status) { Fabricate(:status, account: user.account) }
+
+      before do
+        Fabricate(:status_pin, status: status, account: user.account)
+        post :destroy, params: { status_id: status.id }
+      end
+
+      it 'returns http success' do
+        expect(response).to have_http_status(:success)
+      end
+
+      it 'updates the pinned attribute' do
+        expect(user.account.pinned?(status)).to be false
+      end
+    end
+  end
+end
diff --git a/spec/controllers/concerns/account_controller_concern_spec.rb b/spec/controllers/concerns/account_controller_concern_spec.rb
index bdc181edc..ae46f9ba6 100644
--- a/spec/controllers/concerns/account_controller_concern_spec.rb
+++ b/spec/controllers/concerns/account_controller_concern_spec.rb
@@ -33,7 +33,7 @@ describe ApplicationController, type: :controller do
     it 'sets link headers' do
       account = Fabricate(:account, username: 'username')
       get 'success', params: { account_username: 'username' }
-      expect(response.headers['Link'].to_s).to eq '<http://test.host/.well-known/webfinger?resource=acct%3Ausername%40cb6e6126.ngrok.io>; rel="lrdd"; type="application/xrd+xml", <http://test.host/users/username.atom>; rel="alternate"; type="application/atom+xml"'
+      expect(response.headers['Link'].to_s).to eq '<http://test.host/.well-known/webfinger?resource=acct%3Ausername%40cb6e6126.ngrok.io>; rel="lrdd"; type="application/xrd+xml", <http://test.host/users/username.atom>; rel="alternate"; type="application/atom+xml", <https://cb6e6126.ngrok.io/users/username>; rel="alternate"; type="application/activity+json"'
     end
 
     it 'returns http success' do
diff --git a/spec/controllers/concerns/signature_verification_spec.rb b/spec/controllers/concerns/signature_verification_spec.rb
index b371795ab..64648621e 100644
--- a/spec/controllers/concerns/signature_verification_spec.rb
+++ b/spec/controllers/concerns/signature_verification_spec.rb
@@ -16,7 +16,7 @@ describe ApplicationController, type: :controller do
   end
 
   before do
-    routes.draw { get 'success' => 'anonymous#success' }
+    routes.draw { match via: [:get, :post], 'success' => 'anonymous#success' }
   end
 
   context 'without signature header' do
@@ -40,34 +40,74 @@ describe ApplicationController, type: :controller do
   context 'with signature header' do
     let!(:author) { Fabricate(:account) }
 
-    before do
-      get :success
+    context 'without body' do
+      before do
+        get :success
 
-      fake_request = Request.new(:get, request.url)
-      fake_request.on_behalf_of(author)
+        fake_request = Request.new(:get, request.url)
+        fake_request.on_behalf_of(author)
 
-      request.headers.merge!(fake_request.headers)
-    end
+        request.headers.merge!(fake_request.headers)
+      end
 
-    describe '#signed_request?' do
-      it 'returns true' do
-        expect(controller.signed_request?).to be true
+      describe '#signed_request?' do
+        it 'returns true' do
+          expect(controller.signed_request?).to be true
+        end
+      end
+
+      describe '#signed_request_account' do
+        it 'returns an account' do
+          expect(controller.signed_request_account).to eq author
+        end
+
+        it 'returns nil when path does not match' do
+          request.path = '/alternative-path'
+          expect(controller.signed_request_account).to be_nil
+        end
+
+        it 'returns nil when method does not match' do
+          post :success
+          expect(controller.signed_request_account).to be_nil
+        end
       end
     end
 
-    describe '#signed_request_account' do
-      it 'returns an account' do
-        expect(controller.signed_request_account).to eq author
+    context 'with body' do
+      before do
+        post :success, body: 'Hello world'
+
+        fake_request = Request.new(:post, request.url, body: 'Hello world')
+        fake_request.on_behalf_of(author)
+
+        request.headers.merge!(fake_request.headers)
       end
 
-      it 'returns nil when path does not match' do
-        request.path = '/alternative-path'
-        expect(controller.signed_request_account).to be_nil
+      describe '#signed_request?' do
+        it 'returns true' do
+          expect(controller.signed_request?).to be true
+        end
       end
 
-      it 'returns nil when method does not match' do
-        post :success
-        expect(controller.signed_request_account).to be_nil
+      describe '#signed_request_account' do
+        it 'returns an account' do
+          expect(controller.signed_request_account).to eq author
+        end
+
+        it 'returns nil when path does not match' do
+          request.path = '/alternative-path'
+          expect(controller.signed_request_account).to be_nil
+        end
+
+        it 'returns nil when method does not match' do
+          get :success
+          expect(controller.signed_request_account).to be_nil
+        end
+
+        it 'returns nil when body has been tampered' do
+          request.headers['RAW_POST_DATA'] = 'doo doo doo'
+          expect(controller.signed_request_account).to be_nil
+        end
       end
     end
   end
diff --git a/spec/controllers/remote_follow_controller_spec.rb b/spec/controllers/remote_follow_controller_spec.rb
index 915c86f8e..86b1eb8d0 100644
--- a/spec/controllers/remote_follow_controller_spec.rb
+++ b/spec/controllers/remote_follow_controller_spec.rb
@@ -87,6 +87,14 @@ describe RemoteFollowController do
         expect(response).to render_template(:new)
         expect(response.body).to include(I18n.t('remote_follow.missing_resource'))
       end
+
+      it 'renders new when occur HTTP::ConnectionError' do
+        allow(Goldfinger).to receive(:finger).with('acct:user@unknown').and_raise(HTTP::ConnectionError)
+        post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@unknown' } }
+
+        expect(response).to render_template(:new)
+        expect(response.body).to include(I18n.t('remote_follow.missing_resource'))
+      end
     end
   end
 
diff --git a/spec/controllers/settings/applications_controller_spec.rb b/spec/controllers/settings/applications_controller_spec.rb
new file mode 100644
index 000000000..ca66f8d23
--- /dev/null
+++ b/spec/controllers/settings/applications_controller_spec.rb
@@ -0,0 +1,188 @@
+require 'rails_helper'
+
+describe Settings::ApplicationsController do
+  render_views
+  
+  let!(:user) { Fabricate(:user) }
+  let!(:app) { Fabricate(:application, owner: user) }
+  
+  before do
+    sign_in user, scope: :user
+  end
+
+  describe 'GET #index' do
+    let!(:other_app) { Fabricate(:application) }
+
+    it 'shows apps' do
+      get :index
+      expect(response).to have_http_status(:success)
+      expect(assigns(:applications)).to include(app)
+      expect(assigns(:applications)).to_not include(other_app)
+    end
+  end
+
+  
+  describe 'GET #show' do
+    it 'returns http success' do
+      get :show, params: { id: app.id }
+      expect(response).to have_http_status(:success)
+      expect(assigns[:application]).to eql(app)
+    end
+
+    it 'returns 404 if you dont own app' do
+      app.update!(owner: nil)
+
+      get :show, params: { id: app.id }
+      expect(response.status).to eq 404
+    end
+  end
+
+  describe 'GET #new' do
+    it 'works' do
+      get :new
+      expect(response).to have_http_status(:success)
+    end
+  end
+
+  describe 'POST #create' do
+    context 'success (passed scopes as a String)' do
+      def call_create
+        post :create, params: {
+               doorkeeper_application: {
+                 name: 'My New App',
+                 redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
+                 website: 'http://google.com',
+                 scopes: 'read write follow'
+               }
+             }
+        response
+      end
+
+      it 'creates an entry in the database' do
+        expect { call_create }.to change(Doorkeeper::Application, :count)
+      end
+
+      it 'redirects back to applications page' do
+        expect(call_create).to redirect_to(settings_applications_path)
+      end
+    end
+
+    context 'success (passed scopes as an Array)' do
+      def call_create
+        post :create, params: {
+               doorkeeper_application: {
+                 name: 'My New App',
+                 redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
+                 website: 'http://google.com',
+                 scopes: [ 'read', 'write', 'follow' ]
+               }
+             }
+        response
+      end
+
+      it 'creates an entry in the database' do
+        expect { call_create }.to change(Doorkeeper::Application, :count)
+      end
+
+      it 'redirects back to applications page' do
+        expect(call_create).to redirect_to(settings_applications_path)
+      end
+    end
+
+    context 'failure' do
+      before do
+        post :create, params: {
+               doorkeeper_application: {
+                 name: '',
+                 redirect_uri: '',
+                 website: '',
+                 scopes: []
+               }
+             }
+      end
+
+      it 'returns http success' do
+        expect(response).to have_http_status(:success)
+      end
+
+      it 'renders form again' do
+        expect(response).to render_template(:new)
+      end
+    end
+  end
+  
+  describe 'PATCH #update' do
+    context 'success' do
+      let(:opts) {
+        {
+          website: 'https://foo.bar/'
+        }
+      }
+
+      def call_update
+        patch :update, params: {
+                id: app.id,
+                doorkeeper_application: opts
+              }
+        response
+      end
+
+      it 'updates existing application' do
+        call_update
+        expect(app.reload.website).to eql(opts[:website])
+      end
+      
+      it 'redirects back to applications page' do
+        expect(call_update).to redirect_to(settings_applications_path)
+      end
+    end
+
+    context 'failure' do
+      before do
+        patch :update, params: {
+                id: app.id,
+                doorkeeper_application: {
+                  name: '',
+                  redirect_uri: '',
+                  website: '',
+                  scopes: []
+                }
+              }
+      end
+
+      it 'returns http success' do
+        expect(response).to have_http_status(:success)
+      end
+
+      it 'renders form again' do
+        expect(response).to render_template(:show)
+      end
+    end
+  end
+
+  describe 'destroy' do
+    before do
+      post :destroy, params: { id: app.id }
+    end
+
+    it 'redirects back to applications page' do
+      expect(response).to redirect_to(settings_applications_path)
+    end
+
+    it 'removes the app' do
+      expect(Doorkeeper::Application.find_by(id: app.id)).to be_nil
+    end
+  end
+
+  describe 'regenerate' do
+    let(:token) { user.token_for_app(app) }
+    before do
+      expect(token).to_not be_nil
+      post :regenerate, params: { id: app.id }
+    end
+
+    it 'should create new token' do
+      expect(user.token_for_app(app)).to_not eql(token)
+    end
+  end
+end
diff --git a/spec/controllers/settings/profiles_controller_spec.rb b/spec/controllers/settings/profiles_controller_spec.rb
index e502dbda7..ee3315be6 100644
--- a/spec/controllers/settings/profiles_controller_spec.rb
+++ b/spec/controllers/settings/profiles_controller_spec.rb
@@ -17,11 +17,13 @@ RSpec.describe Settings::ProfilesController, type: :controller do
 
   describe 'PUT #update' do
     it 'updates the user profile' do
+      allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
       account = Fabricate(:account, user: @user, display_name: 'Old name')
 
       put :update, params: { account: { display_name: 'New name' } }
       expect(account.reload.display_name).to eq 'New name'
       expect(response).to redirect_to(settings_profile_path)
+      expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)
     end
   end
 end
diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb
index 88d365624..95fb4d594 100644
--- a/spec/controllers/statuses_controller_spec.rb
+++ b/spec/controllers/statuses_controller_spec.rb
@@ -30,6 +30,18 @@ describe StatusesController do
       end
     end
 
+    context 'status is a reblog' do
+      it 'redirects to the original status' do
+        original_account = Fabricate(:account, domain: 'example.com')
+        original_status = Fabricate(:status, account: original_account, uri: 'tag:example.com,2017:foo', url: 'https://example.com/123')
+        status = Fabricate(:status, reblog: original_status)
+
+        get :show, params: { account_username: status.account.username, id: status.id }
+
+        expect(response).to redirect_to(original_status.url)
+      end
+    end
+
     context 'account is not suspended and status is permitted' do
       it 'assigns @account' do
         status = Fabricate(:status)
diff --git a/spec/controllers/stream_entries_controller_spec.rb b/spec/controllers/stream_entries_controller_spec.rb
index 2cc428e0c..f81e2be7b 100644
--- a/spec/controllers/stream_entries_controller_spec.rb
+++ b/spec/controllers/stream_entries_controller_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe StreamEntriesController, type: :controller do
 
         get route, params: { account_username: alice.username, id: status.stream_entry.id }
 
-        expect(response.headers['Link'].to_s).to eq "<http://test.host/users/alice/updates/#{status.stream_entry.id}.atom>; rel=\"alternate\"; type=\"application/atom+xml\""
+        expect(response.headers['Link'].to_s).to eq "<http://test.host/users/alice/updates/#{status.stream_entry.id}.atom>; rel=\"alternate\"; type=\"application/atom+xml\", <https://cb6e6126.ngrok.io/users/alice/statuses/#{status.id}>; rel=\"alternate\"; type=\"application/activity+json\""
       end
     end
 
@@ -88,14 +88,12 @@ RSpec.describe StreamEntriesController, type: :controller do
   describe 'GET #embed' do
     include_examples 'before_action', :embed
 
-    it 'returns embedded view of status' do
+    it 'redirects to new embed page' do
       status = Fabricate(:status)
 
       get :embed, params: { account_username: status.account.username, id: status.stream_entry.id }
 
-      expect(response).to have_http_status(:success)
-      expect(response.headers['X-Frame-Options']).to eq 'ALLOWALL'
-      expect(response).to render_template(layout: 'embedded')
+      expect(response).to redirect_to(embed_short_account_status_url(status.account, status))
     end
   end
 end