Merge remote-tracking branch 'parent/main' into upstream-20241006
This commit is contained in:
commit
66bed31dbe
226 changed files with 2688 additions and 1846 deletions
|
@ -247,7 +247,7 @@ RSpec.describe Auth::SessionsController do
|
|||
context 'when using two-factor authentication' do
|
||||
context 'with OTP enabled as second factor' do
|
||||
let!(:user) do
|
||||
Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))
|
||||
Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret)
|
||||
end
|
||||
|
||||
let!(:recovery_codes) do
|
||||
|
@ -269,7 +269,7 @@ RSpec.describe Auth::SessionsController do
|
|||
|
||||
context 'when using email and password after an unfinished log-in attempt to a 2FA-protected account' do
|
||||
let!(:other_user) do
|
||||
Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))
|
||||
Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret)
|
||||
end
|
||||
|
||||
before do
|
||||
|
@ -381,7 +381,7 @@ RSpec.describe Auth::SessionsController do
|
|||
|
||||
context 'with WebAuthn and OTP enabled as second factor' do
|
||||
let!(:user) do
|
||||
Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))
|
||||
Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret)
|
||||
end
|
||||
|
||||
let!(:webauthn_credential) do
|
||||
|
|
|
@ -18,7 +18,7 @@ RSpec.describe Settings::TwoFactorAuthentication::ConfirmationsController do
|
|||
def qr_code_markup
|
||||
RQRCode::QRCode.new(
|
||||
'otpauth://totp/cb6e6126.ngrok.io:local-part%40domain?secret=thisisasecretforthespecofnewview&issuer=cb6e6126.ngrok.io'
|
||||
).as_svg(padding: 0, module_size: 4)
|
||||
).as_svg(padding: 0, module_size: 4, use_path: true)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
Fabricator(:account_domain_block) do
|
||||
account { Fabricate.build(:account) }
|
||||
domain 'example.com'
|
||||
domain { sequence { |n| "host-#{n}.example" } }
|
||||
end
|
||||
|
|
|
@ -74,6 +74,24 @@ RSpec.describe ActivityPub::Activity::Create do
|
|||
}
|
||||
end
|
||||
|
||||
let(:invalid_mention_json) do
|
||||
{
|
||||
id: [ActivityPub::TagManager.instance.uri_for(sender), 'post2'].join('/'),
|
||||
type: 'Note',
|
||||
to: [
|
||||
'https://www.w3.org/ns/activitystreams#Public',
|
||||
ActivityPub::TagManager.instance.uri_for(follower),
|
||||
],
|
||||
content: '@bob lorem ipsum',
|
||||
published: 1.hour.ago.utc.iso8601,
|
||||
updated: 1.hour.ago.utc.iso8601,
|
||||
tag: {
|
||||
type: 'Mention',
|
||||
href: 'http://notexisting.dontexistingtld/actor',
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
def activity_for_object(json)
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
|
@ -128,6 +146,25 @@ RSpec.describe ActivityPub::Activity::Create do
|
|||
# Creates two notifications
|
||||
expect(Notification.count).to eq 2
|
||||
end
|
||||
|
||||
it 'ignores unprocessable mention', :aggregate_failures do
|
||||
stub_request(:get, invalid_mention_json[:tag][:href]).to_raise(HTTP::ConnectionError)
|
||||
# When receiving the post that contains an invalid mention…
|
||||
described_class.new(activity_for_object(invalid_mention_json), sender, delivery: true).perform
|
||||
|
||||
# NOTE: Refering explicitly to the workers is a bit awkward
|
||||
DistributionWorker.drain
|
||||
FeedInsertWorker.drain
|
||||
|
||||
# …it creates a status
|
||||
status = Status.find_by(uri: invalid_mention_json[:id])
|
||||
|
||||
# Check the process did not crash
|
||||
expect(status.nil?).to be false
|
||||
|
||||
# It has queued a mention resolve job
|
||||
expect(MentionResolveWorker).to have_enqueued_sidekiq_job(status.id, invalid_mention_json[:tag][:href], anything)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
|
|
|
@ -14,6 +14,17 @@ RSpec.describe NotificationMailer do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'delivery without status' do
|
||||
context 'when notification target_status is missing' do
|
||||
before { allow(notification).to receive(:target_status).and_return(nil) }
|
||||
|
||||
it 'does not deliver mail' do
|
||||
emails = capture_emails { mail.deliver_now }
|
||||
expect(emails).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:receiver) { Fabricate(:user, account_attributes: { username: 'alice' }) }
|
||||
let(:sender) { Fabricate(:account, username: 'bob') }
|
||||
let(:foreign_status) { Fabricate(:status, account: sender, text: 'The body of the foreign status') }
|
||||
|
@ -37,6 +48,7 @@ RSpec.describe NotificationMailer do
|
|||
end
|
||||
|
||||
include_examples 'delivery to non functional user'
|
||||
include_examples 'delivery without status'
|
||||
end
|
||||
|
||||
describe 'follow' do
|
||||
|
@ -75,6 +87,7 @@ RSpec.describe NotificationMailer do
|
|||
end
|
||||
|
||||
include_examples 'delivery to non functional user'
|
||||
include_examples 'delivery without status'
|
||||
end
|
||||
|
||||
describe 'reblog' do
|
||||
|
@ -95,6 +108,7 @@ RSpec.describe NotificationMailer do
|
|||
end
|
||||
|
||||
include_examples 'delivery to non functional user'
|
||||
include_examples 'delivery without status'
|
||||
end
|
||||
|
||||
describe 'follow_request' do
|
||||
|
|
|
@ -3,66 +3,104 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Export do
|
||||
subject { described_class.new(account) }
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:target_accounts) do
|
||||
[{}, { username: 'one', domain: 'local.host' }].map(&method(:Fabricate).curry(2).call(:account))
|
||||
[
|
||||
Fabricate(:account),
|
||||
Fabricate(:account, username: 'one', domain: 'local.host'),
|
||||
]
|
||||
end
|
||||
|
||||
describe 'to_csv' do
|
||||
it 'returns a csv of the blocked accounts' do
|
||||
target_accounts.each { |target_account| account.block!(target_account) }
|
||||
describe '#to_bookmarks_csv' do
|
||||
before { Fabricate.times(2, :bookmark, account: account) }
|
||||
|
||||
export = described_class.new(account).to_blocked_accounts_csv
|
||||
results = export.strip.split
|
||||
let(:export) { CSV.parse(subject.to_bookmarks_csv) }
|
||||
|
||||
expect(results.size).to eq 2
|
||||
expect(results.first).to eq 'one@local.host'
|
||||
it 'returns a csv of bookmarks' do
|
||||
expect(export)
|
||||
.to contain_exactly(
|
||||
include(/statuses/),
|
||||
include(/statuses/)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_blocked_accounts_csv' do
|
||||
before { target_accounts.each { |target_account| account.block!(target_account) } }
|
||||
|
||||
let(:export) { CSV.parse(subject.to_blocked_accounts_csv) }
|
||||
|
||||
it 'returns a csv of the blocked accounts' do
|
||||
expect(export)
|
||||
.to contain_exactly(
|
||||
include('one@local.host'),
|
||||
include(be_present)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_muted_accounts_csv' do
|
||||
before { target_accounts.each { |target_account| account.mute!(target_account) } }
|
||||
|
||||
let(:export) { CSV.parse(subject.to_muted_accounts_csv) }
|
||||
|
||||
it 'returns a csv of the muted accounts' do
|
||||
target_accounts.each { |target_account| account.mute!(target_account) }
|
||||
|
||||
export = described_class.new(account).to_muted_accounts_csv
|
||||
results = export.strip.split("\n")
|
||||
|
||||
expect(results.size).to eq 3
|
||||
expect(results.first).to eq 'Account address,Hide notifications'
|
||||
expect(results.second).to eq 'one@local.host,true'
|
||||
expect(export)
|
||||
.to contain_exactly(
|
||||
contain_exactly('Account address', 'Hide notifications'),
|
||||
include('one@local.host', 'true'),
|
||||
include(be_present)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_following_accounts_csv' do
|
||||
before { target_accounts.each { |target_account| account.follow!(target_account) } }
|
||||
|
||||
let(:export) { CSV.parse(subject.to_following_accounts_csv) }
|
||||
|
||||
it 'returns a csv of the following accounts' do
|
||||
target_accounts.each { |target_account| account.follow!(target_account) }
|
||||
|
||||
export = described_class.new(account).to_following_accounts_csv
|
||||
results = export.strip.split("\n")
|
||||
|
||||
expect(results.size).to eq 3
|
||||
expect(results.first).to eq 'Account address,Show boosts,Notify on new posts,Languages'
|
||||
expect(results.second).to eq 'one@local.host,true,false,'
|
||||
expect(export)
|
||||
.to contain_exactly(
|
||||
contain_exactly('Account address', 'Show boosts', 'Notify on new posts', 'Languages'),
|
||||
include('one@local.host', 'true', 'false', be_blank),
|
||||
include(be_present)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'total_storage' do
|
||||
it 'returns the total size of the media attachments' do
|
||||
media_attachment = Fabricate(:media_attachment, account: account)
|
||||
expect(described_class.new(account).total_storage).to eq media_attachment.file_file_size || 0
|
||||
describe '#to_lists_csv' do
|
||||
before do
|
||||
target_accounts.each do |target_account|
|
||||
account.follow!(target_account)
|
||||
Fabricate(:list, account: account).accounts << target_account
|
||||
end
|
||||
end
|
||||
|
||||
let(:export) { CSV.parse(subject.to_lists_csv) }
|
||||
|
||||
it 'returns a csv of the lists' do
|
||||
expect(export)
|
||||
.to contain_exactly(
|
||||
include('one@local.host'),
|
||||
include(be_present)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'total_follows' do
|
||||
it 'returns the total number of the followed accounts' do
|
||||
target_accounts.each { |target_account| account.follow!(target_account) }
|
||||
expect(described_class.new(account.reload).total_follows).to eq 2
|
||||
end
|
||||
describe '#to_blocked_domains_csv' do
|
||||
before { Fabricate.times(2, :account_domain_block, account: account) }
|
||||
|
||||
it 'returns the total number of the blocked accounts' do
|
||||
target_accounts.each { |target_account| account.block!(target_account) }
|
||||
expect(described_class.new(account.reload).total_blocks).to eq 2
|
||||
end
|
||||
let(:export) { CSV.parse(subject.to_blocked_domains_csv) }
|
||||
|
||||
it 'returns the total number of the muted accounts' do
|
||||
target_accounts.each { |target_account| account.mute!(target_account) }
|
||||
expect(described_class.new(account.reload).total_mutes).to eq 2
|
||||
it 'returns a csv of the blocked domains' do
|
||||
expect(export)
|
||||
.to contain_exactly(
|
||||
include(/example/),
|
||||
include(/example/)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,4 +30,17 @@ RSpec.describe ReportFilter do
|
|||
expect(Report).to have_received(:resolved)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when given remote target_origin and also by_target_domain' do
|
||||
let!(:matching_report) { Fabricate :report, target_account: Fabricate(:account, domain: 'match.example') }
|
||||
let!(:non_matching_report) { Fabricate :report, target_account: Fabricate(:account, domain: 'other.example') }
|
||||
|
||||
it 'preserves the domain value' do
|
||||
filter = described_class.new(by_target_domain: 'match.example', target_origin: 'remote')
|
||||
|
||||
expect(filter.results)
|
||||
.to include(matching_report)
|
||||
.and not_include(non_matching_report)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
86
spec/presenters/export_summary_spec.rb
Normal file
86
spec/presenters/export_summary_spec.rb
Normal file
|
@ -0,0 +1,86 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ExportSummary do
|
||||
subject { described_class.new(account) }
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:target_accounts) do
|
||||
[
|
||||
Fabricate(:account),
|
||||
Fabricate(:account, username: 'one', domain: 'local.host'),
|
||||
]
|
||||
end
|
||||
|
||||
describe '#total_storage' do
|
||||
it 'returns the total size of the media attachments' do
|
||||
media_attachment = Fabricate(:media_attachment, account: account)
|
||||
expect(subject.total_storage).to eq media_attachment.file_file_size || 0
|
||||
end
|
||||
end
|
||||
|
||||
describe '#total_statuses' do
|
||||
before { Fabricate.times(2, :status, account: account) }
|
||||
|
||||
it 'returns the total number of statuses' do
|
||||
expect(subject.total_statuses).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#total_bookmarks' do
|
||||
before { Fabricate.times(2, :bookmark, account: account) }
|
||||
|
||||
it 'returns the total number of bookmarks' do
|
||||
expect(subject.total_bookmarks).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#total_follows' do
|
||||
before { target_accounts.each { |target_account| account.follow!(target_account) } }
|
||||
|
||||
it 'returns the total number of the followed accounts' do
|
||||
expect(subject.total_follows).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#total_lists' do
|
||||
before { Fabricate.times(2, :list, account: account) }
|
||||
|
||||
it 'returns the total number of lists' do
|
||||
expect(subject.total_lists).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#total_followers' do
|
||||
before { target_accounts.each { |target_account| target_account.follow!(account) } }
|
||||
|
||||
it 'returns the total number of the follower accounts' do
|
||||
expect(subject.total_followers).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#total_blocks' do
|
||||
before { target_accounts.each { |target_account| account.block!(target_account) } }
|
||||
|
||||
it 'returns the total number of the blocked accounts' do
|
||||
expect(subject.total_blocks).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#total_mutes' do
|
||||
before { target_accounts.each { |target_account| account.mute!(target_account) } }
|
||||
|
||||
it 'returns the total number of the muted accounts' do
|
||||
expect(subject.total_mutes).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#total_domain_blocks' do
|
||||
before { Fabricate.times(2, :account_domain_block, account: account) }
|
||||
|
||||
it 'returns the total number of account domain blocks' do
|
||||
expect(subject.total_domain_blocks).to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -161,6 +161,11 @@ RSpec.configure do |config|
|
|||
host! Rails.configuration.x.local_domain
|
||||
end
|
||||
|
||||
config.before :each, type: :system do
|
||||
# Align with capybara config so that rails helpers called from rspec use matching host
|
||||
host! 'localhost:3000'
|
||||
end
|
||||
|
||||
config.after do
|
||||
Rails.cache.clear
|
||||
redis.del(redis.keys)
|
||||
|
|
|
@ -6,7 +6,7 @@ require 'webauthn/fake_client'
|
|||
RSpec.describe 'Security Key Options' do
|
||||
describe 'GET /auth/sessions/security_key_options' do
|
||||
let!(:user) do
|
||||
Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))
|
||||
Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret)
|
||||
end
|
||||
|
||||
context 'with WebAuthn and OTP enabled as second factor' do
|
||||
|
|
|
@ -3,25 +3,62 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'The /.well-known/host-meta request' do
|
||||
it 'returns http success with valid XML response' do
|
||||
get '/.well-known/host-meta'
|
||||
context 'without extension format or accept header' do
|
||||
it 'returns http success with expected XML' do
|
||||
get '/.well-known/host-meta'
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
.and have_attributes(
|
||||
media_type: 'application/xrd+xml',
|
||||
body: host_meta_xml_template
|
||||
)
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
.and have_attributes(
|
||||
media_type: 'application/xrd+xml'
|
||||
)
|
||||
|
||||
expect(xrd_link_template_value)
|
||||
.to eq 'https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}'
|
||||
end
|
||||
|
||||
def xrd_link_template_value
|
||||
response
|
||||
.parsed_body
|
||||
.at_xpath('/xrd:XRD/xrd:Link[@rel="lrdd"]/@template', 'xrd' => 'http://docs.oasis-open.org/ns/xri/xrd-1.0')
|
||||
.value
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
context 'with a .json format extension' do
|
||||
it 'returns http success with expected JSON' do
|
||||
get '/.well-known/host-meta.json'
|
||||
|
||||
def host_meta_xml_template
|
||||
<<~XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
|
||||
<Link rel="lrdd" template="https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}"/>
|
||||
</XRD>
|
||||
XML
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
.and have_attributes(
|
||||
media_type: 'application/json'
|
||||
)
|
||||
expect(response.parsed_body)
|
||||
.to include(expected_json_template)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a JSON `Accept` header' do
|
||||
it 'returns http success with expected JSON' do
|
||||
get '/.well-known/host-meta', headers: { 'Accept' => 'application/json' }
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
.and have_attributes(
|
||||
media_type: 'application/json'
|
||||
)
|
||||
expect(response.parsed_body)
|
||||
.to include(expected_json_template)
|
||||
end
|
||||
end
|
||||
|
||||
def expected_json_template
|
||||
{
|
||||
links: [
|
||||
'rel' => 'lrdd',
|
||||
'template' => 'https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}',
|
||||
],
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,9 +4,14 @@ require 'rails_helper'
|
|||
|
||||
RSpec.describe 'Well Known routes' do
|
||||
describe 'the host-meta route' do
|
||||
it 'routes to correct place with xml format' do
|
||||
it 'routes to correct place' do
|
||||
expect(get('/.well-known/host-meta'))
|
||||
.to route_to('well_known/host_meta#show', format: 'xml')
|
||||
.to route_to('well_known/host_meta#show')
|
||||
end
|
||||
|
||||
it 'routes to correct place with json format' do
|
||||
expect(get('/.well-known/host-meta.json'))
|
||||
.to route_to('well_known/host_meta#show', format: 'json')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -27,39 +27,35 @@ RSpec.describe AccountStatusesCleanupService do
|
|||
end
|
||||
|
||||
context 'when given a normal budget of 10' do
|
||||
it 'reports 3 deleted statuses' do
|
||||
expect(subject.call(account_policy, 10)).to eq 3
|
||||
end
|
||||
it 'reports 3 deleted statuses and records last deleted id, deletes statuses, preserves recent unrelated statuses' do
|
||||
expect(subject.call(account_policy, 10))
|
||||
.to eq(3)
|
||||
|
||||
it 'records the last deleted id' do
|
||||
subject.call(account_policy, 10)
|
||||
expect(account_policy.last_inspected).to eq [old_status.id, another_old_status.id].max
|
||||
end
|
||||
expect(account_policy.last_inspected)
|
||||
.to eq [old_status.id, another_old_status.id].max
|
||||
|
||||
it 'actually deletes the statuses' do
|
||||
subject.call(account_policy, 10)
|
||||
expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).to be_nil
|
||||
expect { recent_status.reload }.to_not raise_error
|
||||
end
|
||||
|
||||
it 'preserves recent and unrelated statuses' do
|
||||
subject.call(account_policy, 10)
|
||||
expect { unrelated_status.reload }.to_not raise_error
|
||||
expect { recent_status.reload }.to_not raise_error
|
||||
expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id]))
|
||||
.to be_nil
|
||||
expect { recent_status.reload }
|
||||
.to_not raise_error
|
||||
expect { unrelated_status.reload }
|
||||
.to_not raise_error
|
||||
expect { recent_status.reload }
|
||||
.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when called repeatedly with a budget of 2' do
|
||||
it 'reports 2 then 1 deleted statuses' do
|
||||
expect(subject.call(account_policy, 2)).to eq 2
|
||||
expect(subject.call(account_policy, 2)).to eq 1
|
||||
end
|
||||
it 'reports 2 then 1 deleted statuses and deletes in expected order' do
|
||||
expect(subject.call(account_policy, 2))
|
||||
.to eq(2)
|
||||
expect(Status.find_by(id: very_old_status.id))
|
||||
.to be_nil
|
||||
|
||||
it 'actually deletes the statuses in the expected order' do
|
||||
subject.call(account_policy, 2)
|
||||
expect(Status.find_by(id: very_old_status.id)).to be_nil
|
||||
subject.call(account_policy, 2)
|
||||
expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).to be_nil
|
||||
expect(subject.call(account_policy, 2))
|
||||
.to eq(1)
|
||||
expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id]))
|
||||
.to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -90,19 +86,24 @@ RSpec.describe AccountStatusesCleanupService do
|
|||
end
|
||||
end
|
||||
|
||||
it 'reports 0 deleted statuses then 0 then 3 then 0 again' do
|
||||
expect(subject.call(account_policy, 10)).to eq 0
|
||||
expect(subject.call(account_policy, 10)).to eq 0
|
||||
expect(subject.call(account_policy, 10)).to eq 3
|
||||
expect(subject.call(account_policy, 10)).to eq 0
|
||||
it 'reports 0 deleted statuses then 0 then 3 then 0 again, and keeps id under oldest deletable record' do
|
||||
expect(subject.call(account_policy, 10))
|
||||
.to eq(0)
|
||||
expect(subject.call(account_policy, 10))
|
||||
.to eq(0)
|
||||
expect(subject.call(account_policy, 10))
|
||||
.to eq(3)
|
||||
expect(subject.call(account_policy, 10))
|
||||
.to eq(0)
|
||||
expect(account_policy.last_inspected)
|
||||
.to be < oldest_deletable_record_id
|
||||
end
|
||||
|
||||
it 'never causes the recorded id to get higher than oldest deletable toot' do
|
||||
subject.call(account_policy, 10)
|
||||
subject.call(account_policy, 10)
|
||||
subject.call(account_policy, 10)
|
||||
subject.call(account_policy, 10)
|
||||
expect(account_policy.last_inspected).to be < Mastodon::Snowflake.id_at(account_policy.min_status_age.seconds.ago, with_random: false)
|
||||
def oldest_deletable_record_id
|
||||
Mastodon::Snowflake.id_at(
|
||||
account_policy.min_status_age.seconds.ago,
|
||||
with_random: false
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
def poll_option_json(name, votes)
|
||||
{ type: 'Note', name: name, replies: { type: 'Collection', totalItems: votes } }
|
||||
end
|
||||
|
||||
RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
||||
subject { described_class.new }
|
||||
|
||||
|
@ -338,7 +334,6 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
|||
context 'when originally without media attachments' do
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/foo.png').to_return(body: attachment_fixture('emojo.png'))
|
||||
subject.call(status, json, json)
|
||||
end
|
||||
|
||||
let(:payload) do
|
||||
|
@ -354,19 +349,18 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
|||
}
|
||||
end
|
||||
|
||||
it 'updates media attachments' do
|
||||
media_attachment = status.reload.ordered_media_attachments.first
|
||||
it 'updates media attachments, fetches attachment, records media change in edit' do
|
||||
subject.call(status, json, json)
|
||||
|
||||
expect(media_attachment).to_not be_nil
|
||||
expect(media_attachment.remote_url).to eq 'https://example.com/foo.png'
|
||||
end
|
||||
expect(status.reload.ordered_media_attachments.first)
|
||||
.to be_present
|
||||
.and(have_attributes(remote_url: 'https://example.com/foo.png'))
|
||||
|
||||
it 'fetches the attachment' do
|
||||
expect(a_request(:get, 'https://example.com/foo.png')).to have_been_made
|
||||
end
|
||||
expect(a_request(:get, 'https://example.com/foo.png'))
|
||||
.to have_been_made
|
||||
|
||||
it 'records media change in edit' do
|
||||
expect(status.edits.reload.last.ordered_media_attachment_ids).to_not be_empty
|
||||
expect(status.edits.reload.last.ordered_media_attachment_ids)
|
||||
.to_not be_empty
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -388,27 +382,26 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
|||
|
||||
before do
|
||||
allow(RedownloadMediaWorker).to receive(:perform_async)
|
||||
end
|
||||
|
||||
it 'updates the existing media attachment in-place, does not queue redownload, updates media, records media change' do
|
||||
subject.call(status, json, json)
|
||||
end
|
||||
|
||||
it 'updates the existing media attachment in-place' do
|
||||
media_attachment = status.media_attachments.ordered.reload.first
|
||||
expect(status.media_attachments.ordered.reload.first)
|
||||
.to be_present
|
||||
.and have_attributes(
|
||||
remote_url: 'https://example.com/foo.png',
|
||||
description: 'A picture'
|
||||
)
|
||||
|
||||
expect(media_attachment).to_not be_nil
|
||||
expect(media_attachment.remote_url).to eq 'https://example.com/foo.png'
|
||||
expect(media_attachment.description).to eq 'A picture'
|
||||
end
|
||||
expect(RedownloadMediaWorker)
|
||||
.to_not have_received(:perform_async)
|
||||
|
||||
it 'does not queue redownload for the existing media attachment' do
|
||||
expect(RedownloadMediaWorker).to_not have_received(:perform_async)
|
||||
end
|
||||
expect(status.ordered_media_attachments.map(&:remote_url))
|
||||
.to eq %w(https://example.com/foo.png)
|
||||
|
||||
it 'updates media attachments' do
|
||||
expect(status.ordered_media_attachments.map(&:remote_url)).to eq %w(https://example.com/foo.png)
|
||||
end
|
||||
|
||||
it 'records media change in edit' do
|
||||
expect(status.edits.reload.last.ordered_media_attachment_ids).to_not be_empty
|
||||
expect(status.edits.reload.last.ordered_media_attachment_ids)
|
||||
.to_not be_empty
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -416,10 +409,11 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
|||
before do
|
||||
poll = Fabricate(:poll, status: status)
|
||||
status.update(preloadable_poll: poll)
|
||||
subject.call(status, json, json)
|
||||
end
|
||||
|
||||
it 'removes poll and records media change in edit' do
|
||||
subject.call(status, json, json)
|
||||
|
||||
expect(status.reload.poll).to be_nil
|
||||
expect(status.edits.reload.last.poll_options).to be_nil
|
||||
end
|
||||
|
@ -442,15 +436,13 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
|||
}
|
||||
end
|
||||
|
||||
before do
|
||||
subject.call(status, json, json)
|
||||
end
|
||||
|
||||
it 'creates a poll and records media change in edit' do
|
||||
poll = status.reload.poll
|
||||
subject.call(status, json, json)
|
||||
|
||||
expect(status.reload.poll)
|
||||
.to be_present
|
||||
.and have_attributes(options: %w(Foo Bar Baz))
|
||||
|
||||
expect(poll).to_not be_nil
|
||||
expect(poll.options).to eq %w(Foo Bar Baz)
|
||||
expect(status.edits.reload.last.poll_options).to eq %w(Foo Bar Baz)
|
||||
end
|
||||
end
|
||||
|
@ -738,4 +730,8 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def poll_option_json(name, votes)
|
||||
{ type: 'Note', name: name, replies: { type: 'Collection', totalItems: votes } }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,15 +12,15 @@ RSpec.describe AuthorizeFollowService do
|
|||
|
||||
before do
|
||||
FollowRequest.create(account: bob, target_account: sender)
|
||||
end
|
||||
|
||||
it 'removes follow request and creates follow relation' do
|
||||
subject.call(bob, sender)
|
||||
end
|
||||
|
||||
it 'removes follow request' do
|
||||
expect(bob.requested?(sender)).to be false
|
||||
end
|
||||
|
||||
it 'creates follow relation' do
|
||||
expect(bob.following?(sender)).to be true
|
||||
expect(bob)
|
||||
.to_not be_requested(sender)
|
||||
expect(bob)
|
||||
.to be_following(sender)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -30,19 +30,17 @@ RSpec.describe AuthorizeFollowService do
|
|||
before do
|
||||
FollowRequest.create(account: bob, target_account: sender)
|
||||
stub_request(:post, bob.inbox_url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'removes follow request, creates follow relation, send accept activity', :inline_jobs do
|
||||
subject.call(bob, sender)
|
||||
end
|
||||
|
||||
it 'removes follow request' do
|
||||
expect(bob.requested?(sender)).to be false
|
||||
end
|
||||
|
||||
it 'creates follow relation' do
|
||||
expect(bob.following?(sender)).to be true
|
||||
end
|
||||
|
||||
it 'sends an accept activity', :inline_jobs do
|
||||
expect(a_request(:post, bob.inbox_url)).to have_been_made.once
|
||||
expect(bob)
|
||||
.to_not be_requested(sender)
|
||||
expect(bob)
|
||||
.to be_following(sender)
|
||||
expect(a_request(:post, bob.inbox_url))
|
||||
.to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,32 +24,38 @@ RSpec.describe BatchedRemoveStatusService, :inline_jobs do
|
|||
|
||||
status_alice_hello
|
||||
status_alice_other
|
||||
end
|
||||
|
||||
it 'removes status records, removes from author and local follower feeds, notifies stream, sends delete' do
|
||||
subject.call([status_alice_hello, status_alice_other])
|
||||
|
||||
expect { Status.find(status_alice_hello.id) }
|
||||
.to raise_error ActiveRecord::RecordNotFound
|
||||
expect { Status.find(status_alice_other.id) }
|
||||
.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(feed_ids_for(alice))
|
||||
.to_not include(status_alice_hello.id, status_alice_other.id)
|
||||
|
||||
expect(feed_ids_for(jeff))
|
||||
.to_not include(status_alice_hello.id, status_alice_other.id)
|
||||
|
||||
expect(redis)
|
||||
.to have_received(:publish)
|
||||
.with("timeline:#{jeff.id}", any_args).at_least(:once)
|
||||
|
||||
expect(redis)
|
||||
.to have_received(:publish)
|
||||
.with('timeline:public', any_args).at_least(:once)
|
||||
|
||||
expect(a_request(:post, 'http://example.com/inbox'))
|
||||
.to have_been_made.at_least_once
|
||||
end
|
||||
|
||||
it 'removes statuses' do
|
||||
expect { Status.find(status_alice_hello.id) }.to raise_error ActiveRecord::RecordNotFound
|
||||
expect { Status.find(status_alice_other.id) }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
|
||||
it 'removes statuses from author\'s home feed' do
|
||||
expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id)
|
||||
end
|
||||
|
||||
it 'removes statuses from local follower\'s home feed' do
|
||||
expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id)
|
||||
end
|
||||
|
||||
it 'notifies streaming API of followers' do
|
||||
expect(redis).to have_received(:publish).with("timeline:#{jeff.id}", any_args).at_least(:once)
|
||||
end
|
||||
|
||||
it 'notifies streaming API of public timeline' do
|
||||
expect(redis).to have_received(:publish).with('timeline:public', any_args).at_least(:once)
|
||||
end
|
||||
|
||||
it 'sends delete activity to followers' do
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.at_least_once
|
||||
def feed_ids_for(account)
|
||||
HomeFeed
|
||||
.new(account)
|
||||
.get(10)
|
||||
.pluck(:id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,15 +26,16 @@ RSpec.describe BlockService do
|
|||
|
||||
before do
|
||||
stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'creates a blocking relation and send block activity', :inline_jobs do
|
||||
subject.call(sender, bob)
|
||||
end
|
||||
|
||||
it 'creates a blocking relation' do
|
||||
expect(sender.blocking?(bob)).to be true
|
||||
end
|
||||
expect(sender)
|
||||
.to be_blocking(bob)
|
||||
|
||||
it 'sends a block activity', :inline_jobs do
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
|
||||
expect(a_request(:post, 'http://example.com/inbox'))
|
||||
.to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,30 +24,19 @@ RSpec.describe BulkImportService do
|
|||
].map { |data| import.rows.create!(data: data) }
|
||||
end
|
||||
|
||||
before do
|
||||
account.follow!(Fabricate(:account))
|
||||
end
|
||||
before { account.follow!(Fabricate(:account)) }
|
||||
|
||||
it 'does not immediately change who the account follows' do
|
||||
expect { subject.call(import) }.to_not(change { account.reload.active_relationships.to_a })
|
||||
end
|
||||
it 'does not immediately change who the account follows, enqueues workers, sends follow requests after worker run' do
|
||||
expect { subject.call(import) }
|
||||
.to_not(change { account.reload.active_relationships.to_a })
|
||||
|
||||
it 'enqueues workers for the expected rows' do
|
||||
subject.call(import)
|
||||
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id))
|
||||
end
|
||||
expect(row_worker_job_args)
|
||||
.to match_array(rows.map(&:id))
|
||||
|
||||
it 'requests to follow all the listed users once the workers have run' do
|
||||
subject.call(import)
|
||||
stub_resolve_account_and_drain_workers
|
||||
|
||||
resolve_account_service_double = instance_double(ResolveAccountService)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double)
|
||||
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
|
||||
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
|
||||
|
||||
Import::RowWorker.drain
|
||||
|
||||
expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }).to contain_exactly('user@foo.bar', 'unknown@unknown.bar')
|
||||
expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct })
|
||||
.to contain_exactly('user@foo.bar', 'unknown@unknown.bar')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -71,31 +60,20 @@ RSpec.describe BulkImportService do
|
|||
account.follow!(to_be_unfollowed)
|
||||
end
|
||||
|
||||
it 'unfollows user not present on list' do
|
||||
subject.call(import)
|
||||
expect(account.following?(to_be_unfollowed)).to be false
|
||||
end
|
||||
it 'updates the existing follow relationship as expected and unfollows user not on list, enqueues workers, sends follow reqs after worker run' do
|
||||
expect { subject.call(import) }
|
||||
.to change { Follow.where(account: account, target_account: followed).pick(:show_reblogs, :notify, :languages) }.from([true, false, nil]).to([false, true, ['en']])
|
||||
|
||||
it 'updates the existing follow relationship as expected' do
|
||||
expect { subject.call(import) }.to change { Follow.where(account: account, target_account: followed).pick(:show_reblogs, :notify, :languages) }.from([true, false, nil]).to([false, true, ['en']])
|
||||
end
|
||||
expect(account)
|
||||
.to_not be_following(to_be_unfollowed)
|
||||
|
||||
it 'enqueues workers for the expected rows' do
|
||||
subject.call(import)
|
||||
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id))
|
||||
end
|
||||
expect(row_worker_job_args)
|
||||
.to match_array(rows[1..].map(&:id))
|
||||
|
||||
it 'requests to follow all the expected users once the workers have run' do
|
||||
subject.call(import)
|
||||
stub_resolve_account_and_drain_workers
|
||||
|
||||
resolve_account_service_double = instance_double(ResolveAccountService)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double)
|
||||
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
|
||||
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
|
||||
|
||||
Import::RowWorker.drain
|
||||
|
||||
expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }).to contain_exactly('user@foo.bar', 'unknown@unknown.bar')
|
||||
expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct })
|
||||
.to contain_exactly('user@foo.bar', 'unknown@unknown.bar')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -110,30 +88,19 @@ RSpec.describe BulkImportService do
|
|||
].map { |data| import.rows.create!(data: data) }
|
||||
end
|
||||
|
||||
before do
|
||||
account.block!(Fabricate(:account, username: 'already_blocked', domain: 'remote.org'))
|
||||
end
|
||||
before { account.block!(Fabricate(:account, username: 'already_blocked', domain: 'remote.org')) }
|
||||
|
||||
it 'does not immediately change who the account blocks' do
|
||||
expect { subject.call(import) }.to_not(change { account.reload.blocking.to_a })
|
||||
end
|
||||
it 'does not immediately change who the account blocks, enqueues worker, blocks after run' do
|
||||
expect { subject.call(import) }
|
||||
.to_not(change { account.reload.blocking.to_a })
|
||||
|
||||
it 'enqueues workers for the expected rows' do
|
||||
subject.call(import)
|
||||
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id))
|
||||
end
|
||||
expect(row_worker_job_args)
|
||||
.to match_array(rows.map(&:id))
|
||||
|
||||
it 'blocks all the listed users once the workers have run' do
|
||||
subject.call(import)
|
||||
stub_resolve_account_and_drain_workers
|
||||
|
||||
resolve_account_service_double = instance_double(ResolveAccountService)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double)
|
||||
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
|
||||
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
|
||||
|
||||
Import::RowWorker.drain
|
||||
|
||||
expect(account.blocking.map(&:acct)).to contain_exactly('already_blocked@remote.org', 'user@foo.bar', 'unknown@unknown.bar')
|
||||
expect(account.reload.blocking.map(&:acct))
|
||||
.to contain_exactly('already_blocked@remote.org', 'user@foo.bar', 'unknown@unknown.bar')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -157,27 +124,18 @@ RSpec.describe BulkImportService do
|
|||
account.block!(to_be_unblocked)
|
||||
end
|
||||
|
||||
it 'unblocks user not present on list' do
|
||||
it 'unblocks user not present on list, enqueues worker, requests follow after run' do
|
||||
subject.call(import)
|
||||
|
||||
expect(account.blocking?(to_be_unblocked)).to be false
|
||||
end
|
||||
|
||||
it 'enqueues workers for the expected rows' do
|
||||
subject.call(import)
|
||||
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id))
|
||||
end
|
||||
expect(row_worker_job_args)
|
||||
.to match_array(rows[1..].map(&:id))
|
||||
|
||||
it 'requests to follow all the expected users once the workers have run' do
|
||||
subject.call(import)
|
||||
stub_resolve_account_and_drain_workers
|
||||
|
||||
resolve_account_service_double = instance_double(ResolveAccountService)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double)
|
||||
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
|
||||
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
|
||||
|
||||
Import::RowWorker.drain
|
||||
|
||||
expect(account.blocking.map(&:acct)).to contain_exactly('blocked@foo.bar', 'user@foo.bar', 'unknown@unknown.bar')
|
||||
expect(account.blocking.map(&:acct))
|
||||
.to contain_exactly('blocked@foo.bar', 'user@foo.bar', 'unknown@unknown.bar')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -192,30 +150,19 @@ RSpec.describe BulkImportService do
|
|||
].map { |data| import.rows.create!(data: data) }
|
||||
end
|
||||
|
||||
before do
|
||||
account.mute!(Fabricate(:account, username: 'already_muted', domain: 'remote.org'))
|
||||
end
|
||||
before { account.mute!(Fabricate(:account, username: 'already_muted', domain: 'remote.org')) }
|
||||
|
||||
it 'does not immediately change who the account blocks' do
|
||||
expect { subject.call(import) }.to_not(change { account.reload.muting.to_a })
|
||||
end
|
||||
it 'does not immediately change who the account blocks, enqueures worker, mutes users after worker run' do
|
||||
expect { subject.call(import) }
|
||||
.to_not(change { account.reload.muting.to_a })
|
||||
|
||||
it 'enqueues workers for the expected rows' do
|
||||
subject.call(import)
|
||||
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id))
|
||||
end
|
||||
expect(row_worker_job_args)
|
||||
.to match_array(rows.map(&:id))
|
||||
|
||||
it 'mutes all the listed users once the workers have run' do
|
||||
subject.call(import)
|
||||
stub_resolve_account_and_drain_workers
|
||||
|
||||
resolve_account_service_double = instance_double(ResolveAccountService)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double)
|
||||
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
|
||||
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
|
||||
|
||||
Import::RowWorker.drain
|
||||
|
||||
expect(account.muting.map(&:acct)).to contain_exactly('already_muted@remote.org', 'user@foo.bar', 'unknown@unknown.bar')
|
||||
expect(account.reload.muting.map(&:acct))
|
||||
.to contain_exactly('already_muted@remote.org', 'user@foo.bar', 'unknown@unknown.bar')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -239,31 +186,19 @@ RSpec.describe BulkImportService do
|
|||
account.mute!(to_be_unmuted)
|
||||
end
|
||||
|
||||
it 'updates the existing mute as expected' do
|
||||
expect { subject.call(import) }.to change { Mute.where(account: account, target_account: muted).pick(:hide_notifications) }.from(false).to(true)
|
||||
end
|
||||
it 'updates the existing mute as expected and unblocks user not on list, and enqueues worker, and requests follow after worker run' do
|
||||
expect { subject.call(import) }
|
||||
.to change { Mute.where(account: account, target_account: muted).pick(:hide_notifications) }.from(false).to(true)
|
||||
|
||||
it 'unblocks user not present on list' do
|
||||
subject.call(import)
|
||||
expect(account.muting?(to_be_unmuted)).to be false
|
||||
end
|
||||
|
||||
it 'enqueues workers for the expected rows' do
|
||||
subject.call(import)
|
||||
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id))
|
||||
end
|
||||
expect(row_worker_job_args)
|
||||
.to match_array(rows[1..].map(&:id))
|
||||
|
||||
it 'requests to follow all the expected users once the workers have run' do
|
||||
subject.call(import)
|
||||
stub_resolve_account_and_drain_workers
|
||||
|
||||
resolve_account_service_double = instance_double(ResolveAccountService)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double)
|
||||
allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
|
||||
allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
|
||||
|
||||
Import::RowWorker.drain
|
||||
|
||||
expect(account.muting.map(&:acct)).to contain_exactly('muted@foo.bar', 'user@foo.bar', 'unknown@unknown.bar')
|
||||
expect(account.muting.map(&:acct))
|
||||
.to contain_exactly('muted@foo.bar', 'user@foo.bar', 'unknown@unknown.bar')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -284,13 +219,11 @@ RSpec.describe BulkImportService do
|
|||
account.block_domain!('blocked.com')
|
||||
end
|
||||
|
||||
it 'blocks all the new domains' do
|
||||
it 'blocks all the new domains and marks import finished' do
|
||||
subject.call(import)
|
||||
expect(account.domain_blocks.pluck(:domain)).to contain_exactly('alreadyblocked.com', 'blocked.com', 'to-block.com')
|
||||
end
|
||||
|
||||
it 'marks the import as finished' do
|
||||
subject.call(import)
|
||||
expect(account.domain_blocks.pluck(:domain))
|
||||
.to contain_exactly('alreadyblocked.com', 'blocked.com', 'to-block.com')
|
||||
expect(import.reload.state_finished?).to be true
|
||||
end
|
||||
end
|
||||
|
@ -312,14 +245,13 @@ RSpec.describe BulkImportService do
|
|||
account.block_domain!('blocked.com')
|
||||
end
|
||||
|
||||
it 'blocks all the new domains' do
|
||||
it 'blocks all the new domains and marks import finished' do
|
||||
subject.call(import)
|
||||
expect(account.domain_blocks.pluck(:domain)).to contain_exactly('blocked.com', 'to-block.com')
|
||||
end
|
||||
|
||||
it 'marks the import as finished' do
|
||||
subject.call(import)
|
||||
expect(import.reload.state_finished?).to be true
|
||||
expect(account.domain_blocks.pluck(:domain))
|
||||
.to contain_exactly('blocked.com', 'to-block.com')
|
||||
expect(import.reload.state_finished?)
|
||||
.to be true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -347,22 +279,16 @@ RSpec.describe BulkImportService do
|
|||
account.bookmarks.create!(status: bookmarked)
|
||||
end
|
||||
|
||||
it 'enqueues workers for the expected rows' do
|
||||
subject.call(import)
|
||||
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id))
|
||||
end
|
||||
|
||||
it 'updates the bookmarks as expected once the workers have run' do
|
||||
it 'enqueues workers for the expected rows and updates bookmarks after worker run' do
|
||||
subject.call(import)
|
||||
|
||||
service_double = instance_double(ActivityPub::FetchRemoteStatusService)
|
||||
allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double)
|
||||
allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') }
|
||||
allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) }
|
||||
expect(row_worker_job_args)
|
||||
.to match_array(rows.map(&:id))
|
||||
|
||||
Import::RowWorker.drain
|
||||
stub_fetch_remote_and_drain_workers
|
||||
|
||||
expect(account.bookmarks.map { |bookmark| bookmark.status.uri }).to contain_exactly(already_bookmarked.uri, status.uri, bookmarked.uri, 'https://domain.unknown/foo')
|
||||
expect(account.bookmarks.map { |bookmark| bookmark.status.uri })
|
||||
.to contain_exactly(already_bookmarked.uri, status.uri, bookmarked.uri, 'https://domain.unknown/foo')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -390,23 +316,48 @@ RSpec.describe BulkImportService do
|
|||
account.bookmarks.create!(status: bookmarked)
|
||||
end
|
||||
|
||||
it 'enqueues workers for the expected rows' do
|
||||
subject.call(import)
|
||||
expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id))
|
||||
end
|
||||
|
||||
it 'updates the bookmarks as expected once the workers have run' do
|
||||
it 'enqueues workers for the expected rows and updates bookmarks' do
|
||||
subject.call(import)
|
||||
|
||||
service_double = instance_double(ActivityPub::FetchRemoteStatusService)
|
||||
allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double)
|
||||
allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') }
|
||||
allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) }
|
||||
expect(row_worker_job_args)
|
||||
.to match_array(rows.map(&:id))
|
||||
|
||||
Import::RowWorker.drain
|
||||
stub_fetch_remote_and_drain_workers
|
||||
|
||||
expect(account.bookmarks.map { |bookmark| bookmark.status.uri }).to contain_exactly(status.uri, bookmarked.uri, 'https://domain.unknown/foo')
|
||||
expect(account.bookmarks.map { |bookmark| bookmark.status.uri })
|
||||
.to contain_exactly(status.uri, bookmarked.uri, 'https://domain.unknown/foo')
|
||||
end
|
||||
end
|
||||
|
||||
def row_worker_job_args
|
||||
Import::RowWorker
|
||||
.jobs
|
||||
.pluck('args')
|
||||
.flatten
|
||||
end
|
||||
|
||||
def stub_resolve_account_and_drain_workers
|
||||
resolve_account_service_double = instance_double(ResolveAccountService)
|
||||
allow(ResolveAccountService)
|
||||
.to receive(:new)
|
||||
.and_return(resolve_account_service_double)
|
||||
allow(resolve_account_service_double)
|
||||
.to receive(:call)
|
||||
.with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) }
|
||||
allow(resolve_account_service_double)
|
||||
.to receive(:call)
|
||||
.with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) }
|
||||
|
||||
Import::RowWorker.drain
|
||||
end
|
||||
|
||||
def stub_fetch_remote_and_drain_workers
|
||||
service_double = instance_double(ActivityPub::FetchRemoteStatusService)
|
||||
allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double)
|
||||
allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') }
|
||||
allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) }
|
||||
|
||||
Import::RowWorker.drain
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,11 +11,9 @@ RSpec.describe FavouriteService do
|
|||
let(:bob) { Fabricate(:account) }
|
||||
let(:status) { Fabricate(:status, account: bob) }
|
||||
|
||||
before do
|
||||
subject.call(sender, status)
|
||||
end
|
||||
|
||||
it 'creates a favourite' do
|
||||
subject.call(sender, status)
|
||||
|
||||
expect(status.favourites.first).to_not be_nil
|
||||
end
|
||||
end
|
||||
|
@ -26,15 +24,16 @@ RSpec.describe FavouriteService do
|
|||
|
||||
before do
|
||||
stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {})
|
||||
end
|
||||
|
||||
it 'creates a favourite and sends like activity', :inline_jobs do
|
||||
subject.call(sender, status)
|
||||
end
|
||||
|
||||
it 'creates a favourite' do
|
||||
expect(status.favourites.first).to_not be_nil
|
||||
end
|
||||
expect(status.favourites.first)
|
||||
.to_not be_nil
|
||||
|
||||
it 'sends a like activity', :inline_jobs do
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
|
||||
expect(a_request(:post, 'http://example.com/inbox'))
|
||||
.to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -143,15 +143,16 @@ RSpec.describe FollowService do
|
|||
|
||||
before do
|
||||
stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {})
|
||||
end
|
||||
|
||||
it 'creates follow request and sends an activity to inbox', :inline_jobs do
|
||||
subject.call(sender, bob)
|
||||
end
|
||||
|
||||
it 'creates follow request' do
|
||||
expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil
|
||||
end
|
||||
expect(FollowRequest.find_by(account: sender, target_account: bob))
|
||||
.to_not be_nil
|
||||
|
||||
it 'sends a follow activity to the inbox', :inline_jobs do
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
|
||||
expect(a_request(:post, 'http://example.com/inbox'))
|
||||
.to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -16,20 +16,25 @@ RSpec.describe ProcessMentionsService do
|
|||
before do
|
||||
account.block!(individually_blocked_account)
|
||||
account.domain_blocks.create!(domain: domain_blocked_account.domain)
|
||||
|
||||
subject.call(status)
|
||||
end
|
||||
|
||||
it 'creates a mention to the non-blocked account' do
|
||||
expect(non_blocked_account.mentions.where(status: status).count).to eq 1
|
||||
it 'creates a mention to the non-blocked account but not the individually or domain blocked accounts' do
|
||||
expect { subject.call(status) }
|
||||
.to create_mention_for_non_blocked
|
||||
.and skip_mention_for_individual
|
||||
.and skip_mention_for_domain_blocked
|
||||
end
|
||||
|
||||
it 'does not create a mention to the individually blocked account' do
|
||||
expect(individually_blocked_account.mentions.where(status: status).count).to eq 0
|
||||
def create_mention_for_non_blocked
|
||||
change { non_blocked_account.mentions.where(status: status).count }.to(1)
|
||||
end
|
||||
|
||||
it 'does not create a mention to the domain-blocked account' do
|
||||
expect(domain_blocked_account.mentions.where(status: status).count).to eq 0
|
||||
def skip_mention_for_individual
|
||||
not_change { individually_blocked_account.mentions.where(status: status).count }.from(0)
|
||||
end
|
||||
|
||||
def skip_mention_for_domain_blocked
|
||||
not_change { domain_blocked_account.mentions.where(status: status).count }.from(0)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -40,11 +45,9 @@ RSpec.describe ProcessMentionsService do
|
|||
context 'with a valid remote user' do
|
||||
let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
|
||||
|
||||
before do
|
||||
subject.call(status)
|
||||
end
|
||||
|
||||
it 'creates a mention' do
|
||||
subject.call(status)
|
||||
|
||||
expect(remote_user.mentions.where(status: status).count).to eq 1
|
||||
end
|
||||
end
|
||||
|
@ -53,11 +56,9 @@ RSpec.describe ProcessMentionsService do
|
|||
let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
|
||||
let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct} @#{remote_user.acct} @#{remote_user.acct}", visibility: :public) }
|
||||
|
||||
before do
|
||||
subject.call(status, save_records: false)
|
||||
end
|
||||
|
||||
it 'creates exactly one mention' do
|
||||
subject.call(status, save_records: false)
|
||||
|
||||
expect(status.mentions.size).to eq 1
|
||||
end
|
||||
end
|
||||
|
@ -66,11 +67,9 @@ RSpec.describe ProcessMentionsService do
|
|||
let!(:remote_user) { Fabricate(:account, username: 'sneak', protocol: :activitypub, domain: 'xn--hresiar-mxa.ch', inbox_url: 'http://example.com/inbox') }
|
||||
let!(:status) { Fabricate(:status, account: account, text: 'Hello @sneak@hæresiar.ch') }
|
||||
|
||||
before do
|
||||
subject.call(status)
|
||||
end
|
||||
|
||||
it 'creates a mention' do
|
||||
subject.call(status)
|
||||
|
||||
expect(remote_user.mentions.where(status: status).count).to eq 1
|
||||
end
|
||||
end
|
||||
|
@ -79,11 +78,9 @@ RSpec.describe ProcessMentionsService do
|
|||
let!(:remote_user) { Fabricate(:account, username: 'foo', protocol: :activitypub, domain: 'xn--y9a3aq.xn--y9a3aq', inbox_url: 'http://example.com/inbox') }
|
||||
let!(:status) { Fabricate(:status, account: account, text: 'Hello @foo@հայ.հայ') }
|
||||
|
||||
before do
|
||||
subject.call(status)
|
||||
end
|
||||
|
||||
it 'creates a mention' do
|
||||
subject.call(status)
|
||||
|
||||
expect(remote_user.mentions.where(status: status).count).to eq 1
|
||||
end
|
||||
end
|
||||
|
@ -95,10 +92,11 @@ RSpec.describe ProcessMentionsService do
|
|||
before do
|
||||
stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 404)
|
||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com').to_return(status: 500)
|
||||
subject.call(status)
|
||||
end
|
||||
|
||||
it 'creates a mention' do
|
||||
subject.call(status)
|
||||
|
||||
expect(remote_user.mentions.where(status: status).count).to eq 1
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,17 +10,15 @@ RSpec.describe RejectFollowService do
|
|||
describe 'local' do
|
||||
let(:bob) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
FollowRequest.create(account: bob, target_account: sender)
|
||||
before { FollowRequest.create(account: bob, target_account: sender) }
|
||||
|
||||
it 'removes follow request and does not create relation' do
|
||||
subject.call(bob, sender)
|
||||
end
|
||||
|
||||
it 'removes follow request' do
|
||||
expect(bob.requested?(sender)).to be false
|
||||
end
|
||||
|
||||
it 'does not create follow relation' do
|
||||
expect(bob.following?(sender)).to be false
|
||||
expect(bob)
|
||||
.to_not be_requested(sender)
|
||||
expect(bob)
|
||||
.to_not be_following(sender)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -30,19 +28,17 @@ RSpec.describe RejectFollowService do
|
|||
before do
|
||||
FollowRequest.create(account: bob, target_account: sender)
|
||||
stub_request(:post, bob.inbox_url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'removes follow request, does not create relation, sends reject activity', :inline_jobs do
|
||||
subject.call(bob, sender)
|
||||
end
|
||||
|
||||
it 'removes follow request' do
|
||||
expect(bob.requested?(sender)).to be false
|
||||
end
|
||||
|
||||
it 'does not create follow relation' do
|
||||
expect(bob.following?(sender)).to be false
|
||||
end
|
||||
|
||||
it 'sends a reject activity', :inline_jobs do
|
||||
expect(a_request(:post, bob.inbox_url)).to have_been_made.once
|
||||
expect(bob)
|
||||
.to_not be_requested(sender)
|
||||
expect(bob)
|
||||
.to_not be_following(sender)
|
||||
expect(a_request(:post, bob.inbox_url))
|
||||
.to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,13 +10,13 @@ RSpec.describe RemoveFromFollowersService do
|
|||
describe 'local' do
|
||||
let(:sender) { Fabricate(:account, username: 'alice') }
|
||||
|
||||
before do
|
||||
Follow.create(account: sender, target_account: bob)
|
||||
subject.call(bob, sender)
|
||||
end
|
||||
before { Follow.create(account: sender, target_account: bob) }
|
||||
|
||||
it 'does not create follow relation' do
|
||||
expect(bob.followed_by?(sender)).to be false
|
||||
subject.call(bob, sender)
|
||||
|
||||
expect(bob)
|
||||
.to_not be_followed_by(sender)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -26,15 +26,16 @@ RSpec.describe RemoveFromFollowersService do
|
|||
before do
|
||||
Follow.create(account: sender, target_account: bob)
|
||||
stub_request(:post, sender.inbox_url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'does not create follow relation and sends reject activity', :inline_jobs do
|
||||
subject.call(bob, sender)
|
||||
end
|
||||
|
||||
it 'does not create follow relation' do
|
||||
expect(bob.followed_by?(sender)).to be false
|
||||
end
|
||||
expect(bob)
|
||||
.to_not be_followed_by(sender)
|
||||
|
||||
it 'sends a reject activity', :inline_jobs do
|
||||
expect(a_request(:post, sender.inbox_url)).to have_been_made.once
|
||||
expect(a_request(:post, sender.inbox_url))
|
||||
.to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,42 +30,38 @@ RSpec.describe RemoveStatusService, :inline_jobs do
|
|||
Fabricate(:status, account: bill, reblog: status, uri: 'hoge')
|
||||
end
|
||||
|
||||
it 'removes status from author\'s home feed' do
|
||||
subject.call(status)
|
||||
expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(status.id)
|
||||
end
|
||||
|
||||
it 'removes status from local follower\'s home feed' do
|
||||
subject.call(status)
|
||||
expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(status.id)
|
||||
end
|
||||
|
||||
it 'publishes to public media timeline' do
|
||||
it 'removes status from notifications and from author and local follower home feeds, publishes to media timeline, sends delete activities' do
|
||||
allow(redis).to receive(:publish).with(any_args)
|
||||
|
||||
subject.call(status)
|
||||
expect { subject.call(status) }
|
||||
.to remove_status_from_notifications
|
||||
|
||||
expect(redis).to have_received(:publish).with('timeline:public:media', Oj.dump(event: :delete, payload: status.id.to_s))
|
||||
end
|
||||
expect(home_feed_ids(alice))
|
||||
.to_not include(status.id)
|
||||
expect(home_feed_ids(jeff))
|
||||
.to_not include(status.id)
|
||||
|
||||
it 'sends Delete activity to followers' do
|
||||
subject.call(status)
|
||||
expect(redis)
|
||||
.to have_received(:publish).with('timeline:public:media', Oj.dump(event: :delete, payload: status.id.to_s))
|
||||
|
||||
expect(delete_delivery(hank, status))
|
||||
.to have_been_made.once
|
||||
end
|
||||
|
||||
it 'sends Delete activity to rebloggers' do
|
||||
subject.call(status)
|
||||
|
||||
expect(delete_delivery(bill, status))
|
||||
.to have_been_made.once
|
||||
end
|
||||
|
||||
it 'remove status from notifications' do
|
||||
expect { subject.call(status) }.to change {
|
||||
Notification.where(activity_type: 'Favourite', from_account: jeff, account: alice).count
|
||||
}.from(1).to(0)
|
||||
def home_feed_ids(personage)
|
||||
HomeFeed
|
||||
.new(personage)
|
||||
.get(10)
|
||||
.pluck(:id)
|
||||
end
|
||||
|
||||
def remove_status_from_notifications
|
||||
change { Notification.where(activity_type: 'Favourite', from_account: jeff, account: alice).count }
|
||||
.from(1)
|
||||
.to(0)
|
||||
end
|
||||
|
||||
def delete_delivery(target, status)
|
||||
|
|
|
@ -31,14 +31,13 @@ RSpec.describe ReportService do
|
|||
context 'when forward is true', :inline_jobs do
|
||||
let(:forward) { true }
|
||||
|
||||
it 'sends ActivityPub payload when forward is true' do
|
||||
subject.call(source_account, remote_account, forward: forward)
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made
|
||||
end
|
||||
|
||||
it 'has an uri' do
|
||||
it 'has a URI and sends ActivityPub payload' do
|
||||
report = subject.call(source_account, remote_account, forward: forward)
|
||||
expect(report.uri).to_not be_nil
|
||||
|
||||
expect(report.uri)
|
||||
.to_not be_nil
|
||||
expect(a_request(:post, 'http://example.com/inbox'))
|
||||
.to have_been_made
|
||||
end
|
||||
|
||||
context 'when reporting a reply on a different remote server' do
|
||||
|
@ -122,13 +121,12 @@ RSpec.describe ReportService do
|
|||
status.mentions.create(account: source_account)
|
||||
end
|
||||
|
||||
it 'creates a report' do
|
||||
expect { subject.call }.to change { target_account.targeted_reports.count }.from(0).to(1)
|
||||
end
|
||||
it 'creates a report and attaches the DM to the report' do
|
||||
expect { subject.call }
|
||||
.to change { target_account.targeted_reports.count }.from(0).to(1)
|
||||
|
||||
it 'attaches the DM to the report' do
|
||||
subject.call
|
||||
expect(target_account.targeted_reports.pluck(:status_ids)).to eq [[status.id]]
|
||||
expect(target_account.targeted_reports.pluck(:status_ids))
|
||||
.to eq [[status.id]]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -146,13 +144,12 @@ RSpec.describe ReportService do
|
|||
status.mentions.create(account: source_account)
|
||||
end
|
||||
|
||||
it 'creates a report' do
|
||||
expect { subject.call }.to change { target_account.targeted_reports.count }.from(0).to(1)
|
||||
end
|
||||
it 'creates a report and attaches DM to report' do
|
||||
expect { subject.call }
|
||||
.to change { target_account.targeted_reports.count }.from(0).to(1)
|
||||
|
||||
it 'attaches the DM to the report' do
|
||||
subject.call
|
||||
expect(target_account.targeted_reports.pluck(:status_ids)).to eq [[status.id]]
|
||||
expect(target_account.targeted_reports.pluck(:status_ids))
|
||||
.to eq [[status.id]]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -24,37 +24,38 @@ RSpec.describe ResolveAccountService do
|
|||
context 'when domain is banned' do
|
||||
before { Fabricate(:domain_block, domain: 'ap.example.com', severity: :suspend) }
|
||||
|
||||
it 'does not return an account' do
|
||||
expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to be_nil
|
||||
end
|
||||
|
||||
it 'does not make a webfinger query' do
|
||||
subject.call('foo@ap.example.com', skip_webfinger: true)
|
||||
expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made
|
||||
it 'does not return an account or make a webfinger query' do
|
||||
expect(subject.call('foo@ap.example.com', skip_webfinger: true))
|
||||
.to be_nil
|
||||
expect(webfinger_discovery_request)
|
||||
.to_not have_been_made
|
||||
end
|
||||
end
|
||||
|
||||
context 'when domain is not banned' do
|
||||
it 'returns the expected account' do
|
||||
expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to eq remote_account
|
||||
end
|
||||
|
||||
it 'does not make a webfinger query' do
|
||||
subject.call('foo@ap.example.com', skip_webfinger: true)
|
||||
expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made
|
||||
it 'returns the expected account and does not make a webfinger query' do
|
||||
expect(subject.call('foo@ap.example.com', skip_webfinger: true))
|
||||
.to eq remote_account
|
||||
expect(webfinger_discovery_request)
|
||||
.to_not have_been_made
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account is not known' do
|
||||
it 'does not return an account' do
|
||||
expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to be_nil
|
||||
it 'does not return an account and does not make webfinger query' do
|
||||
expect(subject.call('foo@ap.example.com', skip_webfinger: true))
|
||||
.to be_nil
|
||||
expect(webfinger_discovery_request)
|
||||
.to_not have_been_made
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not make a webfinger query' do
|
||||
subject.call('foo@ap.example.com', skip_webfinger: true)
|
||||
expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made
|
||||
end
|
||||
def webfinger_discovery_request
|
||||
a_request(
|
||||
:get,
|
||||
'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -86,13 +87,11 @@ RSpec.describe ResolveAccountService do
|
|||
allow(AccountDeletionWorker).to receive(:perform_async)
|
||||
end
|
||||
|
||||
it 'returns nil' do
|
||||
expect(subject.call('hoge@example.com')).to be_nil
|
||||
end
|
||||
|
||||
it 'queues account deletion worker' do
|
||||
subject.call('hoge@example.com')
|
||||
expect(AccountDeletionWorker).to have_received(:perform_async)
|
||||
it 'returns nil and queues deletion worker' do
|
||||
expect(subject.call('hoge@example.com'))
|
||||
.to be_nil
|
||||
expect(AccountDeletionWorker)
|
||||
.to have_received(:perform_async)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -112,9 +111,12 @@ RSpec.describe ResolveAccountService do
|
|||
it 'returns new remote account' do
|
||||
account = subject.call('Foo@redirected.example.com')
|
||||
|
||||
expect(account.activitypub?).to be true
|
||||
expect(account.acct).to eq 'foo@ap.example.com'
|
||||
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
|
||||
expect(account)
|
||||
.to have_attributes(
|
||||
activitypub?: true,
|
||||
acct: 'foo@ap.example.com',
|
||||
inbox_url: 'https://ap.example.com/users/foo/inbox'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -127,9 +129,12 @@ RSpec.describe ResolveAccountService do
|
|||
it 'returns new remote account' do
|
||||
account = subject.call('Foo@redirected.example.com')
|
||||
|
||||
expect(account.activitypub?).to be true
|
||||
expect(account.acct).to eq 'foo@ap.example.com'
|
||||
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
|
||||
expect(account)
|
||||
.to have_attributes(
|
||||
activitypub?: true,
|
||||
acct: 'foo@ap.example.com',
|
||||
inbox_url: 'https://ap.example.com/users/foo/inbox'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -165,9 +170,12 @@ RSpec.describe ResolveAccountService do
|
|||
it 'returns new remote account' do
|
||||
account = subject.call('foo@ap.example.com')
|
||||
|
||||
expect(account.activitypub?).to be true
|
||||
expect(account.domain).to eq 'ap.example.com'
|
||||
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
|
||||
expect(account)
|
||||
.to have_attributes(
|
||||
activitypub?: true,
|
||||
domain: 'ap.example.com',
|
||||
inbox_url: 'https://ap.example.com/users/foo/inbox'
|
||||
)
|
||||
end
|
||||
|
||||
context 'with multiple types' do
|
||||
|
@ -178,10 +186,13 @@ RSpec.describe ResolveAccountService do
|
|||
it 'returns new remote account' do
|
||||
account = subject.call('foo@ap.example.com')
|
||||
|
||||
expect(account.activitypub?).to be true
|
||||
expect(account.domain).to eq 'ap.example.com'
|
||||
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
|
||||
expect(account.actor_type).to eq 'Person'
|
||||
expect(account)
|
||||
.to have_attributes(
|
||||
activitypub?: true,
|
||||
domain: 'ap.example.com',
|
||||
inbox_url: 'https://ap.example.com/users/foo/inbox',
|
||||
actor_type: 'Person'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -190,20 +201,21 @@ RSpec.describe ResolveAccountService do
|
|||
let!(:duplicate) { Fabricate(:account, username: 'foo', domain: 'old.example.com', uri: 'https://ap.example.com/users/foo') }
|
||||
let!(:status) { Fabricate(:status, account: duplicate, text: 'foo') }
|
||||
|
||||
it 'returns new remote account' do
|
||||
it 'returns new remote account and merges accounts', :inline_jobs do
|
||||
account = subject.call('foo@ap.example.com')
|
||||
|
||||
expect(account.activitypub?).to be true
|
||||
expect(account.domain).to eq 'ap.example.com'
|
||||
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
|
||||
expect(account.uri).to eq 'https://ap.example.com/users/foo'
|
||||
end
|
||||
expect(account)
|
||||
.to have_attributes(
|
||||
activitypub?: true,
|
||||
domain: 'ap.example.com',
|
||||
inbox_url: 'https://ap.example.com/users/foo/inbox',
|
||||
uri: 'https://ap.example.com/users/foo'
|
||||
)
|
||||
|
||||
it 'merges accounts', :inline_jobs do
|
||||
account = subject.call('foo@ap.example.com')
|
||||
|
||||
expect(status.reload.account_id).to eq account.id
|
||||
expect(Account.where(uri: account.uri).count).to eq 1
|
||||
expect(status.reload.account_id)
|
||||
.to eq account.id
|
||||
expect(Account.where(uri: account.uri).count)
|
||||
.to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -214,11 +226,15 @@ RSpec.describe ResolveAccountService do
|
|||
it 'returns new remote account' do
|
||||
account = subject.call('foo@ap.example.com')
|
||||
|
||||
expect(account.activitypub?).to be true
|
||||
expect(account.domain).to eq 'ap.example.com'
|
||||
expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
|
||||
expect(account.uri).to eq 'https://ap.example.com/users/foo'
|
||||
expect(status.reload.account).to eq(account)
|
||||
expect(account)
|
||||
.to have_attributes(
|
||||
activitypub?: true,
|
||||
domain: 'ap.example.com',
|
||||
inbox_url: 'https://ap.example.com/users/foo/inbox',
|
||||
uri: 'https://ap.example.com/users/foo'
|
||||
)
|
||||
expect(status.reload.account)
|
||||
.to eq(account)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -51,12 +51,11 @@ RSpec.describe ResolveURLService do
|
|||
let(:url) { 'https://example.com/@foo/42' }
|
||||
let(:uri) { 'https://example.com/users/foo/statuses/42' }
|
||||
|
||||
it 'returns status by url' do
|
||||
expect(subject.call(url, on_behalf_of: account)).to eq(status)
|
||||
end
|
||||
|
||||
it 'returns status by uri' do
|
||||
expect(subject.call(uri, on_behalf_of: account)).to eq(status)
|
||||
it 'returns status by URL or URI' do
|
||||
expect(subject.call(url, on_behalf_of: account))
|
||||
.to eq(status)
|
||||
expect(subject.call(uri, on_behalf_of: account))
|
||||
.to eq(status)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -75,12 +74,11 @@ RSpec.describe ResolveURLService do
|
|||
let(:url) { 'https://example.com/@foo/42' }
|
||||
let(:uri) { 'https://example.com/users/foo/statuses/42' }
|
||||
|
||||
it 'does not return the status by url' do
|
||||
expect(subject.call(url, on_behalf_of: account)).to be_nil
|
||||
end
|
||||
|
||||
it 'does not return the status by uri' do
|
||||
expect(subject.call(uri, on_behalf_of: account)).to be_nil
|
||||
it 'does not return the status by URL or URI' do
|
||||
expect(subject.call(url, on_behalf_of: account))
|
||||
.to be_nil
|
||||
expect(subject.call(uri, on_behalf_of: account))
|
||||
.to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -107,22 +105,20 @@ RSpec.describe ResolveURLService do
|
|||
account.follow!(poster)
|
||||
end
|
||||
|
||||
it 'returns status by url' do
|
||||
expect(subject.call(url, on_behalf_of: account)).to eq(status)
|
||||
end
|
||||
|
||||
it 'returns status by uri' do
|
||||
expect(subject.call(uri, on_behalf_of: account)).to eq(status)
|
||||
it 'returns status by URL or URI' do
|
||||
expect(subject.call(url, on_behalf_of: account))
|
||||
.to eq(status)
|
||||
expect(subject.call(uri, on_behalf_of: account))
|
||||
.to eq(status)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account does not follow the poster' do
|
||||
it 'does not return the status by url' do
|
||||
expect(subject.call(url, on_behalf_of: account)).to be_nil
|
||||
end
|
||||
|
||||
it 'does not return the status by uri' do
|
||||
expect(subject.call(uri, on_behalf_of: account)).to be_nil
|
||||
it 'does not return the status by URL or URI' do
|
||||
expect(subject.call(url, on_behalf_of: account))
|
||||
.to be_nil
|
||||
expect(subject.call(uri, on_behalf_of: account))
|
||||
.to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,20 +32,14 @@ RSpec.describe TranslateStatusService do
|
|||
allow(TranslationService).to receive_messages(configured?: true, configured: translation_service)
|
||||
end
|
||||
|
||||
it 'returns translated status content' do
|
||||
expect(service.call(status, 'es').content).to eq '<p>Hola</p>'
|
||||
end
|
||||
|
||||
it 'returns source language' do
|
||||
expect(service.call(status, 'es').detected_source_language).to eq 'en'
|
||||
end
|
||||
|
||||
it 'returns translation provider' do
|
||||
expect(service.call(status, 'es').provider).to eq 'Dummy'
|
||||
end
|
||||
|
||||
it 'returns original status' do
|
||||
expect(service.call(status, 'es').status).to eq status
|
||||
it 'returns translated status content and source language and provider and original status' do
|
||||
expect(service.call(status, 'es'))
|
||||
.to have_attributes(
|
||||
content: '<p>Hola</p>',
|
||||
detected_source_language: 'en',
|
||||
provider: 'Dummy',
|
||||
status: status
|
||||
)
|
||||
end
|
||||
|
||||
describe 'status has content with custom emoji' do
|
||||
|
@ -155,26 +149,16 @@ RSpec.describe TranslateStatusService do
|
|||
let!(:source_texts) { service.send(:source_texts) }
|
||||
|
||||
it 'returns formatted poll options' do
|
||||
expect(source_texts.size).to eq 3
|
||||
expect(source_texts.values).to eq %w(<p>Hello</p> Blue Green)
|
||||
end
|
||||
|
||||
it 'has a first key with content' do
|
||||
expect(source_texts.keys.first).to eq :content
|
||||
end
|
||||
|
||||
it 'has the first option in the second key with correct options' do
|
||||
option1 = source_texts.keys.second
|
||||
expect(option1).to be_a Poll::Option
|
||||
expect(option1.id).to eq '0'
|
||||
expect(option1.title).to eq 'Blue'
|
||||
end
|
||||
|
||||
it 'has the second option in the third key with correct options' do
|
||||
option2 = source_texts.keys.third
|
||||
expect(option2).to be_a Poll::Option
|
||||
expect(option2.id).to eq '1'
|
||||
expect(option2.title).to eq 'Green'
|
||||
expect(source_texts)
|
||||
.to have_attributes(
|
||||
size: 3,
|
||||
values: %w(<p>Hello</p> Blue Green),
|
||||
keys: contain_exactly(
|
||||
eq(:content),
|
||||
be_a(Poll::Option).and(have_attributes(id: '0', title: 'Blue')),
|
||||
be_a(Poll::Option).and(have_attributes(id: '1', title: 'Green'))
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,26 +12,32 @@ RSpec.describe UnblockDomainService do
|
|||
let!(:silenced) { Fabricate(:account, domain: 'example.com', silenced_at: domain_block.created_at) }
|
||||
let!(:suspended) { Fabricate(:account, domain: 'example.com', suspended_at: domain_block.created_at) }
|
||||
|
||||
it 'unsilences accounts and removes block' do
|
||||
domain_block.update(severity: :silence)
|
||||
context 'with severity of silence' do
|
||||
before { domain_block.update(severity: :silence) }
|
||||
|
||||
subject.call(domain_block)
|
||||
expect_deleted_domain_block
|
||||
expect(silenced.reload.silenced?).to be false
|
||||
expect(suspended.reload.suspended?).to be true
|
||||
expect(independently_suspended.reload.suspended?).to be true
|
||||
expect(independently_silenced.reload.silenced?).to be true
|
||||
it 'unsilences accounts and removes block' do
|
||||
subject.call(domain_block)
|
||||
|
||||
expect_deleted_domain_block
|
||||
expect(silenced.reload.silenced?).to be false
|
||||
expect(suspended.reload.suspended?).to be true
|
||||
expect(independently_suspended.reload.suspended?).to be true
|
||||
expect(independently_silenced.reload.silenced?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
it 'unsuspends accounts and removes block' do
|
||||
domain_block.update(severity: :suspend)
|
||||
context 'with severity of suspend' do
|
||||
before { domain_block.update(severity: :suspend) }
|
||||
|
||||
subject.call(domain_block)
|
||||
expect_deleted_domain_block
|
||||
expect(suspended.reload.suspended?).to be false
|
||||
expect(silenced.reload.silenced?).to be false
|
||||
expect(independently_suspended.reload.suspended?).to be true
|
||||
expect(independently_silenced.reload.silenced?).to be true
|
||||
it 'unsuspends accounts and removes block' do
|
||||
subject.call(domain_block)
|
||||
|
||||
expect_deleted_domain_block
|
||||
expect(suspended.reload.suspended?).to be false
|
||||
expect(silenced.reload.silenced?).to be false
|
||||
expect(independently_suspended.reload.suspended?).to be true
|
||||
expect(independently_silenced.reload.silenced?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ RSpec.describe UnblockService do
|
|||
describe 'local' do
|
||||
let(:bob) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
sender.block!(bob)
|
||||
subject.call(sender, bob)
|
||||
end
|
||||
before { sender.block!(bob) }
|
||||
|
||||
it 'destroys the blocking relation' do
|
||||
expect(sender.blocking?(bob)).to be false
|
||||
subject.call(sender, bob)
|
||||
|
||||
expect(sender)
|
||||
.to_not be_blocking(bob)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -26,15 +26,15 @@ RSpec.describe UnblockService do
|
|||
before do
|
||||
sender.block!(bob)
|
||||
stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'destroys the blocking relation and sends unblock activity', :inline_jobs do
|
||||
subject.call(sender, bob)
|
||||
end
|
||||
|
||||
it 'destroys the blocking relation' do
|
||||
expect(sender.blocking?(bob)).to be false
|
||||
end
|
||||
|
||||
it 'sends an unblock activity', :inline_jobs do
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
|
||||
expect(sender)
|
||||
.to_not be_blocking(bob)
|
||||
expect(a_request(:post, 'http://example.com/inbox'))
|
||||
.to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,13 +10,13 @@ RSpec.describe UnfollowService do
|
|||
describe 'local' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
sender.follow!(bob)
|
||||
subject.call(sender, bob)
|
||||
end
|
||||
before { sender.follow!(bob) }
|
||||
|
||||
it 'destroys the following relation' do
|
||||
expect(sender.following?(bob)).to be false
|
||||
subject.call(sender, bob)
|
||||
|
||||
expect(sender)
|
||||
.to_not be_following(bob)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -26,15 +26,15 @@ RSpec.describe UnfollowService do
|
|||
before do
|
||||
sender.follow!(bob)
|
||||
stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'destroys the following relation and sends unfollow activity' do
|
||||
subject.call(sender, bob)
|
||||
end
|
||||
|
||||
it 'destroys the following relation' do
|
||||
expect(sender.following?(bob)).to be false
|
||||
end
|
||||
|
||||
it 'sends an unfollow activity' do
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
|
||||
expect(sender)
|
||||
.to_not be_following(bob)
|
||||
expect(a_request(:post, 'http://example.com/inbox'))
|
||||
.to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -44,15 +44,15 @@ RSpec.describe UnfollowService do
|
|||
before do
|
||||
bob.follow!(sender)
|
||||
stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'destroys the following relation and sends a reject activity' do
|
||||
subject.call(bob, sender)
|
||||
end
|
||||
|
||||
it 'destroys the following relation' do
|
||||
expect(bob.following?(sender)).to be false
|
||||
end
|
||||
|
||||
it 'sends a reject activity' do
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
|
||||
expect(sender)
|
||||
.to_not be_following(bob)
|
||||
expect(a_request(:post, 'http://example.com/inbox'))
|
||||
.to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,23 +21,19 @@ RSpec.describe UpdateAccountService do
|
|||
FollowService.new.call(bob, account)
|
||||
FollowService.new.call(eve, account)
|
||||
FollowService.new.call(ohagi, account)
|
||||
end
|
||||
|
||||
it 'auto accepts pending follow requests from appropriate accounts' do
|
||||
subject.call(account, { locked: false })
|
||||
end
|
||||
|
||||
it 'auto-accepts pending follow requests' do
|
||||
expect(alice.following?(account)).to be true
|
||||
expect(alice.requested?(account)).to be false
|
||||
end
|
||||
expect(alice).to be_following(account)
|
||||
expect(alice).to_not be_requested(account)
|
||||
|
||||
it 'does not auto-accept pending follow requests from silenced users' do
|
||||
expect(bob.following?(account)).to be false
|
||||
expect(bob.requested?(account)).to be true
|
||||
end
|
||||
expect(bob).to_not be_following(account)
|
||||
expect(bob).to be_requested(account)
|
||||
|
||||
it 'auto-accepts pending follow requests from muted users so as to not leak mute' do
|
||||
expect(eve.following?(account)).to be true
|
||||
expect(eve.requested?(account)).to be false
|
||||
expect(eve).to be_following(account)
|
||||
expect(eve).to_not be_requested(account)
|
||||
end
|
||||
|
||||
it 'does not auto-accept pending follow requests from blocking straight follow domains' do
|
||||
|
|
|
@ -10,15 +10,15 @@ RSpec.describe UpdateStatusService do
|
|||
|
||||
before do
|
||||
allow(ActivityPub::DistributionWorker).to receive(:perform_async)
|
||||
end
|
||||
|
||||
it 'does not create an edit or notify anyone' do
|
||||
subject.call(status, status.account_id, text: 'Foo')
|
||||
end
|
||||
|
||||
it 'does not create an edit' do
|
||||
expect(status.reload.edits).to be_empty
|
||||
end
|
||||
|
||||
it 'does not notify anyone' do
|
||||
expect(ActivityPub::DistributionWorker).to_not have_received(:perform_async)
|
||||
expect(status.reload.edits)
|
||||
.to be_empty
|
||||
expect(ActivityPub::DistributionWorker)
|
||||
.to_not have_received(:perform_async)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -28,18 +28,16 @@ RSpec.describe UpdateStatusService do
|
|||
|
||||
before do
|
||||
PreviewCardsStatus.create(status: status, preview_card: preview_card)
|
||||
end
|
||||
|
||||
it 'updates text, resets card, saves edit history' do
|
||||
subject.call(status, status.account_id, text: 'Bar')
|
||||
end
|
||||
|
||||
it 'updates text' do
|
||||
expect(status.reload.text).to eq 'Bar'
|
||||
end
|
||||
|
||||
it 'resets preview card' do
|
||||
expect(status.reload.preview_card).to be_nil
|
||||
end
|
||||
|
||||
it 'saves edit history' do
|
||||
expect(status.reload)
|
||||
.to have_attributes(
|
||||
text: 'Bar',
|
||||
preview_card: be_nil
|
||||
)
|
||||
expect(status.edits.ordered.pluck(:text)).to eq %w(Foo Bar)
|
||||
end
|
||||
end
|
||||
|
@ -50,15 +48,15 @@ RSpec.describe UpdateStatusService do
|
|||
|
||||
before do
|
||||
PreviewCardsStatus.create(status: status, preview_card: preview_card)
|
||||
end
|
||||
|
||||
it 'updates content warning and saves history' do
|
||||
subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar')
|
||||
end
|
||||
|
||||
it 'updates content warning' do
|
||||
expect(status.reload.spoiler_text).to eq 'Bar'
|
||||
end
|
||||
|
||||
it 'saves edit history' do
|
||||
expect(status.edits.ordered.pluck(:text, :spoiler_text)).to eq [['Foo', ''], ['Foo', 'Bar']]
|
||||
expect(status.reload.spoiler_text)
|
||||
.to eq 'Bar'
|
||||
expect(status.edits.ordered.pluck(:text, :spoiler_text))
|
||||
.to eq [['Foo', ''], ['Foo', 'Bar']]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -118,23 +116,19 @@ RSpec.describe UpdateStatusService do
|
|||
|
||||
before do
|
||||
status.media_attachments << detached_media_attachment
|
||||
end
|
||||
|
||||
it 'updates media attachments, handles attachments, saves history' do
|
||||
subject.call(status, status.account_id, text: 'Foo', media_ids: [attached_media_attachment.id.to_s])
|
||||
end
|
||||
|
||||
it 'updates media attachments' do
|
||||
expect(status.ordered_media_attachments).to eq [attached_media_attachment]
|
||||
end
|
||||
|
||||
it 'does not detach detached media attachments' do
|
||||
expect(detached_media_attachment.reload.status_id).to eq status.id
|
||||
end
|
||||
|
||||
it 'attaches attached media attachments' do
|
||||
expect(attached_media_attachment.reload.status_id).to eq status.id
|
||||
end
|
||||
|
||||
it 'saves edit history' do
|
||||
expect(status.edits.ordered.pluck(:ordered_media_attachment_ids)).to eq [[detached_media_attachment.id], [attached_media_attachment.id]]
|
||||
expect(status.ordered_media_attachments)
|
||||
.to eq [attached_media_attachment]
|
||||
expect(detached_media_attachment.reload.status_id)
|
||||
.to eq status.id
|
||||
expect(attached_media_attachment.reload.status_id)
|
||||
.to eq status.id
|
||||
expect(status.edits.ordered.pluck(:ordered_media_attachment_ids))
|
||||
.to eq [[detached_media_attachment.id], [attached_media_attachment.id]]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -144,19 +138,18 @@ RSpec.describe UpdateStatusService do
|
|||
|
||||
before do
|
||||
status.media_attachments << media_attachment
|
||||
end
|
||||
|
||||
it 'does not detach media attachment, updates description, and saves history' do
|
||||
subject.call(status, status.account_id, text: 'Foo', media_ids: [media_attachment.id.to_s], media_attributes: [{ id: media_attachment.id, description: 'New description' }])
|
||||
end
|
||||
|
||||
it 'does not detach media attachment' do
|
||||
expect(media_attachment.reload.status_id).to eq status.id
|
||||
end
|
||||
|
||||
it 'updates the media attachment description' do
|
||||
expect(media_attachment.reload.description).to eq 'New description'
|
||||
end
|
||||
|
||||
it 'saves edit history' do
|
||||
expect(status.edits.ordered.map { |edit| edit.ordered_media_attachments.map(&:description) }).to eq [['Old description'], ['New description']]
|
||||
expect(media_attachment.reload)
|
||||
.to have_attributes(
|
||||
status_id: status.id,
|
||||
description: 'New description'
|
||||
)
|
||||
expect(status.edits.ordered.map { |edit| edit.ordered_media_attachments.map(&:description) })
|
||||
.to eq [['Old description'], ['New description']]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -169,28 +162,27 @@ RSpec.describe UpdateStatusService do
|
|||
before do
|
||||
status.update(poll: poll)
|
||||
VoteService.new.call(voter, poll, [0])
|
||||
end
|
||||
|
||||
it 'updates poll, resets votes, saves history, requeues notifications' do
|
||||
subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i })
|
||||
end
|
||||
|
||||
it 'updates poll' do
|
||||
poll = status.poll.reload
|
||||
expect(poll.options).to eq %w(Bar Baz Foo)
|
||||
end
|
||||
|
||||
it 'resets votes' do
|
||||
poll = status.poll.reload
|
||||
expect(poll.votes_count).to eq 0
|
||||
expect(poll.votes.count).to eq 0
|
||||
expect(poll.cached_tallies).to eq [0, 0, 0]
|
||||
end
|
||||
expect(poll)
|
||||
.to have_attributes(
|
||||
options: %w(Bar Baz Foo),
|
||||
votes_count: 0,
|
||||
cached_tallies: [0, 0, 0]
|
||||
)
|
||||
expect(poll.votes.count)
|
||||
.to eq(0)
|
||||
|
||||
it 'saves edit history' do
|
||||
expect(status.edits.ordered.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)]
|
||||
end
|
||||
expect(status.edits.ordered.pluck(:poll_options))
|
||||
.to eq [%w(Foo Bar), %w(Bar Baz Foo)]
|
||||
|
||||
it 'requeues expiration notification' do
|
||||
poll = status.poll.reload
|
||||
expect(PollExpirationNotifyWorker).to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes)
|
||||
expect(PollExpirationNotifyWorker)
|
||||
.to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -200,16 +192,13 @@ RSpec.describe UpdateStatusService do
|
|||
let!(:bob) { Fabricate(:account, username: 'bob') }
|
||||
let!(:status) { PostStatusService.new.call(account, text: 'Hello @alice') }
|
||||
|
||||
before do
|
||||
it 'changes mentions and keeps old as silent' do
|
||||
subject.call(status, status.account_id, text: 'Hello @bob')
|
||||
end
|
||||
|
||||
it 'changes mentions' do
|
||||
expect(status.active_mentions.pluck(:account_id)).to eq [bob.id]
|
||||
end
|
||||
|
||||
it 'keeps old mentions as silent mentions' do
|
||||
expect(status.mentions.pluck(:account_id)).to contain_exactly(alice.id, bob.id)
|
||||
expect(status.active_mentions.pluck(:account_id))
|
||||
.to eq [bob.id]
|
||||
expect(status.mentions.pluck(:account_id))
|
||||
.to contain_exactly(alice.id, bob.id)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -250,11 +239,9 @@ RSpec.describe UpdateStatusService do
|
|||
let!(:account) { Fabricate(:account) }
|
||||
let!(:status) { PostStatusService.new.call(account, text: 'Hello #foo') }
|
||||
|
||||
before do
|
||||
subject.call(status, status.account_id, text: 'Hello #bar')
|
||||
end
|
||||
|
||||
it 'changes tags' do
|
||||
subject.call(status, status.account_id, text: 'Hello #bar')
|
||||
|
||||
expect(status.tags.pluck(:name)).to eq %w(bar)
|
||||
end
|
||||
end
|
||||
|
|
4
spec/support/response_encoders.rb
Normal file
4
spec/support/response_encoders.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
ActionDispatch::IntegrationTest
|
||||
.register_encoder :xml, response_parser: ->(body) { Nokogiri::XML(body) }
|
|
@ -9,7 +9,6 @@ RSpec.describe 'Invites' do
|
|||
|
||||
before do
|
||||
UserRole.everyone.update(permissions: UserRole::FLAGS[:invite_users])
|
||||
host! 'localhost:3000' # TODO: Move into before for all system specs?
|
||||
sign_in user
|
||||
end
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ RSpec.describe 'Using OAuth from an external app' do
|
|||
end
|
||||
|
||||
context 'when the user has set up TOTP' do
|
||||
let(:user) { Fabricate(:user, email: email, password: password, otp_required_for_login: true, otp_secret: User.generate_otp_secret(32)) }
|
||||
let(:user) { Fabricate(:user, email: email, password: password, otp_required_for_login: true, otp_secret: User.generate_otp_secret) }
|
||||
|
||||
it 'when accepting the authorization request' do
|
||||
params = { client_id: client_app.uid, response_type: 'code', redirect_uri: client_app.redirect_uri, scope: 'read' }
|
||||
|
|
|
@ -28,4 +28,17 @@ RSpec.describe 'report interface', :attachment_processing, :js, :streaming do
|
|||
page.scroll_to(page.find('.batch-table__row'))
|
||||
expect(page).to have_css('.spoiler-button__overlay__label')
|
||||
end
|
||||
|
||||
it 'marks a report resolved from the show page actions area' do
|
||||
visit admin_report_path(report)
|
||||
|
||||
expect { resolve_report }
|
||||
.to change { report.reload.action_taken_at }.to(be_present).from(nil)
|
||||
end
|
||||
|
||||
def resolve_report
|
||||
within '.report-actions' do
|
||||
click_on I18n.t('admin.reports.mark_as_resolved')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
38
spec/workers/mention_resolve_worker_spec.rb
Normal file
38
spec/workers/mention_resolve_worker_spec.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe MentionResolveWorker do
|
||||
let(:status_id) { -42 }
|
||||
let(:uri) { 'https://example.com/users/unknown' }
|
||||
|
||||
describe '#perform' do
|
||||
subject { described_class.new.perform(status_id, uri, {}) }
|
||||
|
||||
context 'with a non-existent status' do
|
||||
it 'returns nil' do
|
||||
expect(subject).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a valid user' do
|
||||
let(:status) { Fabricate(:status) }
|
||||
let(:status_id) { status.id }
|
||||
|
||||
let(:service_double) { instance_double(ActivityPub::FetchRemoteAccountService) }
|
||||
|
||||
before do
|
||||
allow(ActivityPub::FetchRemoteAccountService).to receive(:new).and_return(service_double)
|
||||
|
||||
allow(service_double).to receive(:call).with(uri, anything) { Fabricate(:account, domain: 'example.com', uri: uri) }
|
||||
end
|
||||
|
||||
it 'resolves the account and adds a new mention', :aggregate_failures do
|
||||
expect { subject }
|
||||
.to change { status.reload.mentions }.from([]).to(a_collection_including(having_attributes(account: having_attributes(uri: uri), silent: false)))
|
||||
|
||||
expect(service_double).to have_received(:call).once
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,27 +22,48 @@ RSpec.describe Web::PushNotificationWorker do
|
|||
let(:payload) { { ciphertext: ciphertext, salt: salt, server_public_key: server_public_key, shared_secret: shared_secret } }
|
||||
|
||||
describe 'perform' do
|
||||
around do |example|
|
||||
original_private = Rails.configuration.x.vapid_private_key
|
||||
original_public = Rails.configuration.x.vapid_public_key
|
||||
Rails.configuration.x.vapid_private_key = vapid_private_key
|
||||
Rails.configuration.x.vapid_public_key = vapid_public_key
|
||||
example.run
|
||||
Rails.configuration.x.vapid_private_key = original_private
|
||||
Rails.configuration.x.vapid_public_key = original_public
|
||||
end
|
||||
|
||||
before do
|
||||
allow(subscription).to receive_messages(contact_email: contact_email, vapid_key: vapid_key)
|
||||
allow(Web::PushSubscription).to receive(:find).with(subscription.id).and_return(subscription)
|
||||
Setting.site_contact_email = contact_email
|
||||
|
||||
allow(Webpush::Encryption).to receive(:encrypt).and_return(payload)
|
||||
allow(JWT).to receive(:encode).and_return('jwt.encoded.payload')
|
||||
|
||||
stub_request(:post, endpoint).to_return(status: 201, body: '')
|
||||
|
||||
subject.perform(subscription.id, notification.id)
|
||||
end
|
||||
|
||||
it 'calls the relevant service with the correct headers' do
|
||||
expect(a_request(:post, endpoint).with(headers: {
|
||||
'Content-Encoding' => 'aesgcm',
|
||||
'Content-Type' => 'application/octet-stream',
|
||||
'Crypto-Key' => "dh=BAgtUks5d90kFmxGevk9tH7GEmvz9DB0qcEMUsOBgKwMf-TMjsKIIG6LQvGcFAf6jcmAod15VVwmYwGIIxE4VWE;p256ecdsa=#{vapid_public_key.delete('=')}",
|
||||
'Encryption' => 'salt=WJeVM-RY-F9351SVxTFx_g',
|
||||
'Ttl' => '172800',
|
||||
'Urgency' => 'normal',
|
||||
'Authorization' => 'WebPush jwt.encoded.payload',
|
||||
}, body: "+\xB8\xDBT}\u0013\xB6\xDD.\xF9\xB0\xA7\xC8Ҁ\xFD\x99#\xF7\xAC\x83\xA4\xDB,\u001F\xB5\xB9w\x85>\xF7\xADr")).to have_been_made
|
||||
subject.perform(subscription.id, notification.id)
|
||||
|
||||
expect(web_push_endpoint_request)
|
||||
.to have_been_made
|
||||
end
|
||||
|
||||
def web_push_endpoint_request
|
||||
a_request(
|
||||
:post,
|
||||
endpoint
|
||||
).with(
|
||||
headers: {
|
||||
'Content-Encoding' => 'aesgcm',
|
||||
'Content-Type' => 'application/octet-stream',
|
||||
'Crypto-Key' => "dh=BAgtUks5d90kFmxGevk9tH7GEmvz9DB0qcEMUsOBgKwMf-TMjsKIIG6LQvGcFAf6jcmAod15VVwmYwGIIxE4VWE;p256ecdsa=#{vapid_public_key.delete('=')}",
|
||||
'Encryption' => 'salt=WJeVM-RY-F9351SVxTFx_g',
|
||||
'Ttl' => '172800',
|
||||
'Urgency' => 'normal',
|
||||
'Authorization' => 'WebPush jwt.encoded.payload',
|
||||
},
|
||||
body: "+\xB8\xDBT}\u0013\xB6\xDD.\xF9\xB0\xA7\xC8Ҁ\xFD\x99#\xF7\xAC\x83\xA4\xDB,\u001F\xB5\xB9w\x85>\xF7\xADr"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue