Merge commit 'a5b4a2b7e7' into kb-draft-5.21-lts

This commit is contained in:
KMY 2024-07-05 06:40:30 +09:00
commit 6896542a76
33 changed files with 338 additions and 109 deletions

View file

@ -43,6 +43,11 @@ describe Admin::StatusesController do
describe 'GET #show' do
before do
status.media_attachments << Fabricate(:media_attachment, type: :image, account: status.account)
status.save!
status.snapshot!(at_time: status.created_at, rate_limit: false)
status.update!(text: 'Hello, this is an edited post')
status.snapshot!(rate_limit: false)
get :show, params: { account_id: account.id, id: status.id }
end

View file

@ -13,6 +13,17 @@ describe Api::V1::ScheduledStatusesController do
allow(controller).to receive(:doorkeeper_token) { token }
end
context 'with an application token' do
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: 'read:statuses') }
it 'returns http unprocessable entity' do
get :index
expect(response)
.to have_http_status(422)
end
end
describe 'GET #index' do
it 'returns http success' do
get :index

View file

@ -9,6 +9,26 @@ describe Api::V1::Statuses::TranslationsController do
let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses', application: app) }
context 'with an application token' do
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: 'read:statuses', application: app) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST /api/v1/statuses/:status_id/translate' do
let(:status) { Fabricate(:status, account: user.account, text: 'Hola', language: 'es') }
before do
post :create, params: { status_id: status.id }
end
it 'returns http unprocessable entity' do
expect(response).to have_http_status(422)
end
end
end
context 'with an oauth token' do
before do
allow(controller).to receive(:doorkeeper_token) { token }

View file

@ -182,6 +182,46 @@ RSpec.describe Api::V1::StatusesController do
expect(response.headers['X-RateLimit-Remaining']).to eq '0'
end
end
context 'with missing thread' do
subject { post :create, params: params }
let(:params) { { status: 'Hello world', in_reply_to_id: 0 } }
it 'returns http not found' do
subject
expect(response).to have_http_status(404)
end
end
context 'when scheduling a status' do
subject { post :create, params: params }
let(:params) { { status: 'Hello world', scheduled_at: 10.minutes.from_now } }
let(:account) { user.account }
it 'returns HTTP 200' do
subject
expect(response).to have_http_status(200)
end
it 'creates a scheduled status' do
expect { subject }.to change { account.scheduled_statuses.count }.from(0).to(1)
end
context 'when the scheduling time is less than 5 minutes' do
let(:params) { { status: 'Hello world', scheduled_at: 4.minutes.from_now } }
it 'does not create a scheduled status', :aggregate_failures do
subject
expect(response).to have_http_status(422)
expect(account.scheduled_statuses).to be_empty
end
end
end
end
describe 'DELETE #destroy' do

View file

@ -6,7 +6,8 @@ describe Api::V1::Timelines::TagController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
let(:scopes) { 'read:statuses' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
@ -48,13 +49,23 @@ describe Api::V1::Timelines::TagController do
Form::AdminSettings.new(timeline_preview: false).save
end
context 'when the user is not authenticated' do
context 'without an access token' do
let(:token) { nil }
it 'returns http unauthorized' do
it 'returns http unprocessable entity' do
subject
expect(response).to have_http_status(401)
expect(response).to have_http_status(422)
end
end
context 'with an application access token, not bound to a user' do
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: scopes) }
it 'returns http unprocessable entity' do
subject
expect(response).to have_http_status(422)
end
end

View file

