about summary refs log tree commit diff
path: root/spec/controllers
diff options
context:
space:
mode:
authorStarfall <us@starfall.systems>2022-02-13 22:15:26 -0600
committerStarfall <us@starfall.systems>2022-02-13 22:15:26 -0600
commitc0341f06be5310a00b85a5d48fa80891d47c6710 (patch)
tree907ef7f787f8bd446a6d9be1448a8bcff74e5a08 /spec/controllers
parent169688aa9f2a69ac3d36332c833e9cad43b5f7a5 (diff)
parent6f78c66fe01921a4e7e01aa6e2386a5fce7f3afd (diff)
Merge remote-tracking branch 'glitch/main'
Not at all sure where the admin UI is going to display English language
names now but OK.
Diffstat (limited to 'spec/controllers')
-rw-r--r--spec/controllers/activitypub/followers_synchronizations_controller_spec.rb2
-rw-r--r--spec/controllers/activitypub/replies_controller_spec.rb293
-rw-r--r--spec/controllers/api/v1/accounts/statuses_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/media_controller_spec.rb21
-rw-r--r--spec/controllers/api/v1/statuses_controller_spec.rb17
5 files changed, 160 insertions, 175 deletions
diff --git a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
index 3a382ff27..e233bd560 100644
--- a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
+++ b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController, type: :controll
 
       it 'returns orderedItems with followers from example.com' do
         expect(body[:orderedItems]).to be_an Array
-        expect(body[:orderedItems].sort).to eq [follower_4.uri, follower_1.uri, follower_2.uri]
+        expect(body[:orderedItems]).to match_array([follower_4.uri, follower_1.uri, follower_2.uri])
       end
 
       it 'returns private Cache-Control header' do
diff --git a/spec/controllers/activitypub/replies_controller_spec.rb b/spec/controllers/activitypub/replies_controller_spec.rb
index bf82fd020..a2c7f336f 100644
--- a/spec/controllers/activitypub/replies_controller_spec.rb
+++ b/spec/controllers/activitypub/replies_controller_spec.rb
@@ -4,8 +4,9 @@ require 'rails_helper'
 
 RSpec.describe ActivityPub::RepliesController, type: :controller do
   let(:status) { Fabricate(:status, visibility: parent_visibility) }
-  let(:remote_reply_id) { nil }
-  let(:remote_account) { nil }
+  let(:remote_account)  { Fabricate(:account, domain: 'foobar.com') }
+  let(:remote_reply_id) { 'https://foobar.com/statuses/1234' }
+  let(:remote_querier) { nil }
 
   shared_examples 'cachable response' do
     it 'does not set cookies' do
@@ -23,224 +24,188 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
     end
   end
 
-  before do
-    allow(controller).to receive(:signed_request_account).and_return(remote_account)
+  shared_examples 'common behavior' do
+    context 'when status is private' do
+      let(:parent_visibility) { :private }
 
-    Fabricate(:status, thread: status, visibility: :public)
-    Fabricate(:status, thread: status, visibility: :public)
-    Fabricate(:status, thread: status, visibility: :private)
-    Fabricate(:status, account: status.account, thread: status, visibility: :public)
-    Fabricate(:status, account: status.account, thread: status, visibility: :private)
-
-    Fabricate(:status, account: remote_account, thread: status, visibility: :public, uri: remote_reply_id) if remote_reply_id
-  end
+      it 'returns http not found' do
+        expect(response).to have_http_status(404)
+      end
+    end
 
-  describe 'GET #index' do
-    context 'with no signature' do
-      subject(:response) { get :index, params: { account_username: status.account.username, status_id: status.id } }
-      subject(:body) { body_as_json }
+    context 'when status is direct' do
+      let(:parent_visibility) { :direct }
 
-      context 'when account is permanently suspended' do
-        let(:parent_visibility) { :public }
+      it 'returns http not found' do
+        expect(response).to have_http_status(404)
+      end
+    end
+  end
 
-        before do
-          status.account.suspend!
-          status.account.deletion_request.destroy
-        end
+  shared_examples 'disallowed access' do
+    context 'when status is public' do
+      let(:parent_visibility) { :public }
 
-        it 'returns http gone' do
-          expect(response).to have_http_status(410)
-        end
+      it 'returns http not found' do
+        expect(response).to have_http_status(404)
       end
