1
0
Fork 0
forked from gitea/nas

Merge remote-tracking branch 'parent/main' into upstream-20231124

This commit is contained in:
KMY 2023-11-24 09:07:40 +09:00
commit c5e4020922
206 changed files with 1987 additions and 965 deletions

View file

@ -79,6 +79,22 @@ describe 'GET /api/v1/accounts/relationships' do
end
end
context 'when there are duplicate IDs in the params' do
let(:params) { { id: [simon.id, lewis.id, lewis.id, lewis.id, simon.id] } }
it 'removes duplicate account IDs from params' do
subject
expect(body_as_json)
.to be_an(Enumerable)
.and have_attributes(
size: 2,
first: include(simon_item),
second: include(lewis_item)
)
end
end
def simon_item
{
id: simon.id.to_s,

View file

@ -0,0 +1,35 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin Dimensions' do
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
describe 'GET /api/v1/admin/dimensions' do
context 'when not authorized' do
it 'returns http forbidden' do
post '/api/v1/admin/dimensions', params: { account_id: account.id, limit: 2 }
expect(response)
.to have_http_status(403)
end
end
context 'with correct scope' do
let(:scopes) { 'admin:read' }
it 'returns http success and status json' do
post '/api/v1/admin/dimensions', params: { account_id: account.id, limit: 2 }, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_an(Array)
end
end
end
end

View file

@ -35,7 +35,7 @@ RSpec.describe 'Domain Allows' do
end
context 'when there are allowed domains' do
let!(:domain_allows) { Fabricate.times(5, :domain_allow) }
let!(:domain_allows) { Fabricate.times(2, :domain_allow) }
let(:expected_response) do
domain_allows.map do |domain_allow|
{
@ -53,7 +53,7 @@ RSpec.describe 'Domain Allows' do
end
context 'with limit param' do
let(:params) { { limit: 2 } }
let(:params) { { limit: 1 } }
it 'returns only the requested number of allowed domains' do
subject

View file

@ -0,0 +1,35 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin Measures' do
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
describe 'GET /api/v1/admin/measures' do
context 'when not authorized' do
it 'returns http forbidden' do
post '/api/v1/admin/measures', params: { account_id: account.id, limit: 2 }
expect(response)
.to have_http_status(403)
end
end
context 'with correct scope' do
let(:scopes) { 'admin:read' }
it 'returns http success and status json' do
post '/api/v1/admin/measures', params: { account_id: account.id, limit: 2 }, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_an(Array)
end
end
end
end

View file

@ -0,0 +1,35 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin Retention' do
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
describe 'GET /api/v1/admin/retention' do
context 'when not authorized' do
it 'returns http forbidden' do
post '/api/v1/admin/retention', params: { account_id: account.id, limit: 2 }
expect(response)
.to have_http_status(403)
end
end
context 'with correct scope' do
let(:scopes) { 'admin:read' }
it 'returns http success and status json' do
post '/api/v1/admin/retention', params: { account_id: account.id, limit: 2 }, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_an(Array)
end
end
end
end

View file

@ -14,7 +14,7 @@ RSpec.describe 'Bookmarks' do
end
let(:params) { {} }
let!(:bookmarks) { Fabricate.times(3, :bookmark, account: user.account) }
let!(:bookmarks) { Fabricate.times(2, :bookmark, account: user.account) }
let(:expected_response) do
bookmarks.map do |bookmark|
@ -37,7 +37,7 @@ RSpec.describe 'Bookmarks' do
end
context 'with limit param' do
let(:params) { { limit: 2 } }
let(:params) { { limit: 1 } }
it 'paginates correctly', :aggregate_failures do
subject

View file

@ -0,0 +1,45 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Custom Emojis' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/custom_emojis' do
before do
Fabricate(:custom_emoji, domain: nil, disabled: false, visible_in_picker: true)
end
context 'when logged out' do
it 'returns http success and json' do
get api_v1_custom_emojis_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and have_attributes(
first: include(shortcode: 'coolcat')
)
end
end
context 'when logged in' do
it 'returns http success and json' do
get api_v1_custom_emojis_path, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and have_attributes(
first: include(shortcode: 'coolcat')
)
end
end
end
end

View file

@ -0,0 +1,61 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Endorsements' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/endorsements' do
context 'when not authorized' do
it 'returns http unauthorized' do
get api_v1_endorsements_path
expect(response)
.to have_http_status(401)
end
end
context 'with wrong scope' do
before do
get api_v1_endorsements_path, headers: headers
end
it_behaves_like 'forbidden for wrong scope', 'write write:accounts'
end
context 'with correct scope' do
let(:scopes) { 'read:accounts' }
context 'with endorsed accounts' do
let!(:account_pin) { Fabricate(:account_pin, account: user.account) }
it 'returns http success and accounts json' do
get api_v1_endorsements_path, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and have_attributes(
first: include(acct: account_pin.target_account.acct)
)
end
end
context 'without endorsed accounts without json' do
it 'returns http success' do
get api_v1_endorsements_path, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to_not be_present
end
end
end
end
end

View file

@ -14,7 +14,7 @@ RSpec.describe 'Favourites' do
end
let(:params) { {} }
let!(:favourites) { Fabricate.times(3, :favourite, account: user.account) }
let!(:favourites) { Fabricate.times(2, :favourite, account: user.account) }
let(:expected_response) do
favourites.map do |favourite|
@ -37,7 +37,7 @@ RSpec.describe 'Favourites' do
end
context 'with limit param' do
let(:params) { { limit: 2 } }
let(:params) { { limit: 1 } }
it 'returns only the requested number of favourites' do
subject

View file

@ -32,7 +32,7 @@ RSpec.describe 'FeaturedTags' do
end
context 'when the requesting user has no featured tag' do
before { Fabricate.times(3, :featured_tag) }
before { Fabricate(:featured_tag) }
it 'returns an empty body' do
get '/api/v1/featured_tags', headers: headers
@ -44,7 +44,7 @@ RSpec.describe 'FeaturedTags' do
end
context 'when the requesting user has featured tags' do
let!(:user_featured_tags) { Fabricate.times(5, :featured_tag, account: user.account) }
let!(:user_featured_tags) { Fabricate.times(1, :featured_tag, account: user.account) }
it 'returns only the featured tags belonging to the requesting user' do
get '/api/v1/featured_tags', headers: headers

View file

@ -13,7 +13,7 @@ RSpec.describe 'Follow requests' do
get '/api/v1/follow_requests', headers: headers, params: params
end
let(:accounts) { Fabricate.times(5, :account) }
let(:accounts) { Fabricate.times(2, :account) }
let(:params) { {} }
let(:expected_response) do
@ -40,7 +40,7 @@ RSpec.describe 'Follow requests' do
end
context 'with limit param' do
let(:params) { { limit: 2 } }
let(:params) { { limit: 1 } }
it 'returns only the requested number of follow requests' do
subject

View file

@ -13,7 +13,7 @@ RSpec.describe 'Followed tags' do
get '/api/v1/followed_tags', headers: headers, params: params
end
let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) }
let!(:tag_follows) { Fabricate.times(2, :tag_follow, account: user.account) }
let(:params) { {} }
let(:expected_response) do
@ -41,7 +41,7 @@ RSpec.describe 'Followed tags' do
end
context 'with limit param' do
let(:params) { { limit: 3 } }
let(:params) { { limit: 1 } }
it 'returns only the requested number of follow tags' do
subject
@ -58,7 +58,7 @@ RSpec.describe 'Followed tags' do
it 'sets the correct pagination header for the next path' do
subject
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], max_id: tag_follows[2].id))
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], max_id: tag_follows.last.id))
end
end
end