@ -50,9 +50,11 @@ describe Oauth::AuthorizedApplicationsController do
let!(:application) { Fabricate(:application) }
let!(:access_token) { Fabricate(:accessible_access_token, application: application, resource_owner_id: user.id) }
let!(:web_push_subscription) { Fabricate(:web_push_subscription, user: user, access_token: access_token) }
let(:redis_pipeline_stub) { instance_double(Redis::Namespace, publish: nil) }
before do
sign_in user, scope: :user
allow(redis).to receive(:pipelined).and_yield(redis_pipeline_stub)
post :destroy, params: { id: application.id }
end
@ -63,5 +65,13 @@ describe Oauth::AuthorizedApplicationsController do
it 'removes subscriptions for the application\'s access tokens' do
expect(Web::PushSubscription.where(user: user).count).to eq 0
end
it 'removes the web_push_subscription' do
expect { web_push_subscription.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
it 'sends a session kill payload to the streaming server' do
expect(redis_pipeline_stub).to have_received(:publish).with("timeline:access_token:#{access_token.id}", '{"event":"kill"}')
end
end
end

View file

@ -166,7 +166,11 @@ describe Settings::ApplicationsController do
end
describe 'destroy' do
let(:redis_pipeline_stub) { instance_double(Redis::Namespace, publish: nil) }
let!(:access_token) { Fabricate(:accessible_access_token, application: app) }
before do
allow(redis).to receive(:pipelined).and_yield(redis_pipeline_stub)
post :destroy, params: { id: app.id }
end
@ -177,6 +181,10 @@ describe Settings::ApplicationsController do
it 'removes the app' do
expect(Doorkeeper::Application.find_by(id: app.id)).to be_nil
end
it 'sends a session kill payload to the streaming server' do
expect(redis_pipeline_stub).to have_received(:publish).with("timeline:access_token:#{access_token.id}", '{"event":"kill"}')
end
end
describe 'regenerate' do

View file

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
server: nginx
date: Thu, 13 Jun 2024 14:33:13 GMT
content-type: text/html; charset=ISO-8859-1
content-length: 158
accept-ranges: bytes
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tofu á l'orange</title>
</head>
<body>
<h2>Tofu á l'orange</h2>
</body>
</html>

View file

@ -32,6 +32,8 @@ describe 'Public' do
context 'when the instance allows public preview' do
let(:expected_statuses) { [local_status, remote_status, media_status] }
it_behaves_like 'forbidden for wrong scope', 'profile'
context 'with an authorized user' do
it_behaves_like 'a successful request to the public timeline'
end
@ -96,13 +98,9 @@ describe 'Public' do
Form::AdminSettings.new(timeline_preview: false).save
end
context 'with an authenticated user' do
let(:expected_statuses) { [local_status, remote_status, media_status] }
it_behaves_like 'forbidden for wrong scope', 'profile'
it_behaves_like 'a successful request to the public timeline'
end
context 'with an unauthenticated user' do
context 'without an authentication token' do
let(:headers) { {} }
it 'returns http unprocessable entity' do
@ -111,6 +109,22 @@ describe 'Public' do
expect(response).to have_http_status(422)
end
end
context 'with an application access token, not bound to a user' do
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: scopes) }
it 'returns http unprocessable entity' do
subject
expect(response).to have_http_status(422)
end
end
context 'with an authenticated user' do
let(:expected_statuses) { [local_status, remote_status, media_status] }
it_behaves_like 'a successful request to the public timeline'
end
end
end
end

View file

@ -56,9 +56,11 @@ RSpec.describe BackupService, type: :service do
end
def expect_outbox_export
json = export_json(:outbox)
body = export_json_raw(:outbox)
json = Oj.load(body)
aggregate_failures do
expect(body.scan('@context').count).to eq 1
expect(json['@context']).to_not be_nil
expect(json['type']).to eq 'OrderedCollection'
expect(json['totalItems']).to eq 3
@ -87,8 +89,12 @@ RSpec.describe BackupService, type: :service do
end
end
def export_json_raw(type)
read_zip_file(backup, "#{type}.json")
end
def export_json(type)
Oj.load(read_zip_file(backup, "#{type}.json"))
Oj.load(export_json_raw(type))
end
def include_create_item(status)

View file

@ -27,6 +27,7 @@ RSpec.describe FetchLinkCardService, type: :service do
stub_request(:get, 'http://example.com/sjis_with_wrong_charset').to_return(request_fixture('sjis_with_wrong_charset.txt'))
stub_request(:get, 'http://example.com/koi8-r').to_return(request_fixture('koi8-r.txt'))
stub_request(:get, 'http://example.com/windows-1251').to_return(request_fixture('windows-1251.txt'))
stub_request(:get, 'http://example.com/low_confidence_latin1').to_return(request_fixture('low_confidence_latin1.txt'))
Rails.cache.write('oembed_endpoint:example.com', oembed_cache) if oembed_cache
@ -149,6 +150,14 @@ RSpec.describe FetchLinkCardService, type: :service do
end
end
context 'with a URL of a page in ISO-8859-1 encoding, that charlock_holmes cannot detect' do
let(:status) { Fabricate(:status, text: 'Check out http://example.com/low_confidence_latin1') }
it 'decodes the HTML' do
expect(status.preview_card.title).to eq("Tofu á l'orange")
end
end
context 'with a Japanese path URL' do
let(:status) { Fabricate(:status, text: 'テストhttp://example.com/日本語') }
@ -185,6 +194,19 @@ RSpec.describe FetchLinkCardService, type: :service do
end
end
context 'with an URL too long for PostgreSQL unique indexes' do
let(:url) { "http://example.com/#{'a' * 2674}" }
let(:status) { Fabricate(:status, text: url) }
it 'does not fetch the URL' do
expect(a_request(:get, url)).to_not have_been_made
end
it 'does not create a preview card' do
expect(status.preview_card).to be_nil
end
end
context 'with a URL of a page with oEmbed support' do
let(:html) { '<!doctype html><title>Hello world</title><link rel="alternate" type="application/json+oembed" href="http://example.com/oembed?url=http://example.com/html">' }
let(:status) { Fabricate(:status, text: 'http://example.com/html') }

View file

@ -61,6 +61,16 @@ RSpec.describe PostStatusService, type: :service do
status2 = subject.call(account, text: 'test', idempotency: 'meepmeep', scheduled_at: future)
expect(status2.id).to eq status1.id
end
context 'when scheduled_at is less than min offset' do
let(:invalid_scheduled_time) { 4.minutes.from_now }
it 'raises invalid record error' do
expect do
subject.call(account, text: 'Hi future!', scheduled_at: invalid_scheduled_time)
end.to raise_error(ActiveRecord::RecordInvalid)
end
end
end
it 'creates response to the original status of boost' do