+    end
 
-      context 'when account is temporarily suspended' do
-        let(:parent_visibility) { :public }
+    it_behaves_like 'common behavior'
+  end
 
-        before do
-          status.account.suspend!
-        end
+  shared_examples 'allowed access' do
+    context 'when account is permanently suspended' do
+      let(:parent_visibility) { :public }
 
-        it 'returns http forbidden' do
-          expect(response).to have_http_status(403)
-        end
+      before do
+        status.account.suspend!
+        status.account.deletion_request.destroy
       end
 
-      context 'when status is public' do
-        let(:parent_visibility) { :public }
-
-        it 'returns http success' do
-          expect(response).to have_http_status(200)
-        end
+      it 'returns http gone' do
+        expect(response).to have_http_status(410)
+      end
+    end
 
-        it 'returns application/activity+json' do
-          expect(response.media_type).to eq 'application/activity+json'
-        end
+    context 'when account is temporarily suspended' do
+      let(:parent_visibility) { :public }
 
-        it_behaves_like 'cachable response'
+      before do
+        status.account.suspend!
+      end
 
-        it 'returns items with account\'s own replies' do
-          expect(body[:first]).to be_a Hash
-          expect(body[:first][:items]).to be_an Array
-          expect(body[:first][:items].size).to eq 1
-          expect(body[:first][:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
-        end
+      it 'returns http forbidden' do
+        expect(response).to have_http_status(403)
       end
+    end
 
-      context 'when status is private' do
-        let(:parent_visibility) { :private }
+    context 'when status is public' do
+      let(:parent_visibility) { :public }
+      let(:json) { body_as_json }
+      let(:page_json) { json[:first] }
 
-        it 'returns http not found' do
-          expect(response).to have_http_status(404)
-        end
+      it 'returns http success' do
+        expect(response).to have_http_status(200)
       end
 
-      context 'when status is direct' do
-        let(:parent_visibility) { :direct }
-
-        it 'returns http not found' do
-          expect(response).to have_http_status(404)
-        end
+      it 'returns application/activity+json' do
+        expect(response.media_type).to eq 'application/activity+json'
       end
-    end
 
-    context 'with signature' do
-      let(:remote_account) { Fabricate(:account, domain: 'example.com') }
-      let(:only_other_accounts) { nil }
+      it_behaves_like 'cachable response'
 
-      context do
-        before do
-          get :index, params: { account_username: status.account.username, status_id: status.id, only_other_accounts: only_other_accounts }
+      context 'without only_other_accounts' do
+        it "returns items with thread author's replies" do
+          expect(page_json).to be_a Hash
+          expect(page_json[:items]).to be_an Array
+          expect(page_json[:items].size).to eq 1
+          expect(page_json[:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
         end
 
-        context 'when status is public' do
-          let(:parent_visibility) { :public }
-
-          it 'returns http success' do
-            expect(response).to have_http_status(200)
+        context 'when there are few self-replies' do
+          it 'points next to replies from other people' do
+            expect(page_json).to be_a Hash
+            expect(Addressable::URI.parse(page_json[:next]).query.split('&')).to include('only_other_accounts=true', 'page=true')
           end
+        end
 
-          it 'returns application/activity+json' do
-            expect(response.media_type).to eq 'application/activity+json'
+        context 'when there are many self-replies' do
+          before do
+            10.times { Fabricate(:status, account: status.account, thread: status, visibility: :public) }
           end
 
-          it_behaves_like 'cachable response'
-
-          context 'without only_other_accounts' do
-            it 'returns items with account\'s own replies' do
-              json = body_as_json
-
-              expect(json[:first]).to be_a Hash
-              expect(json[:first][:items]).to be_an Array
-              expect(json[:first][:items].size).to eq 1
-              expect(json[:first][:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
-            end
+          it 'points next to other self-replies' do
+            expect(page_json).to be_a Hash
+            expect(Addressable::URI.parse(page_json[:next]).query.split('&')).to include('only_other_accounts=false', 'page=true')
           end
+        end
+      end
 
-          context 'with only_other_accounts' do
-            let(:only_other_accounts) { 'true' }
-
-            it 'returns items with other public or unlisted replies' do
-              json = body_as_json
-
-              expect(json[:first]).to be_a Hash
-              expect(json[:first][:items]).to be_an Array
-              expect(json[:first][:items].size).to eq 2
-              expect(json[:first][:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
-            end
-
-            context 'with remote responses' do
-              let(:remote_reply_id) { 'foo' }
+      context 'with only_other_accounts' do
+        let(:only_other_accounts) { 'true' }
 
-              it 'returned items are all inlined local toots or are ids' do
-                json = body_as_json
+        it 'returns items with other public or unlisted replies' do
+          expect(page_json).to be_a Hash
+          expect(page_json[:items]).to be_an Array
+          expect(page_json[:items].size).to eq 3
+        end
 
-                expect(json[:first]).to be_a Hash
-                expect(json[:first][:items]).to be_an Array
-                expect(json[:first][:items].size).to eq 3
-                expect(json[:first][:items].all? { |item| item.is_a?(Hash) ? ActivityPub::TagManager.instance.local_uri?(item[:id]) : item.is_a?(String) }).to be true
-                expect(json[:first][:items]).to include remote_reply_id
-              end
-            end
-          end
+        it 'only inlines items that are local and public or unlisted replies' do
+          inlined_replies = page_json[:items].select { |x| x.is_a?(Hash) }
+          public_collection = ActivityPub::TagManager::COLLECTIONS[:public]
+          expect(inlined_replies.all? { |item| item[:to].include?(public_collection) || item[:cc].include?(public_collection) }).to be true
+          expect(inlined_replies.all? { |item| ActivityPub::TagManager.instance.local_uri?(item[:id]) }).to be true
         end
 
-        context 'when status is private' do
-          let(:parent_visibility) { :private }
+        it 'uses ids for remote toots' do
+          remote_replies = page_json[:items].select { |x| !x.is_a?(Hash) }
+          expect(remote_replies.all? { |item| item.is_a?(String) && !ActivityPub::TagManager.instance.local_uri?(item) }).to be true
+        end
 
-          it 'returns http not found' do
-            expect(response).to have_http_status(404)
+        context 'when there are few replies' do
+          it 'does not have a next page' do
+            expect(page_json).to be_a Hash
+            expect(page_json[:next]).to be_nil
           end
         end
 
-        context 'when status is direct' do
-          let(:parent_visibility) { :direct }
+        context 'when there are many replies' do
+          before do
+            10.times { Fabricate(:status, thread: status, visibility: :public) }
+          end
 
-          it 'returns http not found' do
-            expect(response).to have_http_status(404)
+          it 'points next to other replies' do
+            expect(page_json).to be_a Hash
+            expect(Addressable::URI.parse(page_json[:next]).query.split('&')).to include('only_other_accounts=true', 'page=true')
           end
         end
       end
+    end
 
-      context 'when signed request account is blocked' do
-        before do
-          status.account.block!(remote_account)
-          get :index, params: { account_username: status.account.username, status_id: status.id }
-        end
-
-        context 'when status is public' do
-          let(:parent_visibility) { :public }
+    it_behaves_like 'common behavior'
+  end
 
-          it 'returns http not found' do
-            expect(response).to have_http_status(404)
-          end
-        end
+  before do
+    stub_const 'ActivityPub::RepliesController::DESCENDANTS_LIMIT', 5
+    allow(controller).to receive(:signed_request_account).and_return(remote_querier)
 
-        context 'when status is private' do
-          let(:parent_visibility) { :private }
+    Fabricate(:status, thread: status, visibility: :public)
+    Fabricate(:status, thread: status, visibility: :public)
+    Fabricate(:status, thread: status, visibility: :private)
+    Fabricate(:status, account: status.account, thread: status, visibility: :public)
+    Fabricate(:status, account: status.account, thread: status, visibility: :private)
 
-          it 'returns http not found' do
-            expect(response).to have_http_status(404)
-          end
-        end
+    Fabricate(:status, account: remote_account, thread: status, visibility: :public, uri: remote_reply_id)
+  end
 
-        context 'when status is direct' do
-          let(:parent_visibility) { :direct }
+  describe 'GET #index' do
+    subject(:response) { get :index, params: { account_username: status.account.username, status_id: status.id, only_other_accounts: only_other_accounts } }
+    let(:only_other_accounts) { nil }
 
-          it 'returns http not found' do
-            expect(response).to have_http_status(404)
-          end
-        end
-      end
+    context 'with no signature' do
+      it_behaves_like 'allowed access'
+    end
 
-      context 'when signed request account is domain blocked' do
-        before do
-          status.account.block_domain!(remote_account.domain)
-          get :index, params: { account_username: status.account.username, status_id: status.id }
-        end
+    context 'with signature' do
+      let(:remote_querier) { Fabricate(:account, domain: 'example.com') }
 
-        context 'when status is public' do
-          let(:parent_visibility) { :public }
+      it_behaves_like 'allowed access'
 
-          it 'returns http not found' do
-            expect(response).to have_http_status(404)
-          end
+      context 'when signed request account is blocked' do
+        before do
+          status.account.block!(remote_querier)
         end
 
-        context 'when status is private' do
-          let(:parent_visibility) { :private }
+        it_behaves_like 'disallowed access'
+      end
 
-          it 'returns http not found' do
-            expect(response).to have_http_status(404)
-          end
+      context 'when signed request account is domain blocked' do
+        before do
+          status.account.block_domain!(remote_querier.domain)
         end
 
-        context 'when status is direct' do
-          let(:parent_visibility) { :direct }
-
-          it 'returns http not found' do
-            expect(response).to have_http_status(404)
-          end
-        end
+        it_behaves_like 'disallowed access'
       end
     end
   end
diff --git a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
index 348de08c2..b962b3398 100644
--- a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
@@ -79,7 +79,7 @@ describe Api::V1::Accounts::StatusesController do
         it 'lists both the public and the private statuses' do
           get :index, params: { account_id: account.id, pinned: true }
           json = body_as_json
-          expect(json.map { |item| item[:id].to_i }.sort).to eq [status.id, private_status.id].sort
+          expect(json.map { |item| item[:id].to_i }).to match_array([status.id, private_status.id])
         end
       end
     end
diff --git a/spec/controllers/api/v1/media_controller_spec.rb b/spec/controllers/api/v1/media_controller_spec.rb
index d8d732630..a1f6ddb24 100644
--- a/spec/controllers/api/v1/media_controller_spec.rb
+++ b/spec/controllers/api/v1/media_controller_spec.rb
@@ -110,21 +110,24 @@ RSpec.describe Api::V1::MediaController, type: :controller do
       end
     end
 
-    context 'when not attached to a status' do
-      let(:media) { Fabricate(:media_attachment, status: nil, account: user.account) }
+    context 'when the author \'s' do
+      let(:status) { nil }
+      let(:media)  { Fabricate(:media_attachment, status: status, account: user.account) }
 
-      it 'updates the description' do
+      before do
         put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }
+      end
+
+      it 'updates the description' do
         expect(media.reload.description).to eq 'Lorem ipsum!!!'
       end
-    end
 
-    context 'when attached to a status' do
-      let(:media) { Fabricate(:media_attachment, status: Fabricate(:status), account: user.account) }
+      context 'when already attached to a status' do
+        let(:status) { Fabricate(:status, account: user.account) }
 
-      it 'returns http not found' do
-        put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }
-        expect(response).to have_http_status(:not_found)
+        it 'returns http not found' do
+          expect(response).to have_http_status(:not_found)
+        end
       end
     end
   end
diff --git a/spec/controllers/api/v1/statuses_controller_spec.rb b/spec/controllers/api/v1/statuses_controller_spec.rb
index 2679ab017..190dfad11 100644
--- a/spec/controllers/api/v1/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses_controller_spec.rb
@@ -102,6 +102,23 @@ RSpec.describe Api::V1::StatusesController, type: :controller do
         expect(Status.find_by(id: status.id)).to be nil
       end
     end
+
+    describe 'PUT #update' do
+      let(:scopes) { 'write:statuses' }
+      let(:status) { Fabricate(:status, account: user.account) }
+
+      before do
+        put :update, params: { id: status.id, status: 'I am updated' }
+      end
+
+      it 'returns http success' do
+        expect(response).to have_http_status(200)
+      end
+
+      it 'updates the status' do
+        expect(status.reload.text).to eq 'I am updated'
+      end
+    end
   end
 
   context 'without an oauth token' do