Merge tag 'v2.8.0' into instance_only_statuses
This commit is contained in:
@ -3,7 +3,7 @@ require 'rails_helper'
|
||||
RSpec.describe AccountsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let(:alice) { Fabricate(:account, username: 'alice', user: Fabricate(:user)) }
|
||||
let(:eve) { Fabricate(:user) }
|
||||
|
||||
describe 'GET #show' do
|
||||
|
||||
@ -10,7 +10,7 @@ RSpec.describe ActivityPub::InboxesController, type: :controller do
|
||||
Fabricate(:account)
|
||||
end
|
||||
|
||||
post :create
|
||||
post :create, body: '{}'
|
||||
expect(response).to have_http_status(202)
|
||||
end
|
||||
end
|
||||
@ -21,7 +21,7 @@ RSpec.describe ActivityPub::InboxesController, type: :controller do
|
||||
false
|
||||
end
|
||||
|
||||
post :create
|
||||
post :create, body: '{}'
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
|
||||
@ -19,6 +19,10 @@ RSpec.describe Admin::SettingsController, type: :controller do
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
before do
|
||||
allow_any_instance_of(Form::AdminSettings).to receive(:valid?).and_return(true)
|
||||
end
|
||||
|
||||
describe 'for a record that doesnt exist' do
|
||||
around do |example|
|
||||
before = Setting.site_extended_description
|
||||
@ -62,22 +66,6 @@ RSpec.describe Admin::SettingsController, type: :controller do
|
||||
expect(Setting.site_title).to eq 'New title'
|
||||
end
|
||||
end
|
||||
|
||||
context do
|
||||
around do |example|
|
||||
open_registrations = Setting.open_registrations
|
||||
example.run
|
||||
Setting.open_registrations = open_registrations
|
||||
end
|
||||
|
||||
it 'typecasts open_registrations to boolean' do
|
||||
Setting.open_registrations = false
|
||||
patch :update, params: { form_admin_settings: { open_registrations: '1' } }
|
||||
|
||||
expect(response).to redirect_to(edit_admin_settings_path)
|
||||
expect(Setting.open_registrations).to eq true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
96
spec/controllers/api/proofs_controller_spec.rb
Normal file
96
spec/controllers/api/proofs_controller_spec.rb
Normal file
@ -0,0 +1,96 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::ProofsController do
|
||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||
|
||||
before do
|
||||
stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_valid.json?domain=cb6e6126.ngrok.io&kb_username=crypto_alice&sig_hash=111111111111111111111111111111111111111111111111111111111111111111&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":false}')
|
||||
stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_live.json?domain=cb6e6126.ngrok.io&kb_username=crypto_alice&sig_hash=111111111111111111111111111111111111111111111111111111111111111111&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":true}')
|
||||
stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_valid.json?domain=cb6e6126.ngrok.io&kb_username=hidden_alice&sig_hash=222222222222222222222222222222222222222222222222222222222222222222&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":true}')
|
||||
stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_live.json?domain=cb6e6126.ngrok.io&kb_username=hidden_alice&sig_hash=222222222222222222222222222222222222222222222222222222222222222222&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":true}')
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
describe 'with a non-existent username' do
|
||||
it '404s' do
|
||||
get :index, params: { username: 'nonexistent', provider: 'keybase' }
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with a user that has no proofs' do
|
||||
it 'is an empty list of signatures' do
|
||||
get :index, params: { username: alice.username, provider: 'keybase' }
|
||||
|
||||
expect(body_as_json[:signatures]).to eq []
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with a user that has a live, valid proof' do
|
||||
let(:token1) { '111111111111111111111111111111111111111111111111111111111111111111' }
|
||||
let(:kb_name1) { 'crypto_alice' }
|
||||
|
||||
before do
|
||||
Fabricate(:account_identity_proof, account: alice, verified: true, live: true, token: token1, provider_username: kb_name1)
|
||||
end
|
||||
|
||||
it 'is a list with that proof in it' do
|
||||
get :index, params: { username: alice.username, provider: 'keybase' }
|
||||
|
||||
expect(body_as_json[:signatures]).to eq [
|
||||
{ kb_username: kb_name1, sig_hash: token1 },
|
||||
]
|
||||
end
|
||||
|
||||
describe 'add one that is neither live nor valid' do
|
||||
let(:token2) { '222222222222222222222222222222222222222222222222222222222222222222' }
|
||||
let(:kb_name2) { 'hidden_alice' }
|
||||
|
||||
before do
|
||||
Fabricate(:account_identity_proof, account: alice, verified: false, live: false, token: token2, provider_username: kb_name2)
|
||||
end
|
||||
|
||||
it 'is a list with both proofs' do
|
||||
get :index, params: { username: alice.username, provider: 'keybase' }
|
||||
|
||||
expect(body_as_json[:signatures]).to eq [
|
||||
{ kb_username: kb_name1, sig_hash: token1 },
|
||||
{ kb_username: kb_name2, sig_hash: token2 },
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'a user that has an avatar' do
|
||||
let(:alice) { Fabricate(:account, username: 'alice', avatar: attachment_fixture('avatar.gif')) }
|
||||
|
||||
context 'and a proof' do
|
||||
let(:token1) { '111111111111111111111111111111111111111111111111111111111111111111' }
|
||||
let(:kb_name1) { 'crypto_alice' }
|
||||
|
||||
before do
|
||||
Fabricate(:account_identity_proof, account: alice, verified: true, live: true, token: token1, provider_username: kb_name1)
|
||||
get :index, params: { username: alice.username, provider: 'keybase' }
|
||||
end
|
||||
|
||||
it 'has two keys: signatures and avatar' do
|
||||
expect(body_as_json.keys).to match_array [:signatures, :avatar]
|
||||
end
|
||||
|
||||
it 'has the correct signatures' do
|
||||
expect(body_as_json[:signatures]).to eq [
|
||||
{ kb_username: kb_name1, sig_hash: token1 },
|
||||
]
|
||||
end
|
||||
|
||||
it 'has the correct avatar url' do
|
||||
first_part = 'https://cb6e6126.ngrok.io/system/accounts/avatars/'
|
||||
last_part = 'original/avatar.gif'
|
||||
|
||||
expect(body_as_json[:avatar]).to match /#{Regexp.quote(first_part)}(?:\d{3,5}\/){3}#{Regexp.quote(last_part)}/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
34
spec/controllers/api/v1/polls/votes_controller_spec.rb
Normal file
34
spec/controllers/api/v1/polls/votes_controller_spec.rb
Normal file
@ -0,0 +1,34 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::Polls::VotesController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
|
||||
let(:scopes) { 'write:statuses' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
||||
before { allow(controller).to receive(:doorkeeper_token) { token } }
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:poll) { Fabricate(:poll) }
|
||||
|
||||
before do
|
||||
post :create, params: { poll_id: poll.id, choices: %w(1) }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a vote' do
|
||||
vote = poll.votes.where(account: user.account).first
|
||||
|
||||
expect(vote).to_not be_nil
|
||||
expect(vote.choice).to eq 1
|
||||
end
|
||||
|
||||
it 'updates poll tallies' do
|
||||
expect(poll.reload.cached_tallies).to eq [0, 1]
|
||||
end
|
||||
end
|
||||
end
|
||||
23
spec/controllers/api/v1/polls_controller_spec.rb
Normal file
23
spec/controllers/api/v1/polls_controller_spec.rb
Normal file
@ -0,0 +1,23 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::PollsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
|
||||
let(:scopes) { 'read:statuses' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
||||
before { allow(controller).to receive(:doorkeeper_token) { token } }
|
||||
|
||||
describe 'GET #show' do
|
||||
let(:poll) { Fabricate(:poll) }
|
||||
|
||||
before do
|
||||
get :show, params: { id: poll.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -5,14 +5,14 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
|
||||
|
||||
shared_examples 'checks for enabled registrations' do |path|
|
||||
around do |example|
|
||||
open_registrations = Setting.open_registrations
|
||||
registrations_mode = Setting.registrations_mode
|
||||
example.run
|
||||
Setting.open_registrations = open_registrations
|
||||
Setting.registrations_mode = registrations_mode
|
||||
end
|
||||
|
||||
it 'redirects if it is in single user mode while it is open for registration' do
|
||||
Fabricate(:account)
|
||||
Setting.open_registrations = true
|
||||
Setting.registrations_mode = 'open'
|
||||
expect(Rails.configuration.x).to receive(:single_user_mode).and_return(true)
|
||||
|
||||
get path
|
||||
@ -21,7 +21,7 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
|
||||
end
|
||||
|
||||
it 'redirects if it is not open for registration while it is not in single user mode' do
|
||||
Setting.open_registrations = false
|
||||
Setting.registrations_mode = 'none'
|
||||
expect(Rails.configuration.x).to receive(:single_user_mode).and_return(false)
|
||||
|
||||
get path
|
||||
@ -55,13 +55,13 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
|
||||
|
||||
context do
|
||||
around do |example|
|
||||
open_registrations = Setting.open_registrations
|
||||
registrations_mode = Setting.registrations_mode
|
||||
example.run
|
||||
Setting.open_registrations = open_registrations
|
||||
Setting.registrations_mode = registrations_mode
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
Setting.open_registrations = true
|
||||
Setting.registrations_mode = 'open'
|
||||
get :new
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
@ -83,13 +83,13 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
|
||||
|
||||
context do
|
||||
around do |example|
|
||||
open_registrations = Setting.open_registrations
|
||||
registrations_mode = Setting.registrations_mode
|
||||
example.run
|
||||
Setting.open_registrations = open_registrations
|
||||
Setting.registrations_mode = registrations_mode
|
||||
end
|
||||
|
||||
subject do
|
||||
Setting.open_registrations = true
|
||||
Setting.registrations_mode = 'open'
|
||||
request.headers["Accept-Language"] = accept_language
|
||||
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678' } }
|
||||
end
|
||||
|
||||
@ -17,7 +17,15 @@ describe ApplicationController, type: :controller do
|
||||
|
||||
context 'when account is suspended' do
|
||||
it 'returns http gone' do
|
||||
account = Fabricate(:account, suspended: true)
|
||||
account = Fabricate(:account, suspended: true, user: Fabricate(:user))
|
||||
get 'success', params: { account_username: account.username }
|
||||
expect(response).to have_http_status(410)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account is deleted by owner' do
|
||||
it 'returns http gone' do
|
||||
account = Fabricate(:account, suspended: true, user: nil)
|
||||
get 'success', params: { account_username: account.username }
|
||||
expect(response).to have_http_status(410)
|
||||
end
|
||||
@ -25,19 +33,19 @@ describe ApplicationController, type: :controller do
|
||||
|
||||
context 'when account is not suspended' do
|
||||
it 'assigns @account' do
|
||||
account = Fabricate(:account)
|
||||
account = Fabricate(:account, user: Fabricate(:user))
|
||||
get 'success', params: { account_username: account.username }
|
||||
expect(assigns(:account)).to eq account
|
||||
end
|
||||
|
||||
it 'sets link headers' do
|
||||
account = Fabricate(:account, username: 'username')
|
||||
account = Fabricate(:account, username: 'username', user: Fabricate(:user))
|
||||
get 'success', params: { account_username: 'username' }
|
||||
expect(response.headers['Link'].to_s).to eq '<http://test.host/.well-known/webfinger?resource=acct%3Ausername%40cb6e6126.ngrok.io>; rel="lrdd"; type="application/xrd+xml", <http://test.host/users/username.atom>; rel="alternate"; type="application/atom+xml", <https://cb6e6126.ngrok.io/users/username>; rel="alternate"; type="application/activity+json"'
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
account = Fabricate(:account)
|
||||
account = Fabricate(:account, user: Fabricate(:user))
|
||||
get 'success', params: { account_username: account.username }
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Settings::FollowerDomainsController do
|
||||
describe RelationshipsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
@ -12,24 +12,17 @@ describe Settings::FollowerDomainsController do
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
subject { get :show, params: { page: 2 } }
|
||||
subject { get :show, params: { page: 2, relationship: 'followed_by' } }
|
||||
|
||||
it 'assigns @account' do
|
||||
sign_in user, scope: :user
|
||||
subject
|
||||
expect(assigns(:account)).to eq user.account
|
||||
end
|
||||
|
||||
it 'assigns @domains' do
|
||||
it 'assigns @accounts' do
|
||||
Fabricate(:account, domain: 'old').follow!(user.account)
|
||||
Fabricate(:account, domain: 'recent').follow!(user.account)
|
||||
|
||||
sign_in user, scope: :user
|
||||
subject
|
||||
|
||||
assigned = assigns(:domains).per(1).to_a
|
||||
assigned = assigns(:accounts).per(1).to_a
|
||||
expect(assigned.size).to eq 1
|
||||
expect(assigned[0].accounts_from_domain).to eq 1
|
||||
expect(assigned[0].domain).to eq 'old'
|
||||
end
|
||||
|
||||
@ -49,25 +42,24 @@ describe Settings::FollowerDomainsController do
|
||||
stub_request(:post, 'http://example.com/salmon').to_return(status: 200)
|
||||
end
|
||||
|
||||
shared_examples 'redirects back to followers page' do |notice|
|
||||
shared_examples 'redirects back to followers page' do
|
||||
it 'redirects back to followers page' do
|
||||
poopfeast.follow!(user.account)
|
||||
|
||||
sign_in user, scope: :user
|
||||
subject
|
||||
|
||||
expect(flash[:notice]).to eq notice
|
||||
expect(response).to redirect_to(settings_follower_domains_path)
|
||||
expect(response).to redirect_to(relationships_path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when select parameter is not provided' do
|
||||
subject { patch :update }
|
||||
include_examples 'redirects back to followers page', 'In the process of soft-blocking followers from 0 domains...'
|
||||
include_examples 'redirects back to followers page'
|
||||
end
|
||||
|
||||
context 'when select parameter is provided' do
|
||||
subject { patch :update, params: { select: ['example.com'] } }
|
||||
subject { patch :update, params: { form_account_batch: { account_ids: [poopfeast.id] }, block_domains: '' } }
|
||||
|
||||
it 'soft-blocks followers from selected domains' do
|
||||
poopfeast.follow!(user.account)
|
||||
@ -79,7 +71,7 @@ describe Settings::FollowerDomainsController do
|
||||
end
|
||||
|
||||
include_examples 'authenticate user'
|
||||
include_examples 'redirects back to followers page', 'In the process of soft-blocking followers from one domain...'
|
||||
include_examples 'redirects back to followers page'
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -11,7 +11,7 @@ describe Settings::Exports::FollowingAccountsController do
|
||||
sign_in user, scope: :user
|
||||
get :index, format: :csv
|
||||
|
||||
expect(response.body).to eq "username@domain\n"
|
||||
expect(response.body).to eq "Account address,Show boosts\nusername@domain,true\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -11,7 +11,7 @@ describe Settings::Exports::MutedAccountsController do
|
||||
sign_in user, scope: :user
|
||||
get :index, format: :csv
|
||||
|
||||
expect(response.body).to eq "username@domain\n"
|
||||
expect(response.body).to eq "Account address,Hide notifications\nusername@domain,true\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
168
spec/controllers/settings/identity_proofs_controller_spec.rb
Normal file
168
spec/controllers/settings/identity_proofs_controller_spec.rb
Normal file
@ -0,0 +1,168 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Settings::IdentityProofsController do
|
||||
include RoutingHelper
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:valid_token) { '1'*66 }
|
||||
let(:kbname) { 'kbuser' }
|
||||
let(:provider) { 'keybase' }
|
||||
let(:findable_id) { Faker::Number.number(5) }
|
||||
let(:unfindable_id) { Faker::Number.number(5) }
|
||||
let(:new_proof_params) do
|
||||
{ provider: provider, provider_username: kbname, token: valid_token, username: user.account.username }
|
||||
end
|
||||
let(:status_text) { "i just proved that i am also #{kbname} on #{provider}." }
|
||||
let(:status_posting_params) do
|
||||
{ post_status: '0', status_text: status_text }
|
||||
end
|
||||
let(:postable_params) do
|
||||
{ account_identity_proof: new_proof_params.merge(status_posting_params) }
|
||||
end
|
||||
|
||||
before do
|
||||
allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:status) { { 'proof_valid' => true, 'proof_live' => true } }
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'new proof creation' do
|
||||
context 'GET #new' do
|
||||
before do
|
||||
allow_any_instance_of(ProofProvider::Keybase::Badge).to receive(:avatar_url) { full_pack_url('media/images/void.png') }
|
||||
end
|
||||
|
||||
context 'with all of the correct params' do
|
||||
it 'renders the template' do
|
||||
get :new, params: new_proof_params
|
||||
expect(response).to render_template(:new)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without any params' do
|
||||
it 'redirects to :index' do
|
||||
get :new, params: {}
|
||||
expect(response).to redirect_to settings_identity_proofs_path
|
||||
end
|
||||
end
|
||||
|
||||
context 'with params to prove a different, not logged-in user' do
|
||||
let(:wrong_user_params) { new_proof_params.merge(username: 'someone_else') }
|
||||
|
||||
it 'shows a helpful alert' do
|
||||
get :new, params: wrong_user_params
|
||||
expect(flash[:alert]).to eq I18n.t('identity_proofs.errors.wrong_user', proving: 'someone_else', current: user.account.username)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with params to prove the same username cased differently' do
|
||||
let(:capitalized_username) { new_proof_params.merge(username: user.account.username.upcase) }
|
||||
|
||||
it 'renders the new template' do
|
||||
get :new, params: capitalized_username
|
||||
expect(response).to render_template(:new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'POST #create' do
|
||||
context 'when saving works' do
|
||||
before do
|
||||
allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
|
||||
allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
|
||||
allow_any_instance_of(AccountIdentityProof).to receive(:on_success_path) { root_url }
|
||||
end
|
||||
|
||||
it 'serializes a ProofProvider::Keybase::Worker' do
|
||||
expect(ProofProvider::Keybase::Worker).to receive(:perform_async)
|
||||
post :create, params: postable_params
|
||||
end
|
||||
|
||||
it 'delegates redirection to the proof provider' do
|
||||
expect_any_instance_of(AccountIdentityProof).to receive(:on_success_path)
|
||||
post :create, params: postable_params
|
||||
expect(response).to redirect_to root_url
|
||||
end
|
||||
|
||||
it 'does not post a status' do
|
||||
expect(PostStatusService).not_to receive(:new)
|
||||
post :create, params: postable_params
|
||||
end
|
||||
|
||||
context 'and the user has requested to post a status' do
|
||||
let(:postable_params_with_status) do
|
||||
postable_params.tap { |p| p[:account_identity_proof][:post_status] = '1' }
|
||||
end
|
||||
|
||||
it 'posts a status' do
|
||||
expect_any_instance_of(PostStatusService).to receive(:call).with(user.account, text: status_text)
|
||||
|
||||
post :create, params: postable_params_with_status
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when saving fails' do
|
||||
before do
|
||||
allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { false }
|
||||
end
|
||||
|
||||
it 'redirects to :index' do
|
||||
post :create, params: postable_params
|
||||
expect(response).to redirect_to settings_identity_proofs_path
|
||||
end
|
||||
|
||||
it 'flashes a helpful message' do
|
||||
post :create, params: postable_params
|
||||
expect(flash[:alert]).to eq I18n.t('identity_proofs.errors.failed', provider: 'Keybase')
|
||||
end
|
||||
end
|
||||
|
||||
context 'it can also do an update if the provider and username match an existing proof' do
|
||||
before do
|
||||
allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
|
||||
allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
|
||||
Fabricate(:account_identity_proof, account: user.account, provider: provider, provider_username: kbname)
|
||||
allow_any_instance_of(AccountIdentityProof).to receive(:on_success_path) { root_url }
|
||||
end
|
||||
|
||||
it 'calls update with the new token' do
|
||||
expect_any_instance_of(AccountIdentityProof).to receive(:save) do |proof|
|
||||
expect(proof.token).to eq valid_token
|
||||
end
|
||||
|
||||
post :create, params: postable_params
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
context 'with no existing proofs' do
|
||||
it 'shows the helpful explanation' do
|
||||
get :index
|
||||
expect(response.body).to match I18n.t('identity_proofs.explanation_html')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with two proofs' do
|
||||
before do
|
||||
allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
|
||||
@proof1 = Fabricate(:account_identity_proof, account: user.account)
|
||||
@proof2 = Fabricate(:account_identity_proof, account: user.account)
|
||||
allow_any_instance_of(AccountIdentityProof).to receive(:badge) { double(avatar_url: '', profile_url: '', proof_url: '') }
|
||||
allow_any_instance_of(AccountIdentityProof).to receive(:refresh!) { }
|
||||
end
|
||||
|
||||
it 'has the first proof username on the page' do
|
||||
get :index
|
||||
expect(response.body).to match /#{Regexp.quote(@proof1.provider_username)}/
|
||||
end
|
||||
|
||||
it 'has the second proof username on the page' do
|
||||
get :index
|
||||
expect(response.body).to match /#{Regexp.quote(@proof2.provider_username)}/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,15 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe WellKnown::KeybaseProofConfigController, type: :controller do
|
||||
render_views
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'renders json' do
|
||||
get :show
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.content_type).to eq 'application/json'
|
||||
expect { JSON.parse(response.body) }.not_to raise_exception
|
||||
end
|
||||
end
|
||||
end
|
||||
8
spec/fabricators/account_identity_proof_fabricator.rb
Normal file
8
spec/fabricators/account_identity_proof_fabricator.rb
Normal file
@ -0,0 +1,8 @@
|
||||
Fabricator(:account_identity_proof) do
|
||||
account
|
||||
provider 'keybase'
|
||||
provider_username { sequence(:provider_username) { |i| "#{Faker::Lorem.characters(15)}" } }
|
||||
token { sequence(:token) { |i| "#{i}#{Faker::Crypto.sha1()*2}"[0..65] } }
|
||||
verified false
|
||||
live false
|
||||
end
|
||||
6
spec/fabricators/assets/TEAPOT
Normal file
6
spec/fabricators/assets/TEAPOT
Normal file
@ -0,0 +1,6 @@
|
||||
This "Utah teapot" photograph is licensed under the Creative Commons
|
||||
Attribution-Share Alike 3.0 Unported license:
|
||||
https://creativecommons.org/licenses/by-sa/3.0/deed.en
|
||||
|
||||
Original source of work:
|
||||
https://commons.wikimedia.org/wiki/File:Utah_teapot_simple_2.png
|
||||
BIN
spec/fabricators/assets/utah_teapot.png
Normal file
BIN
spec/fabricators/assets/utah_teapot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
6
spec/fabricators/featured_tag_fabricator.rb
Normal file
6
spec/fabricators/featured_tag_fabricator.rb
Normal file
@ -0,0 +1,6 @@
|
||||
Fabricator(:featured_tag) do
|
||||
account
|
||||
tag
|
||||
statuses_count 1_337
|
||||
last_status_at Time.now.utc
|
||||
end
|
||||
8
spec/fabricators/poll_fabricator.rb
Normal file
8
spec/fabricators/poll_fabricator.rb
Normal file
@ -0,0 +1,8 @@
|
||||
Fabricator(:poll) do
|
||||
account
|
||||
status
|
||||
expires_at { 7.days.from_now }
|
||||
options %w(Foo Bar)
|
||||
multiple false
|
||||
hide_totals false
|
||||
end
|
||||
5
spec/fabricators/poll_vote_fabricator.rb
Normal file
5
spec/fabricators/poll_vote_fabricator.rb
Normal file
@ -0,0 +1,5 @@
|
||||
Fabricator(:poll_vote) do
|
||||
account
|
||||
poll
|
||||
choice 0
|
||||
end
|
||||
@ -1,2 +1,3 @@
|
||||
Fabricator(:site_upload) do
|
||||
file { File.open(File.join(Rails.root, 'spec', 'fabricators', 'assets', 'utah_teapot.png')) }
|
||||
end
|
||||
|
||||
4
spec/fabricators/user_invite_request_fabricator.rb
Normal file
4
spec/fabricators/user_invite_request_fabricator.rb
Normal file
@ -0,0 +1,4 @@
|
||||
Fabricator(:user_invite_request) do
|
||||
user
|
||||
text { Faker::Lorem.sentence }
|
||||
end
|
||||
4
spec/fixtures/files/mute-imports.txt
vendored
Normal file
4
spec/fixtures/files/mute-imports.txt
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
bob
|
||||
|
||||
eve@example.com
|
||||
|
||||
4
spec/fixtures/files/new-following-imports.txt
vendored
Normal file
4
spec/fixtures/files/new-following-imports.txt
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
Account address,Show boosts
|
||||
bob,true
|
||||
eve@example.com,false
|
||||
|
||||
4
spec/fixtures/files/new-mute-imports.txt
vendored
Normal file
4
spec/fixtures/files/new-mute-imports.txt
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
Account address,Hide notifications
|
||||
bob,true
|
||||
eve@example.com,false
|
||||
|
||||
272
spec/helpers/admin/action_log_helper_spec.rb
Normal file
272
spec/helpers/admin/action_log_helper_spec.rb
Normal file
@ -0,0 +1,272 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::ActionLogsHelper, type: :helper do
|
||||
klass = Class.new do
|
||||
include ActionView::Helpers
|
||||
include Admin::ActionLogsHelper
|
||||
end
|
||||
|
||||
let(:hoge) { klass.new }
|
||||
|
||||
describe '#log_target' do
|
||||
after do
|
||||
hoge.log_target(log)
|
||||
end
|
||||
|
||||
context 'log.target' do
|
||||
let(:log) { double(target: true) }
|
||||
|
||||
it 'calls linkable_log_target' do
|
||||
expect(hoge).to receive(:linkable_log_target).with(log.target)
|
||||
end
|
||||
end
|
||||
|
||||
context '!log.target' do
|
||||
let(:log) { double(target: false, target_type: :type, recorded_changes: :change) }
|
||||
|
||||
it 'calls log_target_from_history' do
|
||||
expect(hoge).to receive(:log_target_from_history).with(log.target_type, log.recorded_changes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#relevant_log_changes' do
|
||||
let(:log) { double(target_type: target_type, action: log_action, recorded_changes: recorded_changes) }
|
||||
let(:recorded_changes) { double }
|
||||
|
||||
after do
|
||||
hoge.relevant_log_changes(log)
|
||||
end
|
||||
|
||||
context "log.target_type == 'CustomEmoji' && [:enable, :disable, :destroy].include?(log.action)" do
|
||||
let(:target_type) { 'CustomEmoji' }
|
||||
let(:log_action) { :enable }
|
||||
|
||||
it "calls log.recorded_changes.slice('domain')" do
|
||||
expect(recorded_changes).to receive(:slice).with('domain')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'CustomEmoji' && log.action == :update" do
|
||||
let(:target_type) { 'CustomEmoji' }
|
||||
let(:log_action) { :update }
|
||||
|
||||
it "calls log.recorded_changes.slice('domain', 'visible_in_picker')" do
|
||||
expect(recorded_changes).to receive(:slice).with('domain', 'visible_in_picker')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'User' && [:promote, :demote].include?(log.action)" do
|
||||
let(:target_type) { 'User' }
|
||||
let(:log_action) { :promote }
|
||||
|
||||
it "calls log.recorded_changes.slice('moderator', 'admin')" do
|
||||
expect(recorded_changes).to receive(:slice).with('moderator', 'admin')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'User' && [:change_email].include?(log.action)" do
|
||||
let(:target_type) { 'User' }
|
||||
let(:log_action) { :change_email }
|
||||
|
||||
it "calls log.recorded_changes.slice('email', 'unconfirmed_email')" do
|
||||
expect(recorded_changes).to receive(:slice).with('email', 'unconfirmed_email')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'DomainBlock'" do
|
||||
let(:target_type) { 'DomainBlock' }
|
||||
let(:log_action) { nil }
|
||||
|
||||
it "calls log.recorded_changes.slice('severity', 'reject_media')" do
|
||||
expect(recorded_changes).to receive(:slice).with('severity', 'reject_media')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'Status' && log.action == :update" do
|
||||
let(:target_type) { 'Status' }
|
||||
let(:log_action) { :update }
|
||||
|
||||
it "log.recorded_changes.slice('sensitive')" do
|
||||
expect(recorded_changes).to receive(:slice).with('sensitive')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#log_extra_attributes' do
|
||||
after do
|
||||
hoge.log_extra_attributes(hoge: 'hoge')
|
||||
end
|
||||
|
||||
it "calls content_tag(:span, key, class: 'diff-key')" do
|
||||
allow(hoge).to receive(:log_change).with(anything)
|
||||
expect(hoge).to receive(:content_tag).with(:span, :hoge, class: 'diff-key')
|
||||
end
|
||||
|
||||
it 'calls safe_join twice' do
|
||||
expect(hoge).to receive(:safe_join).with(
|
||||
['<span class="diff-key">hoge</span>',
|
||||
'=',
|
||||
'<span class="diff-neutral">hoge</span>']
|
||||
)
|
||||
|
||||
expect(hoge).to receive(:safe_join).with([nil], ' ')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#log_change' do
|
||||
after do
|
||||
hoge.log_change(val)
|
||||
end
|
||||
|
||||
context '!val.is_a?(Array)' do
|
||||
let(:val) { 'hoge' }
|
||||
|
||||
it "calls content_tag(:span, val, class: 'diff-neutral')" do
|
||||
expect(hoge).to receive(:content_tag).with(:span, val, class: 'diff-neutral')
|
||||
end
|
||||
end
|
||||
|
||||
context 'val.is_a?(Array)' do
|
||||
let(:val) { %w(foo bar) }
|
||||
|
||||
it 'calls #content_tag twice and #safe_join' do
|
||||
expect(hoge).to receive(:content_tag).with(:span, 'foo', class: 'diff-old')
|
||||
expect(hoge).to receive(:content_tag).with(:span, 'bar', class: 'diff-new')
|
||||
expect(hoge).to receive(:safe_join).with([nil, nil], '→')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#icon_for_log' do
|
||||
subject { hoge.icon_for_log(log) }
|
||||
|
||||
context "log.target_type == 'Account'" do
|
||||
let(:log) { double(target_type: 'Account') }
|
||||
|
||||
it 'returns "user"' do
|
||||
expect(subject).to be 'user'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'User'" do
|
||||
let(:log) { double(target_type: 'User') }
|
||||
|
||||
it 'returns "user"' do
|
||||
expect(subject).to be 'user'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'CustomEmoji'" do
|
||||
let(:log) { double(target_type: 'CustomEmoji') }
|
||||
|
||||
it 'returns "file"' do
|
||||
expect(subject).to be 'file'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'Report'" do
|
||||
let(:log) { double(target_type: 'Report') }
|
||||
|
||||
it 'returns "flag"' do
|
||||
expect(subject).to be 'flag'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'DomainBlock'" do
|
||||
let(:log) { double(target_type: 'DomainBlock') }
|
||||
|
||||
it 'returns "lock"' do
|
||||
expect(subject).to be 'lock'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'EmailDomainBlock'" do
|
||||
let(:log) { double(target_type: 'EmailDomainBlock') }
|
||||
|
||||
it 'returns "envelope"' do
|
||||
expect(subject).to be 'envelope'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'Status'" do
|
||||
let(:log) { double(target_type: 'Status') }
|
||||
|
||||
it 'returns "pencil"' do
|
||||
expect(subject).to be 'pencil'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#class_for_log_icon' do
|
||||
subject { hoge.class_for_log_icon(log) }
|
||||
|
||||
%i(enable unsuspend unsilence confirm promote resolve).each do |action|
|
||||
context "log.action == #{action}" do
|
||||
let(:log) { double(action: action) }
|
||||
|
||||
it 'returns "positive"' do
|
||||
expect(subject).to be 'positive'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'log.action == :create' do
|
||||
context 'opposite_verbs?(log)' do
|
||||
let(:log) { double(action: :create, target_type: 'DomainBlock') }
|
||||
|
||||
it 'returns "negative"' do
|
||||
expect(subject).to be 'negative'
|
||||
end
|
||||
end
|
||||
|
||||
context '!opposite_verbs?(log)' do
|
||||
let(:log) { double(action: :create, target_type: '') }
|
||||
|
||||
it 'returns "positive"' do
|
||||
expect(subject).to be 'positive'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%i(update reset_password disable_2fa memorialize change_email).each do |action|
|
||||
context "log.action == #{action}" do
|
||||
let(:log) { double(action: action) }
|
||||
|
||||
it 'returns "neutral"' do
|
||||
expect(subject).to be 'neutral'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%i(demote silence disable suspend remove_avatar remove_header reopen).each do |action|
|
||||
context "log.action == #{action}" do
|
||||
let(:log) { double(action: action) }
|
||||
|
||||
it 'returns "negative"' do
|
||||
expect(subject).to be 'negative'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'log.action == :destroy' do
|
||||
context 'opposite_verbs?(log)' do
|
||||
let(:log) { double(action: :destroy, target_type: 'DomainBlock') }
|
||||
|
||||
it 'returns "positive"' do
|
||||
expect(subject).to be 'positive'
|
||||
end
|
||||
end
|
||||
|
||||
context '!opposite_verbs?(log)' do
|
||||
let(:log) { double(action: :destroy, target_type: '') }
|
||||
|
||||
it 'returns "negative"' do
|
||||
expect(subject).to be 'negative'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -69,7 +69,7 @@ describe ApplicationHelper do
|
||||
describe 'open_registrations?' do
|
||||
it 'returns true when open for registrations' do
|
||||
without_partial_double_verification do
|
||||
expect(Setting).to receive(:open_registrations).and_return(true)
|
||||
expect(Setting).to receive(:registrations_mode).and_return('open')
|
||||
end
|
||||
|
||||
expect(helper.open_registrations?).to eq true
|
||||
@ -77,7 +77,7 @@ describe ApplicationHelper do
|
||||
|
||||
it 'returns false when closed for registrations' do
|
||||
without_partial_double_verification do
|
||||
expect(Setting).to receive(:open_registrations).and_return(false)
|
||||
expect(Setting).to receive(:registrations_mode).and_return('none')
|
||||
end
|
||||
|
||||
expect(helper.open_registrations?).to eq false
|
||||
|
||||
@ -12,6 +12,7 @@ RSpec.describe ActivityPub::Activity::Announce do
|
||||
type: 'Announce',
|
||||
actor: 'https://example.com/actor',
|
||||
object: object_json,
|
||||
to: 'http://example.com/followers',
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::Activity::Create do
|
||||
let(:sender) { Fabricate(:account, followers_url: 'http://example.com/followers') }
|
||||
let(:sender) { Fabricate(:account, followers_url: 'http://example.com/followers', domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
|
||||
let(:json) do
|
||||
{
|
||||
@ -28,6 +28,20 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||
subject.perform
|
||||
end
|
||||
|
||||
context 'unknown object type' do
|
||||
let(:object_json) do
|
||||
{
|
||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||
type: 'Banana',
|
||||
content: 'Lorem ipsum',
|
||||
}
|
||||
end
|
||||
|
||||
it 'does not create a status' do
|
||||
expect(sender.statuses.count).to be_zero
|
||||
end
|
||||
end
|
||||
|
||||
context 'standalone' do
|
||||
let(:object_json) do
|
||||
{
|
||||
@ -407,6 +421,89 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||
expect(status).to_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'with poll' do
|
||||
let(:object_json) do
|
||||
{
|
||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||
type: 'Question',
|
||||
content: 'Which color was the submarine?',
|
||||
oneOf: [
|
||||
{
|
||||
name: 'Yellow',
|
||||
replies: {
|
||||
type: 'Collection',
|
||||
totalItems: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Blue',
|
||||
replies: {
|
||||
type: 'Collection',
|
||||
totalItems: 3,
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates status' do
|
||||
status = sender.statuses.first
|
||||
expect(status).to_not be_nil
|
||||
expect(status.poll).to_not be_nil
|
||||
end
|
||||
|
||||
it 'creates a poll' do
|
||||
poll = sender.polls.first
|
||||
expect(poll).to_not be_nil
|
||||
expect(poll.status).to_not be_nil
|
||||
expect(poll.options).to eq %w(Yellow Blue)
|
||||
expect(poll.cached_tallies).to eq [10, 3]
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a vote to a local poll' do
|
||||
let(:poll) { Fabricate(:poll, options: %w(Yellow Blue)) }
|
||||
let!(:local_status) { Fabricate(:status, poll: poll) }
|
||||
|
||||
let(:object_json) do
|
||||
{
|
||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||
type: 'Note',
|
||||
name: 'Yellow',
|
||||
inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status)
|
||||
}
|
||||
end
|
||||
|
||||
it 'adds a vote to the poll with correct uri' do
|
||||
vote = poll.votes.first
|
||||
expect(vote).to_not be_nil
|
||||
expect(vote.uri).to eq object_json[:id]
|
||||
expect(poll.reload.cached_tallies).to eq [1, 0]
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a vote to an expired local poll' do
|
||||
let(:poll) do
|
||||
poll = Fabricate.build(:poll, options: %w(Yellow Blue), expires_at: 1.day.ago)
|
||||
poll.save(validate: false)
|
||||
poll
|
||||
end
|
||||
let!(:local_status) { Fabricate(:status, poll: poll) }
|
||||
|
||||
let(:object_json) do
|
||||
{
|
||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||
type: 'Note',
|
||||
name: 'Yellow',
|
||||
inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status)
|
||||
}
|
||||
end
|
||||
|
||||
it 'does not add a vote to the poll' do
|
||||
expect(poll.votes.first).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when sender is followed by local users' do
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::Activity::Flag do
|
||||
let(:sender) { Fabricate(:account, domain: 'example.com') }
|
||||
let(:sender) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }
|
||||
let(:flagged) { Fabricate(:account) }
|
||||
let(:status) { Fabricate(:status, account: flagged, uri: 'foobar') }
|
||||
let(:flag_id) { nil }
|
||||
|
||||
let(:json) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: nil,
|
||||
id: flag_id,
|
||||
type: 'Flag',
|
||||
content: 'Boo!!',
|
||||
actor: ActivityPub::TagManager.instance.uri_for(sender),
|
||||
@ -34,4 +35,22 @@ RSpec.describe ActivityPub::Activity::Flag do
|
||||
expect(report.status_ids).to eq [status.id]
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform with a defined uri' do
|
||||
subject { described_class.new(json, sender) }
|
||||
let (:flag_id) { 'http://example.com/reports/1' }
|
||||
|
||||
before do
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'creates a report' do
|
||||
report = Report.find_by(account: sender, target_account: flagged)
|
||||
|
||||
expect(report).to_not be_nil
|
||||
expect(report.comment).to eq 'Boo!!'
|
||||
expect(report.status_ids).to eq [status.id]
|
||||
expect(report.uri).to eq flag_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
88
spec/lib/activitypub/adapter_spec.rb
Normal file
88
spec/lib/activitypub/adapter_spec.rb
Normal file
@ -0,0 +1,88 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::Adapter do
|
||||
class TestObject < ActiveModelSerializers::Model
|
||||
attributes :foo
|
||||
end
|
||||
|
||||
class TestWithBasicContextSerializer < ActivityPub::Serializer
|
||||
attributes :foo
|
||||
end
|
||||
|
||||
class TestWithNamedContextSerializer < ActivityPub::Serializer
|
||||
context :security
|
||||
attributes :foo
|
||||
end
|
||||
|
||||
class TestWithNestedNamedContextSerializer < ActivityPub::Serializer
|
||||
attributes :foo
|
||||
|
||||
has_one :virtual_object, key: :baz, serializer: TestWithNamedContextSerializer
|
||||
|
||||
def virtual_object
|
||||
object
|
||||
end
|
||||
end
|
||||
|
||||
class TestWithContextExtensionSerializer < ActivityPub::Serializer
|
||||
context_extensions :sensitive
|
||||
attributes :foo
|
||||
end
|
||||
|
||||
class TestWithNestedContextExtensionSerializer < ActivityPub::Serializer
|
||||
context_extensions :manually_approves_followers
|
||||
attributes :foo
|
||||
|
||||
has_one :virtual_object, key: :baz, serializer: TestWithContextExtensionSerializer
|
||||
|
||||
def virtual_object
|
||||
object
|
||||
end
|
||||
end
|
||||
|
||||
describe '#serializable_hash' do
|
||||
let(:serializer_class) {}
|
||||
|
||||
subject { ActiveModelSerializers::SerializableResource.new(TestObject.new(foo: 'bar'), serializer: serializer_class, adapter: described_class).as_json }
|
||||
|
||||
context 'when serializer defines no context' do
|
||||
let(:serializer_class) { TestWithBasicContextSerializer }
|
||||
|
||||
it 'renders a basic @context' do
|
||||
expect(subject).to include({ '@context' => 'https://www.w3.org/ns/activitystreams' })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when serializer defines a named context' do
|
||||
let(:serializer_class) { TestWithNamedContextSerializer }
|
||||
|
||||
it 'renders a @context with both items' do
|
||||
expect(subject).to include({ '@context' => ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when serializer has children that define a named context' do
|
||||
let(:serializer_class) { TestWithNestedNamedContextSerializer }
|
||||
|
||||
it 'renders a @context with both items' do
|
||||
expect(subject).to include({ '@context' => ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when serializer defines context extensions' do
|
||||
let(:serializer_class) { TestWithContextExtensionSerializer }
|
||||
|
||||
it 'renders a @context with the extension' do
|
||||
expect(subject).to include({ '@context' => ['https://www.w3.org/ns/activitystreams', { 'sensitive' => 'as:sensitive' }] })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when serializer has children that define context extensions' do
|
||||
let(:serializer_class) { TestWithNestedContextExtensionSerializer }
|
||||
|
||||
it 'renders a @context with both extensions' do
|
||||
expect(subject).to include({ '@context' => ['https://www.w3.org/ns/activitystreams', { 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', 'sensitive' => 'as:sensitive' }] })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -106,11 +106,11 @@ describe LanguageDetector do
|
||||
end
|
||||
|
||||
describe 'remote user' do
|
||||
it 'nil for foreign user when language is not present' do
|
||||
it 'detects Korean language' do
|
||||
string = '안녕하세요'
|
||||
result = described_class.instance.detect(string, account_remote)
|
||||
|
||||
expect(result).to eq nil
|
||||
expect(result).to eq :ko
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
82
spec/lib/proof_provider/keybase/verifier_spec.rb
Normal file
82
spec/lib/proof_provider/keybase/verifier_spec.rb
Normal file
@ -0,0 +1,82 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe ProofProvider::Keybase::Verifier do
|
||||
let(:my_domain) { Rails.configuration.x.local_domain }
|
||||
|
||||
let(:keybase_proof) do
|
||||
local_proof = AccountIdentityProof.new(
|
||||
provider: 'Keybase',
|
||||
provider_username: 'cryptoalice',
|
||||
token: '11111111111111111111111111'
|
||||
)
|
||||
|
||||
described_class.new('alice', 'cryptoalice', '11111111111111111111111111', my_domain)
|
||||
end
|
||||
|
||||
let(:query_params) do
|
||||
"domain=#{my_domain}&kb_username=cryptoalice&sig_hash=11111111111111111111111111&username=alice"
|
||||
end
|
||||
|
||||
describe '#valid?' do
|
||||
let(:base_url) { 'https://keybase.io/_/api/1.0/sig/proof_valid.json' }
|
||||
|
||||
context 'when valid' do
|
||||
before do
|
||||
json_response_body = '{"status":{"code":0,"name":"OK"},"proof_valid":true}'
|
||||
stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
|
||||
end
|
||||
|
||||
it 'calls out to keybase and returns true' do
|
||||
expect(keybase_proof.valid?).to eq true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when invalid' do
|
||||
before do
|
||||
json_response_body = '{"status":{"code":0,"name":"OK"},"proof_valid":false}'
|
||||
stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
|
||||
end
|
||||
|
||||
it 'calls out to keybase and returns false' do
|
||||
expect(keybase_proof.valid?).to eq false
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an unexpected api response' do
|
||||
before do
|
||||
json_response_body = '{"status":{"code":100,"desc":"wrong size hex_id","fields":{"sig_hash":"wrong size hex_id"},"name":"INPUT_ERROR"}}'
|
||||
stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
|
||||
end
|
||||
|
||||
it 'swallows the error and returns false' do
|
||||
expect(keybase_proof.valid?).to eq false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#status' do
|
||||
let(:base_url) { 'https://keybase.io/_/api/1.0/sig/proof_live.json' }
|
||||
|
||||
context 'with a normal response' do
|
||||
before do
|
||||
json_response_body = '{"status":{"code":0,"name":"OK"},"proof_live":false,"proof_valid":true}'
|
||||
stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
|
||||
end
|
||||
|
||||
it 'calls out to keybase and returns the status fields as proof_valid and proof_live' do
|
||||
expect(keybase_proof.status).to include({ 'proof_valid' => true, 'proof_live' => false })
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an unexpected keybase response' do
|
||||
before do
|
||||
json_response_body = '{"status":{"code":100,"desc":"missing non-optional field sig_hash","fields":{"sig_hash":"missing non-optional field sig_hash"},"name":"INPUT_ERROR"}}'
|
||||
stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
|
||||
end
|
||||
|
||||
it 'raises a ProofProvider::Keybase::UnexpectedResponseError' do
|
||||
expect { keybase_proof.status }.to raise_error ProofProvider::Keybase::UnexpectedResponseError
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
8
spec/mailers/previews/admin_mailer_preview.rb
Normal file
8
spec/mailers/previews/admin_mailer_preview.rb
Normal file
@ -0,0 +1,8 @@
|
||||
# Preview all emails at http://localhost:3000/rails/mailers/admin_mailer
|
||||
|
||||
class AdminMailerPreview < ActionMailer::Preview
|
||||
# Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_pending_account
|
||||
def new_pending_account
|
||||
AdminMailer.new_pending_account(Account.first, User.pending.first)
|
||||
end
|
||||
end
|
||||
@ -558,6 +558,11 @@ RSpec.describe Account, type: :model do
|
||||
expect(account).to model_have_error_on_field(:username)
|
||||
end
|
||||
|
||||
it 'squishes the username before validation' do
|
||||
account = Fabricate(:account, domain: nil, username: " \u3000bob \t \u00a0 \n ")
|
||||
expect(account.username).to eq 'bob'
|
||||
end
|
||||
|
||||
context 'when is local' do
|
||||
it 'is invalid if the username is not unique in case-insensitive comparison among local accounts' do
|
||||
account_1 = Fabricate(:account, username: 'the_doctor')
|
||||
|
||||
@ -237,9 +237,9 @@ describe AccountInteractions do
|
||||
end
|
||||
|
||||
describe '#block_domain!' do
|
||||
let(:domain_block) { Fabricate(:domain_block) }
|
||||
let(:domain) { 'example.com' }
|
||||
|
||||
subject { account.block_domain!(domain_block) }
|
||||
subject { account.block_domain!(domain) }
|
||||
|
||||
it 'creates and returns AccountDomainBlock' do
|
||||
expect do
|
||||
|
||||
@ -21,20 +21,22 @@ describe Export do
|
||||
target_accounts.each(&account.method(:mute!))
|
||||
|
||||
export = Export.new(account).to_muted_accounts_csv
|
||||
results = export.strip.split
|
||||
results = export.strip.split("\n")
|
||||
|
||||
expect(results.size).to eq 2
|
||||
expect(results.first).to eq 'one@local.host'
|
||||
expect(results.size).to eq 3
|
||||
expect(results.first).to eq 'Account address,Hide notifications'
|
||||
expect(results.second).to eq 'one@local.host,true'
|
||||
end
|
||||
|
||||
it 'returns a csv of the following accounts' do
|
||||
target_accounts.each(&account.method(:follow!))
|
||||
|
||||
export = Export.new(account).to_following_accounts_csv
|
||||
results = export.strip.split
|
||||
results = export.strip.split("\n")
|
||||
|
||||
expect(results.size).to eq 2
|
||||
expect(results.first).to eq 'one@local.host'
|
||||
expect(results.size).to eq 3
|
||||
expect(results.first).to eq 'Account address,Show boosts'
|
||||
expect(results.second).to eq 'one@local.host,true'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
4
spec/models/featured_tag_spec.rb
Normal file
4
spec/models/featured_tag_spec.rb
Normal file
@ -0,0 +1,4 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe FeaturedTag, type: :model do
|
||||
end
|
||||
5
spec/models/poll_spec.rb
Normal file
5
spec/models/poll_spec.rb
Normal file
@ -0,0 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Poll, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
||||
5
spec/models/poll_vote_spec.rb
Normal file
5
spec/models/poll_vote_spec.rb
Normal file
@ -0,0 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe PollVote, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
||||
4
spec/models/user_invite_request_spec.rb
Normal file
4
spec/models/user_invite_request_spec.rb
Normal file
@ -0,0 +1,4 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UserInviteRequest, type: :model do
|
||||
end
|
||||
@ -31,34 +31,6 @@ describe InstancePresenter do
|
||||
end
|
||||
end
|
||||
|
||||
context do
|
||||
around do |example|
|
||||
open_registrations = Setting.open_registrations
|
||||
example.run
|
||||
Setting.open_registrations = open_registrations
|
||||
end
|
||||
|
||||
it "delegates open_registrations to Setting" do
|
||||
Setting.open_registrations = false
|
||||
|
||||
expect(instance_presenter.open_registrations).to eq false
|
||||
end
|
||||
end
|
||||
|
||||
context do
|
||||
around do |example|
|
||||
closed_registrations_message = Setting.closed_registrations_message
|
||||
example.run
|
||||
Setting.closed_registrations_message = closed_registrations_message
|
||||
end
|
||||
|
||||
it "delegates closed_registrations_message to Setting" do
|
||||
Setting.closed_registrations_message = "Closed message"
|
||||
|
||||
expect(instance_presenter.closed_registrations_message).to eq "Closed message"
|
||||
end
|
||||
end
|
||||
|
||||
context do
|
||||
around do |example|
|
||||
site_contact_email = Setting.site_contact_email
|
||||
|
||||
@ -11,8 +11,9 @@ describe 'Localization' do
|
||||
headers = { 'Accept-Language' => 'zh-HK' }
|
||||
|
||||
get "/about", headers: headers
|
||||
|
||||
expect(response.body).to include(
|
||||
I18n.t('about.about_mastodon_html', locale: 'zh-HK')
|
||||
I18n.t('about.tagline', locale: 'zh-HK')
|
||||
)
|
||||
end
|
||||
|
||||
@ -20,16 +21,18 @@ describe 'Localization' do
|
||||
headers = { 'Accept-Language' => 'es-FAKE' }
|
||||
|
||||
get "/about", headers: headers
|
||||
|
||||
expect(response.body).to include(
|
||||
I18n.t('about.about_mastodon_html', locale: 'es')
|
||||
I18n.t('about.tagline', locale: 'es')
|
||||
)
|
||||
end
|
||||
it 'falls back to english when locale is missing' do
|
||||
headers = { 'Accept-Language' => '12-FAKE' }
|
||||
|
||||
get "/about", headers: headers
|
||||
|
||||
expect(response.body).to include(
|
||||
I18n.t('about.about_mastodon_html', locale: 'en')
|
||||
I18n.t('about.tagline', locale: 'en')
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
44
spec/serializers/activitypub/note_spec.rb
Normal file
44
spec/serializers/activitypub/note_spec.rb
Normal file
@ -0,0 +1,44 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ActivityPub::NoteSerializer do
|
||||
let!(:account) { Fabricate(:account) }
|
||||
let!(:other) { Fabricate(:account) }
|
||||
let!(:parent) { Fabricate(:status, account: account, visibility: :public) }
|
||||
let!(:reply1) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
|
||||
let!(:reply2) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
|
||||
let!(:reply3) { Fabricate(:status, account: other, thread: parent, visibility: :public) }
|
||||
let!(:reply4) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
|
||||
let!(:reply5) { Fabricate(:status, account: account, thread: parent, visibility: :direct) }
|
||||
|
||||
before(:each) do
|
||||
@serialization = ActiveModelSerializers::SerializableResource.new(parent, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter)
|
||||
end
|
||||
|
||||
subject { JSON.parse(@serialization.to_json) }
|
||||
|
||||
it 'has a Note type' do
|
||||
expect(subject['type']).to eql('Note')
|
||||
end
|
||||
|
||||
it 'has a replies collection' do
|
||||
expect(subject['replies']['type']).to eql('Collection')
|
||||
end
|
||||
|
||||
it 'has a replies collection with a first Page' do
|
||||
expect(subject['replies']['first']['type']).to eql('CollectionPage')
|
||||
end
|
||||
|
||||
it 'includes public self-replies in its replies collection' do
|
||||
expect(subject['replies']['first']['items']).to include(reply1.uri, reply2.uri, reply4.uri)
|
||||
end
|
||||
|
||||
it 'does not include replies from others in its replies collection' do
|
||||
expect(subject['replies']['first']['items']).to_not include(reply3.uri)
|
||||
end
|
||||
|
||||
it 'does not include replies with direct visibility in its replies collection' do
|
||||
expect(subject['replies']['first']['items']).to_not include(reply5.uri)
|
||||
end
|
||||
end
|
||||
@ -4,18 +4,18 @@ describe AccountSearchService, type: :service do
|
||||
describe '.call' do
|
||||
describe 'with a query to ignore' do
|
||||
it 'returns empty array for missing query' do
|
||||
results = subject.call('', 10)
|
||||
results = subject.call('', nil, limit: 10)
|
||||
|
||||
expect(results).to eq []
|
||||
end
|
||||
it 'returns empty array for hashtag query' do
|
||||
results = subject.call('#tag', 10)
|
||||
results = subject.call('#tag', nil, limit: 10)
|
||||
|
||||
expect(results).to eq []
|
||||
end
|
||||
it 'returns empty array for limit zero' do
|
||||
Fabricate(:account, username: 'match')
|
||||
results = subject.call('match', 0)
|
||||
results = subject.call('match', nil, limit: 0)
|
||||
|
||||
expect(results).to eq []
|
||||
end
|
||||
@ -25,7 +25,7 @@ describe AccountSearchService, type: :service do
|
||||
it 'does not return a nil entry in the array for the exact match' do
|
||||
match = Fabricate(:account, username: 'matchingusername')
|
||||
|
||||
results = subject.call('match', 5)
|
||||
results = subject.call('match', nil, limit: 5)
|
||||
expect(results).to eq [match]
|
||||
end
|
||||
end
|
||||
@ -35,7 +35,7 @@ describe AccountSearchService, type: :service do
|
||||
before do
|
||||
allow(Account).to receive(:find_local)
|
||||
allow(Account).to receive(:search_for)
|
||||
subject.call('@', 10)
|
||||
subject.call('@', nil, limit: 10)
|
||||
end
|
||||
|
||||
it 'uses find_local with empty query to look for local accounts' do
|
||||
@ -47,7 +47,7 @@ describe AccountSearchService, type: :service do
|
||||
before do
|
||||
allow(Account).to receive(:find_local)
|
||||
allow(Account).to receive(:search_for)
|
||||
subject.call('one', 10)
|
||||
subject.call('one', nil, limit: 10)
|
||||
end
|
||||
|
||||
it 'uses find_local to look for local accounts' do
|
||||
@ -55,7 +55,7 @@ describe AccountSearchService, type: :service do
|
||||
end
|
||||
|
||||
it 'uses search_for to find matches' do
|
||||
expect(Account).to have_received(:search_for).with('one', 10)
|
||||
expect(Account).to have_received(:search_for).with('one', 10, 0)
|
||||
end
|
||||
end
|
||||
|
||||
@ -65,16 +65,16 @@ describe AccountSearchService, type: :service do
|
||||
end
|
||||
|
||||
it 'uses find_remote to look for remote accounts' do
|
||||
subject.call('two@example.com', 10)
|
||||
subject.call('two@example.com', nil, limit: 10)
|
||||
expect(Account).to have_received(:find_remote).with('two', 'example.com')
|
||||
end
|
||||
|
||||
describe 'and there is no account provided' do
|
||||
it 'uses search_for to find matches' do
|
||||
allow(Account).to receive(:search_for)
|
||||
subject.call('two@example.com', 10, nil, resolve: false)
|
||||
subject.call('two@example.com', nil, limit: 10, resolve: false)
|
||||
|
||||
expect(Account).to have_received(:search_for).with('two example.com', 10)
|
||||
expect(Account).to have_received(:search_for).with('two example.com', 10, 0)
|
||||
end
|
||||
end
|
||||
|
||||
@ -82,9 +82,9 @@ describe AccountSearchService, type: :service do
|
||||
it 'uses advanced_search_for to find matches' do
|
||||
account = Fabricate(:account)
|
||||
allow(Account).to receive(:advanced_search_for)
|
||||
subject.call('two@example.com', 10, account, resolve: false)
|
||||
subject.call('two@example.com', account, limit: 10, resolve: false)
|
||||
|
||||
expect(Account).to have_received(:advanced_search_for).with('two example.com', account, 10, nil)
|
||||
expect(Account).to have_received(:advanced_search_for).with('two example.com', account, 10, nil, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -95,7 +95,7 @@ describe AccountSearchService, type: :service do
|
||||
partial = Fabricate(:account, username: 'exactness')
|
||||
exact = Fabricate(:account, username: 'exact')
|
||||
|
||||
results = subject.call('exact', 10)
|
||||
results = subject.call('exact', nil, limit: 10)
|
||||
expect(results.size).to eq 2
|
||||
expect(results).to eq [exact, partial]
|
||||
end
|
||||
@ -114,7 +114,7 @@ describe AccountSearchService, type: :service do
|
||||
exact = Fabricate(:account, username: 'e')
|
||||
Rails.configuration.x.local_domain = 'example.com'
|
||||
|
||||
results = subject.call('e@example.com', 2)
|
||||
results = subject.call('e@example.com', nil, limit: 2)
|
||||
expect(results.size).to eq 2
|
||||
expect(results).to eq([exact, remote]).or eq([exact, remote_too])
|
||||
end
|
||||
@ -125,7 +125,7 @@ describe AccountSearchService, type: :service do
|
||||
service = double(call: nil)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(service)
|
||||
|
||||
results = subject.call('newuser@remote.com', 10, nil, resolve: true)
|
||||
results = subject.call('newuser@remote.com', nil, limit: 10, resolve: true)
|
||||
expect(service).to have_received(:call).with('newuser@remote.com')
|
||||
end
|
||||
|
||||
@ -133,7 +133,7 @@ describe AccountSearchService, type: :service do
|
||||
service = double(call: nil)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(service)
|
||||
|
||||
results = subject.call('newuser@remote.com', 10, nil, resolve: false)
|
||||
results = subject.call('newuser@remote.com', nil, limit: 10, resolve: false)
|
||||
expect(service).not_to have_received(:call)
|
||||
end
|
||||
end
|
||||
@ -143,7 +143,7 @@ describe AccountSearchService, type: :service do
|
||||
partial = Fabricate(:account, username: 'exactness')
|
||||
exact = Fabricate(:account, username: 'exact', suspended: true)
|
||||
|
||||
results = subject.call('exact', 10)
|
||||
results = subject.call('exact', nil, limit: 10)
|
||||
expect(results.size).to eq 1
|
||||
expect(results).to eq [partial]
|
||||
end
|
||||
@ -151,7 +151,7 @@ describe AccountSearchService, type: :service do
|
||||
it "does not return suspended remote accounts" do
|
||||
remote = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true)
|
||||
|
||||
results = subject.call('a@example.com', 2)
|
||||
results = subject.call('a@example.com', nil, limit: 2)
|
||||
expect(results.size).to eq 0
|
||||
expect(results).to eq []
|
||||
end
|
||||
|
||||
122
spec/services/activitypub/fetch_replies_service_spec.rb
Normal file
122
spec/services/activitypub/fetch_replies_service_spec.rb
Normal file
@ -0,0 +1,122 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::FetchRepliesService, type: :service do
|
||||
let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }
|
||||
let(:status) { Fabricate(:status, account: actor) }
|
||||
let(:collection_uri) { 'http://example.com/replies/1' }
|
||||
|
||||
let(:items) do
|
||||
[
|
||||
'http://example.com/self-reply-1',
|
||||
'http://example.com/self-reply-2',
|
||||
'http://example.com/self-reply-3',
|
||||
'http://other.com/other-reply-1',
|
||||
'http://other.com/other-reply-2',
|
||||
'http://other.com/other-reply-3',
|
||||
'http://example.com/self-reply-4',
|
||||
'http://example.com/self-reply-5',
|
||||
'http://example.com/self-reply-6',
|
||||
]
|
||||
end
|
||||
|
||||
let(:payload) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'Collection',
|
||||
id: collection_uri,
|
||||
items: items,
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
describe '#call' do
|
||||
context 'when the payload is a Collection with inlined replies' do
|
||||
context 'when passing the collection itself' do
|
||||
it 'spawns workers for up to 5 replies on the same server' do
|
||||
allow(FetchReplyWorker).to receive(:push_bulk)
|
||||
subject.call(status, payload)
|
||||
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passing the URL to the collection' do
|
||||
before do
|
||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
|
||||
end
|
||||
|
||||
it 'spawns workers for up to 5 replies on the same server' do
|
||||
allow(FetchReplyWorker).to receive(:push_bulk)
|
||||
subject.call(status, collection_uri)
|
||||
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the payload is an OrderedCollection with inlined replies' do
|
||||
let(:payload) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'OrderedCollection',
|
||||
id: collection_uri,
|
||||
orderedItems: items,
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
context 'when passing the collection itself' do
|
||||
it 'spawns workers for up to 5 replies on the same server' do
|
||||
allow(FetchReplyWorker).to receive(:push_bulk)
|
||||
subject.call(status, payload)
|
||||
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passing the URL to the collection' do
|
||||
before do
|
||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
|
||||
end
|
||||
|
||||
it 'spawns workers for up to 5 replies on the same server' do
|
||||
allow(FetchReplyWorker).to receive(:push_bulk)
|
||||
subject.call(status, collection_uri)
|
||||
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the payload is a paginated Collection with inlined replies' do
|
||||
let(:payload) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'Collection',
|
||||
id: collection_uri,
|
||||
first: {
|
||||
type: 'CollectionPage',
|
||||
partOf: collection_uri,
|
||||
items: items,
|
||||
}
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
context 'when passing the collection itself' do
|
||||
it 'spawns workers for up to 5 replies on the same server' do
|
||||
allow(FetchReplyWorker).to receive(:push_bulk)
|
||||
subject.call(status, payload)
|
||||
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passing the URL to the collection' do
|
||||
before do
|
||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
|
||||
end
|
||||
|
||||
it 'spawns workers for up to 5 replies on the same server' do
|
||||
allow(FetchReplyWorker).to receive(:push_bulk)
|
||||
subject.call(status, collection_uri)
|
||||
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -28,4 +28,49 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
|
||||
expect(account.fields[1].value).to eq 'Unit test'
|
||||
end
|
||||
end
|
||||
|
||||
context 'identity proofs' do
|
||||
let(:payload) do
|
||||
{
|
||||
id: 'https://foo.test',
|
||||
type: 'Actor',
|
||||
inbox: 'https://foo.test/inbox',
|
||||
attachment: [
|
||||
{ type: 'IdentityProof', name: 'Alice', signatureAlgorithm: 'keybase', signatureValue: 'a' * 66 },
|
||||
],
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
it 'parses out of attachment' do
|
||||
allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
|
||||
|
||||
account = subject.call('alice', 'example.com', payload)
|
||||
|
||||
expect(account.identity_proofs.count).to eq 1
|
||||
|
||||
proof = account.identity_proofs.first
|
||||
|
||||
expect(proof.provider).to eq 'keybase'
|
||||
expect(proof.provider_username).to eq 'Alice'
|
||||
expect(proof.token).to eq 'a' * 66
|
||||
end
|
||||
|
||||
it 'removes no longer present proofs' do
|
||||
allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
|
||||
|
||||
account = Fabricate(:account, username: 'alice', domain: 'example.com')
|
||||
old_proof = Fabricate(:account_identity_proof, account: account, provider: 'keybase', provider_username: 'Bob', token: 'b' * 66)
|
||||
|
||||
subject.call('alice', 'example.com', payload)
|
||||
|
||||
expect(account.identity_proofs.count).to eq 1
|
||||
expect(account.identity_proofs.find_by(id: old_proof.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'queues a validity check on the proof' do
|
||||
allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
|
||||
account = subject.call('alice', 'example.com', payload)
|
||||
expect(ProofProvider::Keybase::Worker).to have_received(:perform_async)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -8,8 +8,10 @@ RSpec.describe AppSignUpService, type: :service do
|
||||
|
||||
describe '#call' do
|
||||
it 'returns nil when registrations are closed' do
|
||||
Setting.open_registrations = false
|
||||
tmp = Setting.registrations_mode
|
||||
Setting.registrations_mode = 'none'
|
||||
expect(subject.call(app, good_params)).to be_nil
|
||||
Setting.registrations_mode = tmp
|
||||
end
|
||||
|
||||
it 'raises an error when params are missing' do
|
||||
|
||||
169
spec/services/import_service_spec.rb
Normal file
169
spec/services/import_service_spec.rb
Normal file
@ -0,0 +1,169 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ImportService, type: :service do
|
||||
let!(:account) { Fabricate(:account, locked: false) }
|
||||
let!(:bob) { Fabricate(:account, username: 'bob', locked: false) }
|
||||
let!(:eve) { Fabricate(:account, username: 'eve', domain: 'example.com', locked: false) }
|
||||
|
||||
context 'import old-style list of muted users' do
|
||||
subject { ImportService.new }
|
||||
|
||||
let(:csv) { attachment_fixture('mute-imports.txt') }
|
||||
|
||||
describe 'when no accounts are muted' do
|
||||
let(:import) { Import.create(account: account, type: 'muting', data: csv) }
|
||||
it 'mutes the listed accounts, including notifications' do
|
||||
subject.call(import)
|
||||
expect(account.muting.count).to eq 2
|
||||
expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when some accounts are muted and overwrite is not set' do
|
||||
let(:import) { Import.create(account: account, type: 'muting', data: csv) }
|
||||
|
||||
it 'mutes the listed accounts, including notifications' do
|
||||
account.mute!(bob, notifications: false)
|
||||
subject.call(import)
|
||||
expect(account.muting.count).to eq 2
|
||||
expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when some accounts are muted and overwrite is set' do
|
||||
let(:import) { Import.create(account: account, type: 'muting', data: csv, overwrite: true) }
|
||||
|
||||
it 'mutes the listed accounts, including notifications' do
|
||||
account.mute!(bob, notifications: false)
|
||||
subject.call(import)
|
||||
expect(account.muting.count).to eq 2
|
||||
expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'import new-style list of muted users' do
|
||||
subject { ImportService.new }
|
||||
|
||||
let(:csv) { attachment_fixture('new-mute-imports.txt') }
|
||||
|
||||
describe 'when no accounts are muted' do
|
||||
let(:import) { Import.create(account: account, type: 'muting', data: csv) }
|
||||
it 'mutes the listed accounts, respecting notifications' do
|
||||
subject.call(import)
|
||||
expect(account.muting.count).to eq 2
|
||||
expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true
|
||||
expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when some accounts are muted and overwrite is not set' do
|
||||
let(:import) { Import.create(account: account, type: 'muting', data: csv) }
|
||||
|
||||
it 'mutes the listed accounts, respecting notifications' do
|
||||
account.mute!(bob, notifications: true)
|
||||
subject.call(import)
|
||||
expect(account.muting.count).to eq 2
|
||||
expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true
|
||||
expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when some accounts are muted and overwrite is set' do
|
||||
let(:import) { Import.create(account: account, type: 'muting', data: csv, overwrite: true) }
|
||||
|
||||
it 'mutes the listed accounts, respecting notifications' do
|
||||
account.mute!(bob, notifications: true)
|
||||
subject.call(import)
|
||||
expect(account.muting.count).to eq 2
|
||||
expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true
|
||||
expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'import old-style list of followed users' do
|
||||
subject { ImportService.new }
|
||||
|
||||
let(:csv) { attachment_fixture('mute-imports.txt') }
|
||||
|
||||
before do
|
||||
allow(NotificationWorker).to receive(:perform_async)
|
||||
end
|
||||
|
||||
describe 'when no accounts are followed' do
|
||||
let(:import) { Import.create(account: account, type: 'following', data: csv) }
|
||||
it 'follows the listed accounts, including boosts' do
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when some accounts are already followed and overwrite is not set' do
|
||||
let(:import) { Import.create(account: account, type: 'following', data: csv) }
|
||||
|
||||
it 'follows the listed accounts, including notifications' do
|
||||
account.follow!(bob, reblogs: false)
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when some accounts are already followed and overwrite is set' do
|
||||
let(:import) { Import.create(account: account, type: 'following', data: csv, overwrite: true) }
|
||||
|
||||
it 'mutes the listed accounts, including notifications' do
|
||||
account.follow!(bob, reblogs: false)
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'import new-style list of followed users' do
|
||||
subject { ImportService.new }
|
||||
|
||||
let(:csv) { attachment_fixture('new-following-imports.txt') }
|
||||
|
||||
before do
|
||||
allow(NotificationWorker).to receive(:perform_async)
|
||||
end
|
||||
|
||||
describe 'when no accounts are followed' do
|
||||
let(:import) { Import.create(account: account, type: 'following', data: csv) }
|
||||
it 'follows the listed accounts, respecting boosts' do
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when some accounts are already followed and overwrite is not set' do
|
||||
let(:import) { Import.create(account: account, type: 'following', data: csv) }
|
||||
|
||||
it 'mutes the listed accounts, respecting notifications' do
|
||||
account.follow!(bob, reblogs: true)
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when some accounts are already followed and overwrite is set' do
|
||||
let(:import) { Import.create(account: account, type: 'following', data: csv, overwrite: true) }
|
||||
|
||||
it 'mutes the listed accounts, respecting notifications' do
|
||||
account.follow!(bob, reblogs: true)
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -3,6 +3,27 @@ require 'rails_helper'
|
||||
RSpec.describe ReblogService, type: :service do
|
||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||
|
||||
context 'creates a reblog with appropriate visibility' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||
let(:visibility) { :public }
|
||||
let(:reblog_visibility) { :public }
|
||||
let(:status) { Fabricate(:status, account: bob, visibility: visibility) }
|
||||
|
||||
subject { ReblogService.new }
|
||||
|
||||
before do
|
||||
subject.call(alice, status, visibility: reblog_visibility)
|
||||
end
|
||||
|
||||
describe 'boosting privately' do
|
||||
let(:reblog_visibility) { :private }
|
||||
|
||||
it 'reblogs privately' do
|
||||
expect(status.reblogs.first.visibility).to eq 'private'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'OStatus' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com') }
|
||||
let(:status) { Fabricate(:status, account: bob, uri: 'tag:example.com;something:something') }
|
||||
|
||||
@ -21,6 +21,11 @@ RSpec.describe ReportService, type: :service do
|
||||
subject.call(source_account, remote_account, forward: false)
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to_not have_been_made
|
||||
end
|
||||
|
||||
it 'has an uri' do
|
||||
report = subject.call(source_account, remote_account, forward: true)
|
||||
expect(report.uri).to_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when other reports already exist for the same target' do
|
||||
|
||||
@ -10,7 +10,7 @@ describe SearchService, type: :service do
|
||||
it 'returns empty results without searching' do
|
||||
allow(AccountSearchService).to receive(:new)
|
||||
allow(Tag).to receive(:search_for)
|
||||
results = subject.call('', 10)
|
||||
results = subject.call('', nil, 10)
|
||||
|
||||
expect(results).to eq(empty_results)
|
||||
expect(AccountSearchService).not_to have_received(:new)
|
||||
@ -27,7 +27,7 @@ describe SearchService, type: :service do
|
||||
it 'returns the empty results' do
|
||||
service = double(call: nil)
|
||||
allow(ResolveURLService).to receive(:new).and_return(service)
|
||||
results = subject.call(@query, 10)
|
||||
results = subject.call(@query, nil, 10)
|
||||
|
||||
expect(service).to have_received(:call).with(@query, on_behalf_of: nil)
|
||||
expect(results).to eq empty_results
|
||||
@ -40,7 +40,7 @@ describe SearchService, type: :service do
|
||||
service = double(call: account)
|
||||
allow(ResolveURLService).to receive(:new).and_return(service)
|
||||
|
||||
results = subject.call(@query, 10)
|
||||
results = subject.call(@query, nil, 10)
|
||||
expect(service).to have_received(:call).with(@query, on_behalf_of: nil)
|
||||
expect(results).to eq empty_results.merge(accounts: [account])
|
||||
end
|
||||
@ -52,7 +52,7 @@ describe SearchService, type: :service do
|
||||
service = double(call: status)
|
||||
allow(ResolveURLService).to receive(:new).and_return(service)
|
||||
|
||||
results = subject.call(@query, 10)
|
||||
results = subject.call(@query, nil, 10)
|
||||
expect(service).to have_received(:call).with(@query, on_behalf_of: nil)
|
||||
expect(results).to eq empty_results.merge(statuses: [status])
|
||||
end
|
||||
@ -67,8 +67,8 @@ describe SearchService, type: :service do
|
||||
service = double(call: [account])
|
||||
allow(AccountSearchService).to receive(:new).and_return(service)
|
||||
|
||||
results = subject.call(query, 10)
|
||||
expect(service).to have_received(:call).with(query, 10, nil, resolve: false)
|
||||
results = subject.call(query, nil, 10)
|
||||
expect(service).to have_received(:call).with(query, nil, limit: 10, offset: 0, resolve: false)
|
||||
expect(results).to eq empty_results.merge(accounts: [account])
|
||||
end
|
||||
end
|
||||
@ -77,17 +77,17 @@ describe SearchService, type: :service do
|
||||
it 'includes the tag in the results' do
|
||||
query = '#tag'
|
||||
tag = Tag.new
|
||||
allow(Tag).to receive(:search_for).with('tag', 10).and_return([tag])
|
||||
allow(Tag).to receive(:search_for).with('tag', 10, 0).and_return([tag])
|
||||
|
||||
results = subject.call(query, 10)
|
||||
expect(Tag).to have_received(:search_for).with('tag', 10)
|
||||
results = subject.call(query, nil, 10)
|
||||
expect(Tag).to have_received(:search_for).with('tag', 10, 0)
|
||||
expect(results).to eq empty_results.merge(hashtags: [tag])
|
||||
end
|
||||
it 'does not include tag when starts with @ character' do
|
||||
query = '@username'
|
||||
allow(Tag).to receive(:search_for)
|
||||
|
||||
results = subject.call(query, 10)
|
||||
results = subject.call(query, nil, 10)
|
||||
expect(Tag).not_to have_received(:search_for)
|
||||
expect(results).to eq empty_results
|
||||
end
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SuspendAccountService, type: :service do
|
||||
describe '#call' do
|
||||
describe '#call on local account' do
|
||||
before do
|
||||
stub_request(:post, "https://alice.com/inbox").to_return(status: 201)
|
||||
stub_request(:post, "https://bob.com/inbox").to_return(status: 201)
|
||||
@ -43,4 +43,46 @@ RSpec.describe SuspendAccountService, type: :service do
|
||||
expect(a_request(:post, "https://bob.com/inbox")).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
describe '#call on remote account' do
|
||||
before do
|
||||
stub_request(:post, "https://alice.com/inbox").to_return(status: 201)
|
||||
stub_request(:post, "https://bob.com/inbox").to_return(status: 201)
|
||||
end
|
||||
|
||||
subject do
|
||||
-> { described_class.new.call(remote_bob) }
|
||||
end
|
||||
|
||||
let!(:account) { Fabricate(:account) }
|
||||
let!(:remote_alice) { Fabricate(:account, inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }
|
||||
let!(:remote_bob) { Fabricate(:account, inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
|
||||
let!(:status) { Fabricate(:status, account: remote_bob) }
|
||||
let!(:media_attachment) { Fabricate(:media_attachment, account: remote_bob) }
|
||||
let!(:notification) { Fabricate(:notification, account: remote_bob) }
|
||||
let!(:favourite) { Fabricate(:favourite, account: remote_bob) }
|
||||
let!(:active_relationship) { Fabricate(:follow, account: remote_bob, target_account: account) }
|
||||
let!(:passive_relationship) { Fabricate(:follow, target_account: remote_bob) }
|
||||
let!(:subscription) { Fabricate(:subscription, account: remote_bob) }
|
||||
|
||||
it 'deletes associated records' do
|
||||
is_expected.to change {
|
||||
[
|
||||
remote_bob.statuses,
|
||||
remote_bob.media_attachments,
|
||||
remote_bob.stream_entries,
|
||||
remote_bob.notifications,
|
||||
remote_bob.favourites,
|
||||
remote_bob.active_relationships,
|
||||
remote_bob.passive_relationships,
|
||||
remote_bob.subscriptions
|
||||
].map(&:count)
|
||||
}.from([1, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0])
|
||||
end
|
||||
|
||||
it 'sends a reject follow to follwer inboxes' do
|
||||
subject.call
|
||||
expect(a_request(:post, remote_bob.inbox_url)).to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
28
spec/validators/poll_validator_spec.rb
Normal file
28
spec/validators/poll_validator_spec.rb
Normal file
@ -0,0 +1,28 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe PollValidator, type: :validator do
|
||||
describe '#validate' do
|
||||
before do
|
||||
validator.validate(poll)
|
||||
end
|
||||
|
||||
let(:validator) { described_class.new }
|
||||
let(:poll) { double(options: options, expires_at: expires_at, errors: errors) }
|
||||
let(:errors) { double(add: nil) }
|
||||
let(:options) { %w(foo bar) }
|
||||
let(:expires_at) { 1.day.from_now }
|
||||
|
||||
it 'have no errors' do
|
||||
expect(errors).not_to have_received(:add)
|
||||
end
|
||||
|
||||
context 'expires just 5 min ago' do
|
||||
let(:expires_at) { 5.minutes.from_now }
|
||||
it 'not calls errors add' do
|
||||
expect(errors).not_to have_received(:add)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -6,23 +6,29 @@ describe 'about/show.html.haml', without_verify_partial_doubles: true do
|
||||
before do
|
||||
allow(view).to receive(:site_hostname).and_return('example.com')
|
||||
allow(view).to receive(:site_title).and_return('example site')
|
||||
allow(view).to receive(:new_user).and_return(User.new)
|
||||
allow(view).to receive(:use_seamless_external_login?).and_return(false)
|
||||
end
|
||||
|
||||
it 'has valid open graph tags' do
|
||||
instance_presenter = double(:instance_presenter,
|
||||
site_title: 'something',
|
||||
site_short_description: 'something',
|
||||
site_description: 'something',
|
||||
version_number: '1.0',
|
||||
source_url: 'https://github.com/tootsuite/mastodon',
|
||||
open_registrations: false,
|
||||
thumbnail: nil,
|
||||
hero: nil,
|
||||
mascot: nil,
|
||||
user_count: 0,
|
||||
status_count: 0,
|
||||
contact_account: nil,
|
||||
closed_registrations_message: 'yes')
|
||||
instance_presenter = double(
|
||||
:instance_presenter,
|
||||
site_title: 'something',
|
||||
site_short_description: 'something',
|
||||
site_description: 'something',
|
||||
version_number: '1.0',
|
||||
source_url: 'https://github.com/tootsuite/mastodon',
|
||||
open_registrations: false,
|
||||
thumbnail: nil,
|
||||
hero: nil,
|
||||
mascot: nil,
|
||||
user_count: 420,
|
||||
status_count: 69,
|
||||
active_user_count: 420,
|
||||
contact_account: nil,
|
||||
sample_accounts: []
|
||||
)
|
||||
|
||||
assign(:instance_presenter, instance_presenter)
|
||||
render
|
||||
|
||||
|
||||
40
spec/workers/activitypub/fetch_replies_worker_spec.rb
Normal file
40
spec/workers/activitypub/fetch_replies_worker_spec.rb
Normal 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 Mastodon::UnexpectedResponseError
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user