Gab Social. All are welcome.

This commit is contained in:
robcolbert
2019-07-02 03:10:25 -04:00
commit bd0b5afc92
5366 changed files with 222812 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
# frozen_string_literal: true
require 'rails_helper'
describe ActivityPub::DeliveryWorker do
subject { described_class.new }
let(:sender) { Fabricate(:account) }
let(:payload) { 'test' }
describe 'perform' do
it 'performs a request' do
stub_request(:post, 'https://example.com/api').to_return(status: 200)
subject.perform(payload, sender.id, 'https://example.com/api')
expect(a_request(:post, 'https://example.com/api')).to have_been_made.once
end
it 'raises when request fails' do
stub_request(:post, 'https://example.com/api').to_return(status: 500)
expect { subject.perform(payload, sender.id, 'https://example.com/api') }.to raise_error GabSocial::UnexpectedResponseError
end
end
end

View File

@@ -0,0 +1,48 @@
require 'rails_helper'
describe ActivityPub::DistributionWorker do
subject { described_class.new }
let(:status) { Fabricate(:status) }
let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com') }
describe '#perform' do
before do
allow(ActivityPub::DeliveryWorker).to receive(:push_bulk)
follower.follow!(status.account)
end
context 'with public status' do
before do
status.update(visibility: :public)
end
it 'delivers to followers' do
subject.perform(status.id)
expect(ActivityPub::DeliveryWorker).to have_received(:push_bulk).with(['http://example.com'])
end
end
context 'with private status' do
before do
status.update(visibility: :private)
end
it 'delivers to followers' do
subject.perform(status.id)
expect(ActivityPub::DeliveryWorker).to have_received(:push_bulk).with(['http://example.com'])
end
end
context 'with direct status' do
before do
status.update(visibility: :direct)
end
it 'does nothing' do
subject.perform(status.id)
expect(ActivityPub::DeliveryWorker).to_not have_received(:push_bulk)
end
end
end
end

View File

@@ -0,0 +1,40 @@
# frozen_string_literal: true
require 'rails_helper'
describe ActivityPub::FetchRepliesWorker do
subject { described_class.new }
let(:account) { Fabricate(:account, uri: 'https://example.com/user/1') }
let(:status) { Fabricate(:status, account: account) }
let(:payload) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'https://example.com/statuses_replies/1',
type: 'Collection',
items: [],
}
end
let(:json) { Oj.dump(payload) }
describe 'perform' do
it 'performs a request if the collection URI is from the same host' do
stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 200, body: json)
subject.perform(status.id, 'https://example.com/statuses_replies/1')
expect(a_request(:get, 'https://example.com/statuses_replies/1')).to have_been_made.once
end
it 'does not perform a request if the collection URI is from a different host' do
stub_request(:get, 'https://other.com/statuses_replies/1').to_return(status: 200)
subject.perform(status.id, 'https://other.com/statuses_replies/1')
expect(a_request(:get, 'https://other.com/statuses_replies/1')).to_not have_been_made
end
it 'raises when request fails' do
stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 500)
expect { subject.perform(status.id, 'https://example.com/statuses_replies/1') }.to raise_error GabSocial::UnexpectedResponseError
end
end
end

View File

@@ -0,0 +1,15 @@
require 'rails_helper'
describe ActivityPub::ProcessingWorker do
subject { described_class.new }
let(:account) { Fabricate(:account) }
describe '#perform' do
it 'delegates to ActivityPub::ProcessCollectionService' do
allow(ActivityPub::ProcessCollectionService).to receive(:new).and_return(double(:service, call: nil))
subject.perform(account.id, '')
expect(ActivityPub::ProcessCollectionService).to have_received(:new)
end
end
end

View File

@@ -0,0 +1,20 @@
require 'rails_helper'
describe ActivityPub::UpdateDistributionWorker do
subject { described_class.new }
let(:account) { Fabricate(:account) }
let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com') }
describe '#perform' do
before do
allow(ActivityPub::DeliveryWorker).to receive(:push_bulk)
follower.follow!(account)
end
it 'delivers to followers' do
subject.perform(account.id)
expect(ActivityPub::DeliveryWorker).to have_received(:push_bulk).with(['http://example.com'])
end
end
end

