mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-13 15:58:50 +00:00
Merge commit 'c357a7f8d697ede4df4be74456b0497118c9d049' into glitch-soc/merge-upstream
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:fasp_follow_recommendation, from: 'Fasp::FollowRecommendation') do
|
||||
requesting_account { Fabricate.build(:account) }
|
||||
recommended_account { Fabricate.build(:account, domain: 'fedi.example.com') }
|
||||
end
|
||||
@@ -41,3 +41,15 @@ Fabricator(:follow_recommendation_fasp, from: :fasp_provider) do
|
||||
def fasp.update_remote_capabilities = true
|
||||
end
|
||||
end
|
||||
|
||||
Fabricator(:account_search_fasp, from: :fasp_provider) do
|
||||
confirmed true
|
||||
capabilities [
|
||||
{ id: 'account_search', version: '0.1', enabled: true },
|
||||
]
|
||||
|
||||
after_build do |fasp|
|
||||
# Prevent fabrication from attempting an HTTP call to the provider
|
||||
def fasp.update_remote_capabilities = true
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Mastodon::EmailConfigurationHelper do
|
||||
describe '#smtp_settings' do
|
||||
describe '#convert_smtp_settings' do
|
||||
subject { described_class }
|
||||
|
||||
let(:converted_settings) { subject.smtp_settings(configuration) }
|
||||
let(:converted_settings) { subject.convert_smtp_settings(configuration) }
|
||||
let(:base_configuration) do
|
||||
{
|
||||
address: 'localhost',
|
||||
|
||||
@@ -103,4 +103,9 @@ class UserMailerPreview < ActionMailer::Preview
|
||||
def terms_of_service_changed
|
||||
UserMailer.terms_of_service_changed(User.first, TermsOfService.live.first)
|
||||
end
|
||||
|
||||
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/announcement_published
|
||||
def announcement_published
|
||||
UserMailer.announcement_published(User.first, Announcement.last)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,6 +14,43 @@ RSpec.describe UserMailer do
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'optional bulk mailer settings' do
|
||||
context 'when no optional bulk mailer settings are present' do
|
||||
it 'does not include delivery method options' do
|
||||
expect(mail.message.delivery_method.settings).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when optional bulk mailer settings are present' do
|
||||
let(:smtp_settings) do
|
||||
{
|
||||
address: 'localhost',
|
||||
port: 25,
|
||||
authentication: 'none',
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
Rails.configuration.x.email ||= ActiveSupport::OrderedOptions.new
|
||||
Rails.configuration.x.email.update({ bulk_mail: { smtp_settings: } })
|
||||
end
|
||||
|
||||
after do
|
||||
Rails.configuration.x.email = nil
|
||||
end
|
||||
|
||||
it 'uses the bulk mailer settings' do
|
||||
expect(mail.message.delivery_method.settings).to eq({
|
||||
address: 'localhost',
|
||||
port: 25,
|
||||
authentication: nil,
|
||||
enable_starttls: nil,
|
||||
enable_starttls_auto: true,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:receiver) { Fabricate(:user) }
|
||||
|
||||
describe '#confirmation_instructions' do
|
||||
@@ -316,6 +353,8 @@ RSpec.describe UserMailer do
|
||||
.and(have_subject(I18n.t('user_mailer.terms_of_service_changed.subject')))
|
||||
.and(have_body_text(I18n.t('user_mailer.terms_of_service_changed.changelog')))
|
||||
end
|
||||
|
||||
it_behaves_like 'optional bulk mailer settings'
|
||||
end
|
||||
|
||||
describe '#announcement_published' do
|
||||
@@ -328,5 +367,7 @@ RSpec.describe UserMailer do
|
||||
.and(have_subject(I18n.t('user_mailer.announcement_published.subject')))
|
||||
.and(have_body_text(I18n.t('user_mailer.announcement_published.description', domain: local_domain_uri.host)))
|
||||
end
|
||||
|
||||
it_behaves_like 'optional bulk mailer settings'
|
||||
end
|
||||
end
|
||||
|
||||
23
spec/models/account_suggestions/fasp_source_spec.rb
Normal file
23
spec/models/account_suggestions/fasp_source_spec.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AccountSuggestions::FaspSource do
|
||||
describe '#get', feature: :fasp do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:bob) { Fabricate(:account) }
|
||||
let(:alice) { Fabricate(:account, domain: 'fedi.example.com') }
|
||||
let(:eve) { Fabricate(:account, domain: 'fedi.example.com') }
|
||||
|
||||
before do
|
||||
[alice, eve].each do |recommended_account|
|
||||
Fasp::FollowRecommendation.create!(requesting_account: bob, recommended_account:)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns recommendations obtained by FASP' do
|
||||
expect(subject.get(bob)).to contain_exactly([alice.id, :fasp], [eve.id, :fasp])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,6 +3,87 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TermsOfService do
|
||||
describe 'Validations' do
|
||||
subject { Fabricate.build :terms_of_service }
|
||||
|
||||
it { is_expected.to validate_presence_of(:text) }
|
||||
it { is_expected.to validate_uniqueness_of(:effective_date) }
|
||||
|
||||
it { is_expected.to allow_values(2.days.from_now).for(:effective_date) }
|
||||
it { is_expected.to_not allow_values(2.days.ago).for(:effective_date) }
|
||||
|
||||
context 'with an existing published effective TOS' do
|
||||
before do
|
||||
travel_to 5.days.ago do
|
||||
Fabricate :terms_of_service, published_at: 2.days.ago, effective_date: 1.day.from_now
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to allow_values(1.day.ago).for(:effective_date) }
|
||||
end
|
||||
|
||||
context 'when published' do
|
||||
subject { Fabricate.build :terms_of_service, published_at: Time.zone.today }
|
||||
|
||||
it { is_expected.to validate_presence_of(:changelog) }
|
||||
it { is_expected.to validate_presence_of(:effective_date) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Scopes' do
|
||||
describe '.published' do
|
||||
let!(:unpublished) { Fabricate :terms_of_service, published_at: nil }
|
||||
let!(:published_older_effective) { travel_to(3.days.ago) { Fabricate :terms_of_service, published_at: 5.days.ago, effective_date: Time.zone.today } }
|
||||
let!(:published_newer_effective) { travel_to(2.days.ago) { Fabricate :terms_of_service, published_at: 5.days.ago, effective_date: Time.zone.today } }
|
||||
|
||||
it 'returns published records in correct order' do
|
||||
expect(described_class.published)
|
||||
.to eq([published_newer_effective, published_older_effective])
|
||||
.and not_include(unpublished)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.live' do
|
||||
let!(:not_effective) { Fabricate :terms_of_service }
|
||||
let!(:effective_past) { travel_to(3.days.ago) { Fabricate :terms_of_service, effective_date: Time.zone.today } }
|
||||
let!(:effective_future) { Fabricate :terms_of_service, effective_date: 3.days.from_now }
|
||||
|
||||
before { not_effective.update_attribute(:effective_date, nil) }
|
||||
|
||||
it 'returns records without effective or with past effective' do
|
||||
expect(described_class.live)
|
||||
.to include(not_effective)
|
||||
.and include(effective_past)
|
||||
.and not_include(effective_future)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.upcoming' do
|
||||
let!(:unpublished) { Fabricate :terms_of_service, published_at: nil }
|
||||
let!(:effective_past) { travel_to(3.days.ago) { Fabricate :terms_of_service, effective_date: Time.zone.today } }
|
||||
let!(:effective_future_near) { Fabricate :terms_of_service, effective_date: 3.days.from_now }
|
||||
let!(:effective_future_far) { Fabricate :terms_of_service, effective_date: 5.days.from_now }
|
||||
|
||||
it 'returns published records with future effective date in order of soonest first' do
|
||||
expect(described_class.upcoming)
|
||||
.to eq([effective_future_near, effective_future_far])
|
||||
.and not_include(unpublished)
|
||||
.and not_include(effective_past)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.draft' do
|
||||
let!(:published) { Fabricate :terms_of_service, published_at: 2.days.ago }
|
||||
let!(:unpublished) { Fabricate :terms_of_service, published_at: nil }
|
||||
|
||||
it 'returns not published records' do
|
||||
expect(described_class.draft)
|
||||
.to include(unpublished)
|
||||
.and not_include(published)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#scope_for_notification' do
|
||||
subject { terms_of_service.scope_for_notification }
|
||||
|
||||
|
||||
@@ -118,6 +118,15 @@ RSpec.describe 'Search API' do
|
||||
.to start_with('application/json')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when `account_search` FASP is enabled', feature: :fasp do
|
||||
it 'enqueues a retrieval job and adds a header to inform the client' do
|
||||
get '/api/v2/search', headers: headers, params: params
|
||||
|
||||
expect(Fasp::AccountSearchWorker).to have_enqueued_sidekiq_job
|
||||
expect(response.headers['Mastodon-Async-Refresh']).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
57
spec/requests/public_files_spec.rb
Normal file
57
spec/requests/public_files_spec.rb
Normal file
@@ -0,0 +1,57 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Public files' do
|
||||
include RoutingHelper
|
||||
|
||||
context 'when requesting service worker file' do
|
||||
it 'returns the file with the expected headers' do
|
||||
get '/sw.js'
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
|
||||
expect(response.headers['Cache-Control'])
|
||||
.to eq "public, max-age=#{Mastodon::Middleware::PublicFileServer::SERVICE_WORKER_TTL}, must-revalidate"
|
||||
|
||||
expect(response.headers['X-Content-Type-Options'])
|
||||
.to eq 'nosniff'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when requesting paperclip attachments', :attachment_processing do
|
||||
let(:attachment) { Fabricate(:media_attachment, type: :image) }
|
||||
|
||||
it 'returns the file with the expected headers' do
|
||||
get attachment.file.url(:original)
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
|
||||
expect(response.headers['Cache-Control'])
|
||||
.to eq "public, max-age=#{Mastodon::Middleware::PublicFileServer::CACHE_TTL}, immutable"
|
||||
|
||||
expect(response.headers['Content-Security-Policy'])
|
||||
.to eq "default-src 'none'; form-action 'none'"
|
||||
|
||||
expect(response.headers['X-Content-Type-Options'])
|
||||
.to eq 'nosniff'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when requesting other static files' do
|
||||
it 'returns the file with the expected headers' do
|
||||
get '/sounds/boop.ogg'
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
|
||||
expect(response.headers['Cache-Control'])
|
||||
.to eq "public, max-age=#{Mastodon::Middleware::PublicFileServer::CACHE_TTL}, must-revalidate"
|
||||
|
||||
expect(response.headers['X-Content-Type-Options'])
|
||||
.to eq 'nosniff'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -66,7 +66,7 @@ RSpec.describe SearchService do
|
||||
allow(AccountSearchService).to receive(:new).and_return(service)
|
||||
|
||||
results = subject.call(query, nil, 10)
|
||||
expect(service).to have_received(:call).with(query, nil, limit: 10, offset: 0, resolve: false, start_with_hashtag: false, use_searchable_text: true, following: false)
|
||||
expect(service).to have_received(:call).with(query, nil, limit: 10, offset: 0, resolve: false, start_with_hashtag: false, use_searchable_text: true, following: false, query_fasp: nil)
|
||||
expect(results).to eq empty_results.merge(accounts: [account])
|
||||
end
|
||||
end
|
||||
|
||||
50
spec/workers/fasp/account_search_worker_spec.rb
Normal file
50
spec/workers/fasp/account_search_worker_spec.rb
Normal file
@@ -0,0 +1,50 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Fasp::AccountSearchWorker, feature: :fasp do
|
||||
include ProviderRequestHelper
|
||||
|
||||
let(:provider) { Fabricate(:account_search_fasp) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:fetch_service) { instance_double(ActivityPub::FetchRemoteActorService, call: true) }
|
||||
|
||||
let!(:stubbed_request) do
|
||||
path = '/account_search/v0/search?term=cats&limit=10'
|
||||
stub_provider_request(provider,
|
||||
method: :get,
|
||||
path:,
|
||||
response_body: [
|
||||
'https://fedi.example.com/accounts/2',
|
||||
'https://fedi.example.com/accounts/9',
|
||||
])
|
||||
end
|
||||
|
||||
before do
|
||||
allow(ActivityPub::FetchRemoteActorService).to receive(:new).and_return(fetch_service)
|
||||
end
|
||||
|
||||
it 'requests search results and fetches received account uris' do
|
||||
described_class.new.perform('cats')
|
||||
|
||||
expect(stubbed_request).to have_been_made
|
||||
expect(fetch_service).to have_received(:call).with('https://fedi.example.com/accounts/2')
|
||||
expect(fetch_service).to have_received(:call).with('https://fedi.example.com/accounts/9')
|
||||
end
|
||||
|
||||
it 'marks a running async refresh as finished' do
|
||||
async_refresh = AsyncRefresh.create("fasp:account_search:#{Digest::MD5.base64digest('cats')}", count_results: true)
|
||||
|
||||
described_class.new.perform('cats')
|
||||
|
||||
expect(async_refresh.reload).to be_finished
|
||||
end
|
||||
|
||||
it 'tracks the number of fetched accounts in the async refresh' do
|
||||
async_refresh = AsyncRefresh.create("fasp:account_search:#{Digest::MD5.base64digest('cats')}", count_results: true)
|
||||
|
||||
described_class.new.perform('cats')
|
||||
|
||||
expect(async_refresh.reload.result_count).to eq 2
|
||||
end
|
||||
end
|
||||
@@ -7,7 +7,7 @@ RSpec.describe Fasp::FollowRecommendationWorker, feature: :fasp do
|
||||
|
||||
let(:provider) { Fabricate(:follow_recommendation_fasp) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:fetch_service) { instance_double(ActivityPub::FetchRemoteActorService, call: true) }
|
||||
let(:fetch_service) { instance_double(ActivityPub::FetchRemoteActorService) }
|
||||
|
||||
let!(:stubbed_request) do
|
||||
account_uri = ActivityPub::TagManager.instance.uri_for(account)
|
||||
@@ -23,6 +23,8 @@ RSpec.describe Fasp::FollowRecommendationWorker, feature: :fasp do
|
||||
|
||||
before do
|
||||
allow(ActivityPub::FetchRemoteActorService).to receive(:new).and_return(fetch_service)
|
||||
|
||||
allow(fetch_service).to receive(:call).and_invoke(->(_) { Fabricate(:account, domain: 'fedi.example.com') })
|
||||
end
|
||||
|
||||
it "sends the requesting account's uri to provider and fetches received account uris" do
|
||||
@@ -48,4 +50,10 @@ RSpec.describe Fasp::FollowRecommendationWorker, feature: :fasp do
|
||||
|
||||
expect(async_refresh.reload.result_count).to eq 2
|
||||
end
|
||||
|
||||
it 'persists the results' do
|
||||
expect do
|
||||
described_class.new.perform(account.id)
|
||||
end.to change(Fasp::FollowRecommendation, :count).by(2)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Scheduler::Fasp::FollowRecommendationCleanupScheduler do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe '#perform', feature: :fasp do
|
||||
before do
|
||||
Fabricate(:fasp_follow_recommendation, created_at: 2.days.ago)
|
||||
end
|
||||
|
||||
it 'deletes outdated recommendations' do
|
||||
expect { worker.perform }.to change(Fasp::FollowRecommendation, :count).by(-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user