View file

@ -0,0 +1,37 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Instances' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/instance' do
context 'when not logged in' do
it 'returns http success and json' do
get api_v1_instance_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and include(title: 'Mastodon')
end
end
context 'when logged in' do
it 'returns http success and json' do
get api_v1_instance_path, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and include(title: 'Mastodon')
end
end
end
end

View file

@ -0,0 +1,40 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Activity' do
describe 'GET /api/v1/instance/activity' do
around do |example|
original = Setting.activity_api_enabled
example.run
Setting.activity_api_enabled = original
end
context 'with activity api enabled' do
before { Setting.activity_api_enabled = true }
it 'returns http success' do
get api_v1_instance_activity_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and(be_an(Array))
.and(have_attributes(size: Api::V1::Instances::ActivityController::WEEKS_OF_ACTIVITY))
end
end
context 'with activity api diabled' do
before { Setting.activity_api_enabled = false }
it 'returns not found' do
get api_v1_instance_activity_path
expect(response)
.to have_http_status(404)
end
end
end
end

View file

@ -0,0 +1,55 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Domain Blocks' do
describe 'GET /api/v1/instance/domain_blocks' do
around do |example|
original = Setting.show_domain_blocks
example.run
Setting.show_domain_blocks = original
end
before do
Fabricate(:domain_block)
end
context 'with domain blocks set to all' do
before { Setting.show_domain_blocks = 'all' }
it 'returns http success' do
get api_v1_instance_domain_blocks_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and(be_an(Array))
.and(have_attributes(size: 1))
end
end
context 'with domain blocks set to users' do
before { Setting.show_domain_blocks = 'users' }
it 'returns http not found' do
get api_v1_instance_domain_blocks_path
expect(response)
.to have_http_status(404)
end
end
context 'with domain blocks set to disabled' do
before { Setting.show_domain_blocks = 'disabled' }
it 'returns http not found' do
get api_v1_instance_domain_blocks_path
expect(response)
.to have_http_status(404)
end
end
end
end

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Extended Descriptions' do
describe 'GET /api/v1/instance/extended_description' do
it 'returns http success' do
get api_v1_instance_extended_description_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and include(:content)
end
end
end