View File

@@ -0,0 +1,59 @@
# frozen_string_literal: true
require 'rails_helper'
describe AfterRemoteFollowRequestWorker do
subject { described_class.new }
let(:follow_request) { Fabricate(:follow_request) }
describe 'perform' do
context 'when the follow_request does not exist' do
it 'catches a raise and returns true' do
allow(FollowService).to receive(:new)
result = subject.perform('aaa')
expect(result).to eq(true)
expect(FollowService).not_to have_received(:new)
end
end
context 'when the account cannot be updated' do
it 'returns nil and does not call service when account is nil' do
allow(FollowService).to receive(:new)
service = double(call: nil)
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
result = subject.perform(follow_request.id)
expect(result).to be_nil
expect(FollowService).not_to have_received(:new)
end
it 'returns nil and does not call service when account is locked' do
allow(FollowService).to receive(:new)
service = double(call: double(locked?: true))
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
result = subject.perform(follow_request.id)
expect(result).to be_nil
expect(FollowService).not_to have_received(:new)
end
end
context 'when the account is updated' do
it 'calls the follow service and destroys the follow' do
follow_service = double(call: nil)
allow(FollowService).to receive(:new).and_return(follow_service)
account = Fabricate(:account, locked: false)
service = double(call: account)
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
result = subject.perform(follow_request.id)
expect(result).to be_nil
expect(follow_service).to have_received(:call).with(follow_request.account, account.acct)
expect { follow_request.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
end
end

View File

@@ -0,0 +1,59 @@
# frozen_string_literal: true
require 'rails_helper'
describe AfterRemoteFollowWorker do
subject { described_class.new }
let(:follow) { Fabricate(:follow) }
describe 'perform' do
context 'when the follow does not exist' do
it 'catches a raise and returns true' do
allow(FollowService).to receive(:new)
result = subject.perform('aaa')
expect(result).to eq(true)
expect(FollowService).not_to have_received(:new)
end
end
context 'when the account cannot be updated' do
it 'returns nil and does not call service when account is nil' do
allow(FollowService).to receive(:new)
service = double(call: nil)
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
result = subject.perform(follow.id)
expect(result).to be_nil
expect(FollowService).not_to have_received(:new)
end
it 'returns nil and does not call service when account is not locked' do
allow(FollowService).to receive(:new)
service = double(call: double(locked?: false))
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
result = subject.perform(follow.id)
expect(result).to be_nil
expect(FollowService).not_to have_received(:new)
end
end
context 'when the account is updated' do
it 'calls the follow service and destroys the follow' do
follow_service = double(call: nil)
allow(FollowService).to receive(:new).and_return(follow_service)
account = Fabricate(:account, locked: true)
service = double(call: account)
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
result = subject.perform(follow.id)
expect(result).to be_nil
expect(follow_service).to have_received(:call).with(follow.account, account.acct)
expect { follow.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
end
end

View File

@@ -0,0 +1,36 @@
# frozen_string_literal: true
require 'rails_helper'
describe DigestMailerWorker do
describe 'perform' do
let(:user) { Fabricate(:user, last_emailed_at: 3.days.ago) }
context 'for a user who receives digests' do
it 'sends the email' do
service = double(deliver_now!: nil)
allow(NotificationMailer).to receive(:digest).and_return(service)
update_user_digest_setting(true)
described_class.perform_async(user.id)
expect(NotificationMailer).to have_received(:digest)
expect(user.reload.last_emailed_at).to be_within(1).of(Time.now.utc)
end
end
context 'for a user who does not receive digests' do
it 'does not send the email' do
allow(NotificationMailer).to receive(:digest)
update_user_digest_setting(false)
described_class.perform_async(user.id)
expect(NotificationMailer).not_to have_received(:digest)
expect(user.last_emailed_at).to be_within(1).of(3.days.ago)
end
end
def update_user_digest_setting(value)
user.settings['notification_emails'] = user.settings['notification_emails'].merge('digest' => value)
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
require 'rails_helper'
describe DomainBlockWorker do
subject { described_class.new }
describe 'perform' do
let(:domain_block) { Fabricate(:domain_block) }
it 'returns true for non-existent domain block' do
service = double(call: nil)
allow(BlockDomainService).to receive(:new).and_return(service)
result = subject.perform(domain_block.id)
expect(result).to be_nil
expect(service).to have_received(:call).with(domain_block)
end
it 'calls domain block service for relevant domain block' do
result = subject.perform('aaa')
expect(result).to eq(true)
end
end
end

View File

@@ -0,0 +1,52 @@
# frozen_string_literal: true
require 'rails_helper'
describe FeedInsertWorker do
subject { described_class.new }
describe 'perform' do
let(:follower) { Fabricate(:account) }
let(:status) { Fabricate(:status) }
context 'when there are no records' do
it 'skips push with missing status' do
instance = double(push_to_home: nil)
allow(FeedManager).to receive(:instance).and_return(instance)
result = subject.perform(nil, follower.id)
expect(result).to eq true
expect(instance).not_to have_received(:push_to_home)
end
it 'skips push with missing account' do
instance = double(push_to_home: nil)
allow(FeedManager).to receive(:instance).and_return(instance)
result = subject.perform(status.id, nil)
expect(result).to eq true
expect(instance).not_to have_received(:push_to_home)
end
end
context 'when there are real records' do
it 'skips the push when there is a filter' do
instance = double(push_to_home: nil, filter?: true)
allow(FeedManager).to receive(:instance).and_return(instance)
result = subject.perform(status.id, follower.id)
expect(result).to be_nil
expect(instance).not_to have_received(:push_to_home)
end
it 'pushes the status onto the home timeline without filter' do
instance = double(push_to_home: nil, filter?: false)
allow(FeedManager).to receive(:instance).and_return(instance)
result = subject.perform(status.id, follower.id)
expect(result).to be_nil
expect(instance).to have_received(:push_to_home).with(follower, status)
end
end
end
end

View File

@@ -0,0 +1,23 @@
# frozen_string_literal: true
require 'rails_helper'
describe PublishScheduledStatusWorker do
subject { described_class.new }
let(:scheduled_status) { Fabricate(:scheduled_status, params: { text: 'Hello world, future!' }) }
describe 'perform' do
before do
subject.perform(scheduled_status.id)
end
it 'creates a status' do
expect(scheduled_status.account.statuses.first.text).to eq 'Hello world, future!'
end
it 'removes the scheduled status' do
expect(ScheduledStatus.find_by(id: scheduled_status.id)).to be_nil
end
end
end

View File

@@ -0,0 +1,88 @@
# frozen_string_literal: true
require 'rails_helper'
describe Pubsubhubbub::ConfirmationWorker do
include RoutingHelper
subject { described_class.new }
let!(:alice) { Fabricate(:account, username: 'alice') }
let!(:subscription) { Fabricate(:subscription, account: alice, callback_url: 'http://example.com/api', confirmed: false, expires_at: 3.days.from_now, secret: nil) }
describe 'perform' do
describe 'with subscribe mode' do
it 'confirms and updates subscription when challenge matches' do
stub_random_value
stub_request(:get, url_for_mode('subscribe'))
.with(headers: http_headers)
.to_return(status: 200, body: challenge_value, headers: {})
seconds = 10.days.seconds.to_i
subject.perform(subscription.id, 'subscribe', 'asdf', seconds)
subscription.reload
expect(subscription.secret).to eq 'asdf'
expect(subscription.confirmed).to eq true
expect(subscription.expires_at).to be_within(5).of(10.days.from_now)
end
it 'does not update subscription when challenge does not match' do
stub_random_value
stub_request(:get, url_for_mode('subscribe'))
.with(headers: http_headers)
.to_return(status: 200, body: 'wrong value', headers: {})
seconds = 10.days.seconds.to_i
subject.perform(subscription.id, 'subscribe', 'asdf', seconds)
subscription.reload
expect(subscription.secret).to be_blank
expect(subscription.confirmed).to eq false
expect(subscription.expires_at).to be_within(5).of(3.days.from_now)
end
end
describe 'with unsubscribe mode' do
it 'confirms and destroys subscription when challenge matches' do
stub_random_value
stub_request(:get, url_for_mode('unsubscribe'))
.with(headers: http_headers)
.to_return(status: 200, body: challenge_value, headers: {})
seconds = 10.days.seconds.to_i
subject.perform(subscription.id, 'unsubscribe', 'asdf', seconds)
expect { subscription.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
it 'does not destroy subscription when challenge does not match' do
stub_random_value
stub_request(:get, url_for_mode('unsubscribe'))
.with(headers: http_headers)
.to_return(status: 200, body: 'wrong value', headers: {})
seconds = 10.days.seconds.to_i
subject.perform(subscription.id, 'unsubscribe', 'asdf', seconds)
expect { subscription.reload }.not_to raise_error
end
end
end
def url_for_mode(mode)
"http://example.com/api?hub.challenge=#{challenge_value}&hub.lease_seconds=863999&hub.mode=#{mode}&hub.topic=https://#{Rails.configuration.x.local_domain}/users/alice.atom"
end
def stub_random_value
allow(SecureRandom).to receive(:hex).and_return(challenge_value)
end
def challenge_value
'1a2s3d4f'
end
def http_headers
{ 'Connection' => 'close', 'Host' => 'example.com' }
end
end

View File

@@ -0,0 +1,68 @@
# frozen_string_literal: true
require 'rails_helper'
describe Pubsubhubbub::DeliveryWorker do
include RoutingHelper
subject { described_class.new }
let(:payload) { 'test' }
describe 'perform' do
it 'raises when subscription does not exist' do
expect { subject.perform 123, payload }.to raise_error(ActiveRecord::RecordNotFound)
end
it 'does not attempt to deliver when domain blocked' do
_domain_block = Fabricate(:domain_block, domain: 'example.com', severity: :suspend)
subscription = Fabricate(:subscription, callback_url: 'https://example.com/api', last_successful_delivery_at: 2.days.ago)
subject.perform(subscription.id, payload)
expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(2.days.ago)
end
it 'raises when request fails' do
subscription = Fabricate(:subscription)
stub_request_to_respond_with(subscription, 500)
expect { subject.perform(subscription.id, payload) }.to raise_error GabSocial::UnexpectedResponseError
end
it 'updates subscriptions when delivery succeeds' do
subscription = Fabricate(:subscription)
stub_request_to_respond_with(subscription, 200)
subject.perform(subscription.id, payload)
expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(Time.now.utc)
end
it 'updates subscription without a secret when delivery succeeds' do
subscription = Fabricate(:subscription, secret: nil)
stub_request_to_respond_with(subscription, 200)
subject.perform(subscription.id, payload)
expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(Time.now.utc)
end
def stub_request_to_respond_with(subscription, code)
stub_request(:post, 'http://example.com/callback')
.with(body: payload, headers: expected_headers(subscription))
.to_return(status: code, body: '', headers: {})
end
def expected_headers(subscription)
{
'Connection' => 'close',
'Content-Type' => 'application/atom+xml',
'Host' => 'example.com',
'Link' => "<https://#{Rails.configuration.x.local_domain}/api/push>; rel=\"hub\", <https://#{Rails.configuration.x.local_domain}/users/#{subscription.account.username}.atom>; rel=\"self\"",
}.tap do |basic|
known_digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret.to_s, payload)
basic.merge('X-Hub-Signature' => "sha1=#{known_digest}") if subscription.secret?
end
end
end
end

View File

@@ -0,0 +1,46 @@
require 'rails_helper'
describe Pubsubhubbub::DistributionWorker do
subject { Pubsubhubbub::DistributionWorker.new }
let!(:alice) { Fabricate(:account, username: 'alice') }
let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example2.com') }
let!(:anonymous_subscription) { Fabricate(:subscription, account: alice, callback_url: 'http://example1.com', confirmed: true, lease_seconds: 3600) }
let!(:subscription_with_follower) { Fabricate(:subscription, account: alice, callback_url: 'http://example2.com', confirmed: true, lease_seconds: 3600) }
before do
bob.follow!(alice)
end
describe 'with public status' do
let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :public) }
it 'delivers payload to all subscriptions' do
allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)
subject.perform(status.stream_entry.id)
expect(Pubsubhubbub::DeliveryWorker).to have_received(:push_bulk).with([anonymous_subscription.id, subscription_with_follower.id])
end
end
context 'when OStatus privacy is not used' do
describe 'with private status' do
let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :private) }
it 'does not deliver anything' do
allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)
subject.perform(status.stream_entry.id)
expect(Pubsubhubbub::DeliveryWorker).to_not have_received(:push_bulk)
end
end
describe 'with direct status' do
let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :direct) }
it 'does not deliver payload' do
allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)
subject.perform(status.stream_entry.id)
expect(Pubsubhubbub::DeliveryWorker).to_not have_received(:push_bulk)
end
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
require 'rails_helper'
describe RegenerationWorker do
subject { described_class.new }
describe 'perform' do
let(:account) { Fabricate(:account) }
it 'calls the precompute feed service for the account' do
service = double(call: nil)
allow(PrecomputeFeedService).to receive(:new).and_return(service)
result = subject.perform(account.id)
expect(result).to be_nil
expect(service).to have_received(:call).with(account)
end
it 'fails when account does not exist' do
result = subject.perform('aaa')
expect(result).to eq(true)
end
end
end

View File

@@ -0,0 +1,26 @@
require 'rails_helper'
describe Scheduler::FeedCleanupScheduler do
subject { described_class.new }
let!(:active_user) { Fabricate(:user, current_sign_in_at: 2.days.ago) }
let!(:inactive_user) { Fabricate(:user, current_sign_in_at: 22.days.ago) }
it 'clears feeds of inactives' do
Redis.current.zadd(feed_key_for(inactive_user), 1, 1)
Redis.current.zadd(feed_key_for(active_user), 1, 1)
Redis.current.zadd(feed_key_for(inactive_user, 'reblogs'), 2, 2)
Redis.current.sadd(feed_key_for(inactive_user, 'reblogs:2'), 3)
subject.perform
expect(Redis.current.zcard(feed_key_for(inactive_user))).to eq 0
expect(Redis.current.zcard(feed_key_for(active_user))).to eq 1
expect(Redis.current.exists(feed_key_for(inactive_user, 'reblogs'))).to be false
expect(Redis.current.exists(feed_key_for(inactive_user, 'reblogs:2'))).to be false
end
def feed_key_for(user, subtype = nil)
FeedManager.instance.key(:home, user.account_id, subtype)
end
end

View File

@@ -0,0 +1,15 @@
require 'rails_helper'
describe Scheduler::MediaCleanupScheduler do
subject { described_class.new }
let!(:old_media) { Fabricate(:media_attachment, account_id: nil, created_at: 10.days.ago) }
let!(:new_media) { Fabricate(:media_attachment, account_id: nil, created_at: 1.hour.ago) }
it 'removes old media records' do
subject.perform
expect { old_media.reload }.to raise_error(ActiveRecord::RecordNotFound)
expect(new_media.reload).to be_persisted
end
end

View File

@@ -0,0 +1,19 @@
require 'rails_helper'
describe Scheduler::SubscriptionsScheduler do
subject { Scheduler::SubscriptionsScheduler.new }
let!(:expiring_account1) { Fabricate(:account, subscription_expires_at: 20.minutes.from_now, domain: 'example.com', followers_count: 1, hub_url: 'http://hub.example.com') }
let!(:expiring_account2) { Fabricate(:account, subscription_expires_at: 4.hours.from_now, domain: 'example.org', followers_count: 1, hub_url: 'http://hub.example.org') }
before do
stub_request(:post, 'http://hub.example.com/').to_return(status: 202)
stub_request(:post, 'http://hub.example.org/').to_return(status: 202)
end
it 're-subscribes for all expiring accounts' do
subject.perform
expect(a_request(:post, 'http://hub.example.com/')).to have_been_made.once
expect(a_request(:post, 'http://hub.example.org/')).to have_been_made.once
end
end