View file

@ -0,0 +1,38 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Peers' do
describe 'GET /api/v1/instance/peers' do
around do |example|
original = Setting.peers_api_enabled
example.run
Setting.peers_api_enabled = original
end
context 'with peers api enabled' do
before { Setting.peers_api_enabled = true }
it 'returns http success' do
get api_v1_instance_peers_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_an(Array)
end
end
context 'with peers api diabled' do
before { Setting.peers_api_enabled = false }
it 'returns http not found' do
get api_v1_instance_peers_path
expect(response)
.to have_http_status(404)
end
end
end
end

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Privacy Policy' do
describe 'GET /api/v1/instance/privacy_policy' do
it 'returns http success' do
get api_v1_instance_privacy_policy_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and include(:content)
end
end
end

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Rules' do
describe 'GET /api/v1/instance/rules' do
it 'returns http success' do
get api_v1_instance_rules_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_an(Array)
end
end
end

View file

@ -0,0 +1,43 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Translation Languages' do
describe 'GET /api/v1/instances/translation_languages' do
context 'when no translation service is configured' do
it 'returns empty language matrix', :aggregate_failures do
get api_v1_instance_translation_languages_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to eq({})
end
end
context 'when a translation service is configured' do
before { configure_translation_service }
it 'returns language matrix', :aggregate_failures do
get api_v1_instance_translation_languages_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to eq({ und: %w(en de), en: ['de'] })
end
private
def configure_translation_service
allow(TranslationService).to receive_messages(configured?: true, configured: service_double)
end
def service_double
instance_double(TranslationService::DeepL, languages: { nil => %w(en de), 'en' => ['de'] })
end
end
end
end

View file

@ -15,7 +15,7 @@ RSpec.describe 'Accounts' do
let(:params) { { limit: 0 } }
let(:list) { Fabricate(:list, account: user.account) }
let(:accounts) { Fabricate.times(3, :account) }
let(:accounts) { Fabricate.times(2, :account) }
let(:expected_response) do
accounts.map do |account|

View file

@ -13,7 +13,7 @@ RSpec.describe 'Mutes' do
get '/api/v1/mutes', headers: headers, params: params
end
let!(:mutes) { Fabricate.times(3, :mute, account: user.account) }
let!(:mutes) { Fabricate.times(2, :mute, account: user.account) }
let(:params) { {} }
it_behaves_like 'forbidden for wrong scope', 'write write:mutes'
@ -33,7 +33,7 @@ RSpec.describe 'Mutes' do
end
context 'with limit param' do
let(:params) { { limit: 2 } }
let(:params) { { limit: 1 } }
it 'returns only the requested number of muted accounts' do
subject
@ -46,8 +46,8 @@ RSpec.describe 'Mutes' do
headers = response.headers['Link']
expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_mutes_url(limit: params[:limit], since_id: mutes[2].id.to_s))
expect(headers.find_link(%w(rel next)).href).to eq(api_v1_mutes_url(limit: params[:limit], max_id: mutes[1].id.to_s))
expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_mutes_url(limit: params[:limit], since_id: mutes.last.id.to_s))
expect(headers.find_link(%w(rel next)).href).to eq(api_v1_mutes_url(limit: params[:limit], max_id: mutes.last.id.to_s))
end
end
@ -72,8 +72,8 @@ RSpec.describe 'Mutes' do
body = body_as_json
expect(body.size).to eq 2
expect(body[0][:id]).to eq mutes[2].target_account_id.to_s
expect(body.size).to eq 1
expect(body[0][:id]).to eq mutes[1].target_account_id.to_s
end
end

View file

@ -168,7 +168,7 @@ RSpec.describe 'Notifications' do
end
before do
Fabricate.times(3, :notification, account: user.account)
Fabricate(:notification, account: user.account)
end
it_behaves_like 'forbidden for wrong scope', 'read read:notifications'

View file

@ -0,0 +1,42 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Preferences' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/preferences' do
context 'when not authorized' do
it 'returns http unauthorized' do
get api_v1_preferences_path
expect(response)
.to have_http_status(401)
end
end
context 'with wrong scope' do
before do
get api_v1_preferences_path, headers: headers
end
it_behaves_like 'forbidden for wrong scope', 'write write:accounts'
end
context 'with correct scope' do
let(:scopes) { 'read:accounts' }
it 'returns http success' do
get api_v1_preferences_path, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
end
end
end
end

View file

@ -0,0 +1,61 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Scheduled Statuses' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/scheduled_statuses' do
context 'when not authorized' do
it 'returns http unauthorized' do
get api_v1_scheduled_statuses_path
expect(response)
.to have_http_status(401)
end
end
context 'with wrong scope' do
before do
get api_v1_scheduled_statuses_path, headers: headers
end
it_behaves_like 'forbidden for wrong scope', 'write write:statuses'
end
context 'with correct scope' do
let(:scopes) { 'read:statuses' }
context 'without scheduled statuses' do
it 'returns http success without json' do
get api_v1_scheduled_statuses_path, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to_not be_present
end
end
context 'with scheduled statuses' do
let!(:scheduled_status) { Fabricate(:scheduled_status, account: user.account) }
it 'returns http success and status json' do
get api_v1_scheduled_statuses_path, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and have_attributes(
first: include(id: scheduled_status.id.to_s)
)
end
end
end
end
end

View file

@ -70,19 +70,13 @@ RSpec.describe 'Favourites' do
end
end
describe 'POST /api/v1/statuses/:status_id/unfavourite' do
describe 'POST /api/v1/statuses/:status_id/unfavourite', :sidekiq_fake do
subject do
post "/api/v1/statuses/#{status.id}/unfavourite", headers: headers
end
let(:status) { Fabricate(:status) }
around do |example|
Sidekiq::Testing.fake! do
example.run
end
end
it_behaves_like 'forbidden for wrong scope', 'read read:favourites'
context 'with public status' do

View file

@ -245,7 +245,7 @@ describe '/api/v1/statuses' do
context 'when exceeding rate limit' do
before do
rate_limiter = RateLimiter.new(user.account, family: :statuses)
300.times { rate_limiter.record! }
RateLimiter::FAMILIES[:statuses][:limit].times { rate_limiter.record! }
end
it 'returns rate limit headers', :aggregate_failures do

View file

@ -23,7 +23,7 @@ RSpec.describe 'Filters' do
get '/api/v2/filters', headers: headers
end
let!(:filters) { Fabricate.times(3, :custom_filter, account: user.account) }
let!(:filters) { Fabricate.times(2, :custom_filter, account: user.account) }
it_behaves_like 'forbidden for wrong scope', 'write write:filters'
it_behaves_like 'unauthorized for invalid token'

View file

@ -0,0 +1,37 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Instances' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v2/instance' do
context 'when logged out' do
it 'returns http success and json' do
get api_v2_instance_path
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and include(title: 'Mastodon')
end
end
context 'when logged in' do
it 'returns http success and json' do
get api_v2_instance_path, headers: headers
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_present
.and include(title: 'Mastodon')
end
end
end
end

View file

@ -9,10 +9,82 @@ RSpec.describe 'Media API', :paperclip_processing do
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'POST /api/v2/media' do
it 'returns http success' do
post '/api/v2/media', headers: headers, params: { file: fixture_file_upload('attachment-jpg.123456_abcd', 'image/jpeg') }
expect(File.exist?(user.account.media_attachments.first.file.path(:small))).to be true
expect(response).to have_http_status(200)
context 'when small media format attachment is processed immediately' do
let(:params) { { file: fixture_file_upload('attachment-jpg.123456_abcd', 'image/jpeg') } }
it 'returns http success' do
post '/api/v2/media', headers: headers, params: params
expect(File.exist?(user.account.media_attachments.first.file.path(:small)))
.to be true
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to be_a(Hash)
end
end
context 'when large format media attachment has not been processed' do
let(:params) { { file: fixture_file_upload('attachment.webm', 'video/webm') } }
it 'returns http accepted' do
post '/api/v2/media', headers: headers, params: params
expect(File.exist?(user.account.media_attachments.first.file.path(:small)))
.to be true
expect(response)
.to have_http_status(202)
expect(body_as_json)
.to be_a(Hash)
end
end
describe 'when paperclip errors occur' do
let(:media_attachments) { double }
let(:params) { { file: fixture_file_upload('attachment.jpg', 'image/jpeg') } }
before do
allow(User).to receive(:find).with(token.resource_owner_id).and_return(user)
allow(user.account).to receive(:media_attachments).and_return(media_attachments)
end
context 'when imagemagick cannot identify the file type' do
before do
allow(media_attachments).to receive(:create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError)
end
it 'returns http unprocessable entity' do
post '/api/v2/media', headers: headers, params: params
expect(response)
.to have_http_status(422)
expect(body_as_json)
.to be_a(Hash)
.and include(error: /File type/)
end
end
context 'when there is a generic error' do
before do
allow(media_attachments).to receive(:create!).and_raise(Paperclip::Error)
end
it 'returns http 500' do
post '/api/v2/media', headers: headers, params: params
expect(response)
.to have_http_status(500)
expect(body_as_json)
.to be_a(Hash)
.and include(error: /processing/)
end
end
end
end
end