Merge tag 'v2.7.0rc1' into instance_only_statuses

This commit is contained in:
Renato "Lond" Cerqueira
2019-01-09 10:47:10 +01:00
585 changed files with 16065 additions and 8146 deletions

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe ActivityPub::CollectionsController, type: :controller do
describe 'POST #show' do
let(:account) { Fabricate(:account) }
context 'id is "featured"' do
it 'returns 200 with "application/activity+json"' do
post :show, params: { id: 'featured', account_username: account.username }
expect(response).to have_http_status(200)
expect(response.content_type).to eq 'application/activity+json'
end
end
context 'id is not "featured"' do
it 'returns 404' do
post :show, params: { id: 'hoge', account_username: account.username }
expect(response).to have_http_status(404)
end
end
end
end

View File

@ -1,7 +1,29 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe ActivityPub::InboxesController, type: :controller do
describe 'POST #create' do
pending
context 'if signed_request_account' do
it 'returns 202' do
allow(controller).to receive(:signed_request_account) do
Fabricate(:account)
end
post :create
expect(response).to have_http_status(202)
end
end
context 'not signed_request_account' do
it 'returns 401' do
allow(controller).to receive(:signed_request_account) do
false
end
post :create
expect(response).to have_http_status(401)
end
end
end
end

View File

@ -24,8 +24,8 @@ RSpec.describe Admin::AccountsController, type: :controller do
expect(h[:local]).to eq '1'
expect(h[:remote]).to eq '1'
expect(h[:by_domain]).to eq 'domain'
expect(h[:active]).to eq '1'
expect(h[:silenced]).to eq '1'
expect(h[:alphabetic]).to eq '1'
expect(h[:suspended]).to eq '1'
expect(h[:username]).to eq 'username'
expect(h[:display_name]).to eq 'display name'
@ -39,8 +39,8 @@ RSpec.describe Admin::AccountsController, type: :controller do
local: '1',
remote: '1',
by_domain: 'domain',
active: '1',
silenced: '1',
alphabetic: '1',
suspended: '1',
username: 'username',
display_name: 'display name',
@ -191,58 +191,6 @@ RSpec.describe Admin::AccountsController, type: :controller do
end
end
describe 'POST #disable' do
subject { post :disable, params: { id: account.id } }
let(:current_user) { Fabricate(:user, admin: current_user_admin) }
let(:account) { Fabricate(:account, user: user) }
let(:user) { Fabricate(:user, disabled: false, admin: target_user_admin) }
context 'when user is admin' do
let(:current_user_admin) { true }
context 'when target user is admin' do
let(:target_user_admin) { true }
it 'fails to disable account' do
is_expected.to have_http_status :forbidden
expect(user.reload).not_to be_disabled
end
end
context 'when target user is not admin' do
let(:target_user_admin) { false }
it 'succeeds in disabling account' do
is_expected.to redirect_to admin_account_path(account.id)
expect(user.reload).to be_disabled
end
end
end
context 'when user is not admin' do
let(:current_user_admin) { false }
context 'when target user is admin' do
let(:target_user_admin) { true }
it 'fails to disable account' do
is_expected.to have_http_status :forbidden
expect(user.reload).not_to be_disabled
end
end
context 'when target user is not admin' do
let(:target_user_admin) { false }
it 'fails to disable account' do
is_expected.to have_http_status :forbidden
expect(user.reload).not_to be_disabled
end
end
end
end
describe 'POST #redownload' do
subject { post :redownload, params: { id: account.id } }

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'rails_helper'
describe Admin::ActionLogsController, type: :controller do
describe 'GET #index' do
it 'returns 200' do
sign_in Fabricate(:user, admin: true)
get :index, params: { page: 1 }
expect(response).to have_http_status(200)
end
end
end

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'rails_helper'
describe Admin::DashboardController, type: :controller do
describe 'GET #index' do
it 'returns 200' do
sign_in Fabricate(:user, admin: true)
get :index
expect(response).to have_http_status(200)
end
end
end

View File

@ -7,26 +7,6 @@ RSpec.describe Admin::DomainBlocksController, type: :controller do
sign_in Fabricate(:user, admin: true), scope: :user
end
describe 'GET #index' do
around do |example|
default_per_page = DomainBlock.default_per_page
DomainBlock.paginates_per 1
example.run
DomainBlock.paginates_per default_per_page
end
it 'renders domain blocks' do
2.times { Fabricate(:domain_block) }
get :index, params: { page: 2 }
assigned = assigns(:domain_blocks)
expect(assigned.count).to eq 1
expect(assigned.klass).to be DomainBlock
expect(response).to have_http_status(200)
end
end
describe 'GET #new' do
it 'assigns a new domain block' do
get :new
@ -53,7 +33,7 @@ RSpec.describe Admin::DomainBlocksController, type: :controller do
expect(DomainBlockWorker).to have_received(:perform_async)
expect(flash[:notice]).to eq I18n.t('admin.domain_blocks.created_msg')
expect(response).to redirect_to(admin_domain_blocks_path)
expect(response).to redirect_to(admin_instances_path(limited: '1'))
end
it 'renders new when failed to save' do
@ -76,7 +56,7 @@ RSpec.describe Admin::DomainBlocksController, type: :controller do
expect(service).to have_received(:call).with(domain_block, true)
expect(flash[:notice]).to eq I18n.t('admin.domain_blocks.destroyed_msg')
expect(response).to redirect_to(admin_domain_blocks_path)
expect(response).to redirect_to(admin_instances_path(limited: '1'))
end
end
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rails_helper'
describe Admin::InvitesController do
@ -40,4 +42,18 @@ describe Admin::InvitesController do
expect(invite.reload).to be_expired
end
end
describe 'POST #deactivate_all' do
it 'expires all invites, then redirects to admin_invites_path' do
invites = Fabricate.times(2, :invite, expires_at: nil)
post :deactivate_all
invites.each do |invite|
expect(invite.reload).to be_expired
end
expect(response).to redirect_to admin_invites_path
end
end
end

View File

@ -46,73 +46,37 @@ describe Admin::ReportsController do
end
end
describe 'PUT #update' do
describe 'with an unknown outcome' do
it 'rejects the change' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'unknown' }
describe 'POST #reopen' do
it 'reopens the report' do
report = Fabricate(:report)
expect(response).to have_http_status(404)
end
put :reopen, params: { id: report }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.action_taken_by_account).to eq nil
expect(report.action_taken).to eq false
end
end
describe 'with an outcome of `resolve`' do
it 'resolves the report' do
report = Fabricate(:report)
describe 'POST #assign_to_self' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'resolve' }
expect(response).to redirect_to(admin_reports_path)
report.reload
expect(report.action_taken_by_account).to eq user.account
expect(report.action_taken).to eq true
end
put :assign_to_self, params: { id: report }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq user.account
end
end
describe 'with an outsome of `silence`' do
it 'silences the reported account' do
report = Fabricate(:report)
describe 'POST #unassign' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'silence' }
expect(response).to redirect_to(admin_reports_path)
report.reload
expect(report.action_taken_by_account).to eq user.account
expect(report.action_taken).to eq true
expect(report.target_account).to be_silenced
end
end
describe 'with an outsome of `reopen`' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'reopen' }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.action_taken_by_account).to eq nil
expect(report.action_taken).to eq false
end
end
describe 'with an outsome of `assign_to_self`' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'assign_to_self' }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq user.account
end
end
describe 'with an outsome of `unassign`' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'unassign' }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq nil
end
put :unassign, params: { id: report }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq nil
end
end
end

View File

@ -1,33 +0,0 @@
require 'rails_helper'
describe Admin::SilencesController do
render_views
before do
sign_in Fabricate(:user, admin: true), scope: :user
end
describe 'POST #create' do
it 'redirects to admin accounts page' do
account = Fabricate(:account, silenced: false)
post :create, params: { account_id: account.id }
account.reload
expect(account.silenced?).to eq true
expect(response).to redirect_to(admin_accounts_path)
end
end
describe 'DELETE #destroy' do
it 'redirects to admin accounts page' do
account = Fabricate(:account, silenced: true)
delete :destroy, params: { account_id: account.id }
account.reload
expect(account.silenced?).to eq false
expect(response).to redirect_to(admin_accounts_path)
end
end
end

View File

@ -1,32 +0,0 @@
require 'rails_helper'
describe Admin::SuspensionsController do
render_views
before do
sign_in Fabricate(:user, admin: true), scope: :user
end
describe 'POST #create' do
it 'redirects to admin accounts page' do
account = Fabricate(:account, suspended: false)
expect(Admin::SuspensionWorker).to receive(:perform_async).with(account.id)
post :create, params: { account_id: account.id, form_admin_suspension_confirmation: { acct: account.acct } }
expect(response).to redirect_to(admin_accounts_path)
end
end
describe 'DELETE #destroy' do
it 'redirects to admin accounts page' do
account = Fabricate(:account, suspended: true)
delete :destroy, params: { account_id: account.id }
account.reload
expect(account.suspended?).to eq false
expect(response).to redirect_to(admin_accounts_path)
end
end
end

View File

@ -0,0 +1,71 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Admin::TagsController, type: :controller do
render_views
before do
sign_in Fabricate(:user, admin: true)
end
describe 'GET #index' do
before do
account_tag_stat = Fabricate(:tag).account_tag_stat
account_tag_stat.update(hidden: hidden, accounts_count: 1)
get :index, params: { hidden: hidden }
end
context 'with hidden tags' do
let(:hidden) { true }
it 'returns status 200' do
expect(response).to have_http_status(200)
end
end
context 'without hidden tags' do
let(:hidden) { false }
it 'returns status 200' do
expect(response).to have_http_status(200)
end
end
end
describe 'POST #hide' do
let(:tag) { Fabricate(:tag) }
before do
tag.account_tag_stat.update(hidden: false)
post :hide, params: { id: tag.id }
end
it 'hides tag' do
tag.reload
expect(tag).to be_hidden
end
it 'redirects to admin_tags_path' do
expect(response).to redirect_to(admin_tags_path(controller.instance_variable_get(:@filter_params)))
end
end
describe 'POST #unhide' do
let(:tag) { Fabricate(:tag) }
before do
tag.account_tag_stat.update(hidden: true)
post :unhide, params: { id: tag.id }
end
it 'unhides tag' do
tag.reload
expect(tag).not_to be_hidden
end
it 'redirects to admin_tags_path' do
expect(response).to redirect_to(admin_tags_path(controller.instance_variable_get(:@filter_params)))
end
end
end

View File

@ -0,0 +1,46 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::Accounts::PinsController, type: :controller do
let(:john) { Fabricate(:user, account: Fabricate(:account, username: 'john')) }
let(:kevin) { Fabricate(:user, account: Fabricate(:account, username: 'kevin')) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: john.id, scopes: 'write:accounts') }
before do
kevin.account.followers << john.account
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST #create' do
subject { post :create, params: { account_id: kevin.account.id } }
it 'returns 200' do
expect(response).to have_http_status(200)
end
it 'creates account_pin' do
expect do
subject
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(1)
end
end
describe 'DELETE #destroy' do
subject { delete :destroy, params: { account_id: kevin.account.id } }
before do
Fabricate(:account_pin, account: john.account, target_account: kevin.account)
end
it 'returns 200' do
expect(response).to have_http_status(200)
end
it 'destroys account_pin' do
expect do
subject
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(-1)
end
end
end

View File

@ -19,6 +19,40 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
end
end
describe 'POST #create' do
let(:app) { Fabricate(:application) }
let(:token) { Doorkeeper::AccessToken.find_or_create_for(app, nil, 'read write', nil, false) }
let(:agreement) { nil }
before do
post :create, params: { username: 'test', password: '12345678', email: 'hello@world.tld', agreement: agreement }
end
context 'given truthy agreement' do
let(:agreement) { 'true' }
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns a new access token as JSON' do
expect(body_as_json[:access_token]).to_not be_blank
end
it 'creates a user' do
user = User.find_by(email: 'hello@world.tld')
expect(user).to_not be_nil
expect(user.created_by_application_id).to eq app.id
end
end
context 'given no agreement' do
it 'returns http unprocessable entity' do
expect(response).to have_http_status(422)
end
end
end
describe 'GET #show' do
let(:scopes) { 'read:accounts' }

View File

@ -15,7 +15,7 @@ RSpec.describe Api::V1::ConversationsController, type: :controller do
let(:scopes) { 'read:statuses' }
before do
PostStatusService.new.call(other.account, 'Hey @alice', nil, visibility: 'direct')
PostStatusService.new.call(other.account, text: 'Hey @alice', visibility: 'direct')
end
it 'returns http success' do

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::EndorsementsController, type: :controller do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
describe 'GET #index' do
it 'returns 200' do
allow(controller).to receive(:doorkeeper_token) { token }
get :index
expect(response).to have_http_status(200)
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::Instances::ActivityController, type: :controller do
describe 'GET #show' do
it 'returns 200' do
get :show
expect(response).to have_http_status(200)
end
context '!Setting.activity_api_enabled' do
it 'returns 404' do
Setting.activity_api_enabled = false
get :show
expect(response).to have_http_status(404)
end
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::Instances::PeersController, type: :controller do
describe 'GET #index' do
it 'returns 200' do
get :index
expect(response).to have_http_status(200)
end
context '!Setting.peers_api_enabled' do
it 'returns 404' do
Setting.peers_api_enabled = false
get :index
expect(response).to have_http_status(404)
end
end
end
end

View File

@ -50,9 +50,9 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do
let(:scopes) { 'read:notifications' }
before do
first_status = PostStatusService.new.call(user.account, 'Test')
first_status = PostStatusService.new.call(user.account, text: 'Test')
@reblog_of_first_status = ReblogService.new.call(other.account, first_status)
mentioning_status = PostStatusService.new.call(other.account, 'Hello @alice')
mentioning_status = PostStatusService.new.call(other.account, text: 'Hello @alice')
@mention_from_status = mentioning_status.mentions.first
@favourite = FavouriteService.new.call(other.account, first_status)
@follow = FollowService.new.call(other.account, 'alice')

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::Timelines::DirectController, type: :controller do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
describe 'GET #show' do
it 'returns 200' do
allow(controller).to receive(:doorkeeper_token) { token }
get :show
expect(response).to have_http_status(200)
end
end
end

View File

@ -17,7 +17,7 @@ describe Api::V1::Timelines::HomeController do
describe 'GET #show' do
before do
follow = Fabricate(:follow, account: user.account)
PostStatusService.new.call(follow.target_account, 'New status for user home timeline.')
PostStatusService.new.call(follow.target_account, text: 'New status for user home timeline.')
end
it 'returns http success' do

View File

@ -19,7 +19,7 @@ describe Api::V1::Timelines::ListController do
before do
follow = Fabricate(:follow, account: user.account)
list.accounts << follow.target_account
PostStatusService.new.call(follow.target_account, 'New status for user home timeline.')
PostStatusService.new.call(follow.target_account, text: 'New status for user home timeline.')
end
it 'returns http success' do

View File

@ -16,7 +16,7 @@ describe Api::V1::Timelines::PublicController do
describe 'GET #show' do
before do
PostStatusService.new.call(user.account, 'New status from user for federated public timeline.')
PostStatusService.new.call(user.account, text: 'New status from user for federated public timeline.')
end
it 'returns http success' do
@ -29,7 +29,7 @@ describe Api::V1::Timelines::PublicController do
describe 'GET #show with local only' do
before do
PostStatusService.new.call(user.account, 'New status from user for local public timeline.')
PostStatusService.new.call(user.account, text: 'New status from user for local public timeline.')
end
it 'returns http success' do

View File

@ -16,7 +16,7 @@ describe Api::V1::Timelines::TagController do
describe 'GET #show' do
before do
PostStatusService.new.call(user.account, 'It is a #test')
PostStatusService.new.call(user.account, text: 'It is a #test')
end
it 'returns http success' do

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe AccountableConcern do
class Hoge
include AccountableConcern
attr_reader :current_account
def initialize(current_account)
@current_account = current_account
end
end
let(:user) { Fabricate(:user, account: Fabricate(:account)) }
let(:target) { Fabricate(:user, account: Fabricate(:account)) }
let(:hoge) { Hoge.new(user.account) }
describe '#log_action' do
it 'creates Admin::ActionLog' do
expect do
hoge.log_action(:create, target.account)
end.to change { Admin::ActionLog.count }.by(1)
end
end
end

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
require 'rails_helper'
describe RemoteInteractionController, type: :controller do
render_views
let(:status) { Fabricate(:status) }
describe 'GET #new' do
it 'returns 200' do
get :new, params: { id: status.id }
expect(response).to have_http_status(200)
end
end
describe 'POST #create' do
context '@remote_follow is valid' do
it 'returns 302' do
allow_any_instance_of(RemoteFollow).to receive(:valid?) { true }
allow_any_instance_of(RemoteFollow).to receive(:addressable_template) do
Addressable::Template.new('https://hoge.com')
end
post :create, params: { id: status.id, remote_follow: { acct: '@hoge' } }
expect(response).to have_http_status(302)
end
end
context '@remote_follow is invalid' do
it 'returns 200' do
allow_any_instance_of(RemoteFollow).to receive(:valid?) { false }
post :create, params: { id: status.id, remote_follow: { acct: '@hoge' } }
expect(response).to have_http_status(200)
end
end
end
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rails_helper'
describe Settings::ExportsController do
@ -28,4 +30,23 @@ describe Settings::ExportsController do
end
end
end
describe 'POST #create' do
before do
sign_in Fabricate(:user), scope: :user
end
it 'redirects to settings_export_path' do
post :create
expect(response).to redirect_to(settings_export_path)
end
it 'queues BackupWorker job by 1' do
Sidekiq::Testing.fake! do
expect do
post :create
end.to change(BackupWorker.jobs, :size).by(1)
end
end
end
end

View File

@ -26,4 +26,26 @@ RSpec.describe Settings::ProfilesController, type: :controller do
expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)
end
end
describe 'PUT #update with new profile image' do
it 'updates profile image' do
allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
account = Fabricate(:account, user: @user, display_name: 'AvatarTest')
expect(account.avatar.instance.avatar_file_name).to be_nil
put :update, params: { account: { avatar: fixture_file_upload('files/avatar.gif', 'image/gif') } }
expect(response).to redirect_to(settings_profile_path)
expect(account.reload.avatar.instance.avatar_file_name).not_to be_nil
expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)
end
end
describe 'PUT #update with oversized image' do
it 'gives the user an error message' do
allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
account = Fabricate(:account, user: @user, display_name: 'AvatarTest')
put :update, params: { account: { avatar: fixture_file_upload('files/4096x4097.png', 'image/png') } }
expect(response.body).to include('images are not supported')
end
end
end

View File

@ -115,14 +115,18 @@ describe StatusesController do
end
it 'assigns @descendant_threads for threads with :next_status key if they are hitting the depth limit' do
stub_const 'StatusesController::DESCENDANTS_DEPTH_LIMIT', 1
stub_const 'StatusesController::DESCENDANTS_DEPTH_LIMIT', 2
status = Fabricate(:status)
child = Fabricate(:status, in_reply_to_id: status.id)
child0 = Fabricate(:status, in_reply_to_id: status.id)
child1 = Fabricate(:status, in_reply_to_id: child0.id)
child2 = Fabricate(:status, in_reply_to_id: child0.id)
get :show, params: { account_username: status.account.username, id: status.id }
expect(assigns(:descendant_threads)[0][:statuses].pluck(:id)).not_to include child.id
expect(assigns(:descendant_threads)[0][:next_status].id).to eq child.id
expect(assigns(:descendant_threads)[0][:statuses].pluck(:id)).not_to include child1.id
expect(assigns(:descendant_threads)[1][:statuses].pluck(:id)).not_to include child2.id
expect(assigns(:descendant_threads)[0][:next_status].id).to eq child1.id
expect(assigns(:descendant_threads)[1][:next_status].id).to eq child2.id
end
it 'returns a success' do

View File

@ -0,0 +1,6 @@
Fabricator(:account_stat) do
account nil
statuses_count ""
following_count ""
followers_count ""
end

View File

@ -0,0 +1,3 @@
Fabricator(:account_tag_stat) do
accounts_count ""
end

View File

@ -0,0 +1,5 @@
Fabricator(:account_warning) do
account nil
target_account nil
text "MyText"
end

View File

@ -0,0 +1,3 @@
Fabricator(:account_warning_preset) do
text "MyText"
end

View File

@ -0,0 +1,4 @@
Fabricator(:scheduled_status) do
account
scheduled_at { 20.hours.from_now }
end

View File

@ -3,4 +3,5 @@ Fabricator(:user) do
email { sequence(:email) { |i| "#{i}#{Faker::Internet.email}" } }
password "123456789"
confirmed_at { Time.zone.now }
agreement true
end

BIN
spec/fixtures/files/4096x4097.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

17
spec/fixtures/requests/windows-1251.txt vendored Normal file
View File

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
server: nginx
date: Wed, 12 Dec 2018 13:14:03 GMT
content-type: text/html
content-length: 190
accept-ranges: bytes
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />
<title><3E><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD></title>
</head>
<body>
<p><3E><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD></p>
</body>
</html>

View File

@ -1,15 +1,55 @@
# frozen_string_literal: true
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the Admin::AccountModerationNotesHelper. For example:
#
# describe Admin::AccountModerationNotesHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe Admin::AccountModerationNotesHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
include StreamEntriesHelper
describe '#admin_account_link_to' do
context 'account is nil' do
let(:account) { nil }
it 'returns nil' do
expect(helper.admin_account_link_to(account)).to be_nil
end
end
context 'with account' do
let(:account) { Fabricate(:account) }
it 'calls #link_to' do
expect(helper).to receive(:link_to).with(
admin_account_path(account.id),
class: name_tag_classes(account),
title: account.acct
)
helper.admin_account_link_to(account)
end
end
end
describe '#admin_account_inline_link_to' do
context 'account is nil' do
let(:account) { nil }
it 'returns nil' do
expect(helper.admin_account_inline_link_to(account)).to be_nil
end
end
context 'with account' do
let(:account) { Fabricate(:account) }
it 'calls #link_to' do
expect(helper).to receive(:link_to).with(
admin_account_path(account.id),
class: name_tag_classes(account, true),
title: account.acct
)
helper.admin_account_inline_link_to(account)
end
end
end
end

View File

@ -22,11 +22,35 @@ describe JsonLdHelper do
end
describe '#first_of_value' do
pending
context 'value.is_a?(Array)' do
it 'returns value.first' do
value = ['a']
expect(helper.first_of_value(value)).to be 'a'
end
end
context '!value.is_a?(Array)' do
it 'returns value' do
value = 'a'
expect(helper.first_of_value(value)).to be 'a'
end
end
end
describe '#supported_context?' do
pending
context "!json.nil? && equals_or_includes?(json['@context'], ActivityPub::TagManager::CONTEXT)" do
it 'returns true' do
json = { '@context' => ActivityPub::TagManager::CONTEXT }.as_json
expect(helper.supported_context?(json)).to be true
end
end
context 'else' do
it 'returns false' do
json = nil
expect(helper.supported_context?(json)).to be false
end
end
end
describe '#fetch_resource' do

View File

@ -14,15 +14,72 @@ RSpec.describe ActivityPub::Activity::Block do
}.with_indifferent_access
end
describe '#perform' do
subject { described_class.new(json, sender) }
context 'when the recipient does not follow the sender' do
describe '#perform' do
subject { described_class.new(json, sender) }
before do
subject.perform
end
it 'creates a block from sender to recipient' do
expect(sender.blocking?(recipient)).to be true
end
end
end
context 'when the recipient follows the sender' do
before do
subject.perform
recipient.follow!(sender)
end
it 'creates a block from sender to recipient' do
expect(sender.blocking?(recipient)).to be true
describe '#perform' do
subject { described_class.new(json, sender) }
before do
subject.perform
end
it 'creates a block from sender to recipient' do
expect(sender.blocking?(recipient)).to be true
end
it 'ensures recipient is not following sender' do
expect(recipient.following?(sender)).to be false
end
end
end
context 'when a matching undo has been received first' do
let(:undo_json) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'bar',
type: 'Undo',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: json,
}.with_indifferent_access
end
before do
recipient.follow!(sender)
ActivityPub::Activity::Undo.new(undo_json, sender).perform
end
describe '#perform' do
subject { described_class.new(json, sender) }
before do
subject.perform
end
it 'does not create a block from sender to recipient' do
expect(sender.blocking?(recipient)).to be false
end
it 'ensures recipient is not following sender' do
expect(recipient.following?(sender)).to be false
end
end
end
end

View File

@ -0,0 +1,52 @@
require 'rails_helper'
RSpec.describe ActivityPub::Activity::Move do
let(:follower) { Fabricate(:account) }
let(:old_account) { Fabricate(:account) }
let(:new_account) { Fabricate(:account) }
before do
follower.follow!(old_account)
old_account.update!(uri: 'https://example.org/alice', domain: 'example.org', protocol: :activitypub, inbox_url: 'https://example.org/inbox')
new_account.update!(uri: 'https://example.com/alice', domain: 'example.com', protocol: :activitypub, inbox_url: 'https://example.com/inbox', also_known_as: [old_account.uri])
stub_request(:post, 'https://example.org/inbox').to_return(status: 200)
stub_request(:post, 'https://example.com/inbox').to_return(status: 200)
service_stub = double
allow(ActivityPub::FetchRemoteAccountService).to receive(:new).and_return(service_stub)
allow(service_stub).to receive(:call).and_return(new_account)
end
let(:json) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'foo',
type: 'Move',
actor: old_account.uri,
object: old_account.uri,
target: new_account.uri,
}.with_indifferent_access
end
describe '#perform' do
subject { described_class.new(json, old_account) }
before do
subject.perform
end
it 'sets moved account on old account' do
expect(old_account.reload.moved_to_account_id).to eq new_account.id
end
it 'makes followers unfollow old account' do
expect(follower.following?(old_account)).to be false
end
it 'makes followers follow-request the new account' do
expect(follower.requested?(new_account)).to be true
end
end
end

View File

@ -108,14 +108,14 @@ RSpec.describe FeedManager do
it 'returns false for status by followee mentioning another account' do
bob.follow!(alice)
status = PostStatusService.new.call(alice, 'Hey @jeff')
status = PostStatusService.new.call(alice, text: 'Hey @jeff')
expect(FeedManager.instance.filter?(:home, status, bob.id)).to be false
end
it 'returns true for status by followee mentioning blocked account' do
bob.block!(jeff)
bob.follow!(alice)
status = PostStatusService.new.call(alice, 'Hey @jeff')
status = PostStatusService.new.call(alice, text: 'Hey @jeff')
expect(FeedManager.instance.filter?(:home, status, bob.id)).to be true
end
@ -155,7 +155,7 @@ RSpec.describe FeedManager do
context 'for mentions feed' do
it 'returns true for status that mentions blocked account' do
bob.block!(jeff)
status = PostStatusService.new.call(alice, 'Hey @jeff')
status = PostStatusService.new.call(alice, text: 'Hey @jeff')
expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be true
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe AdminMailer, type: :mailer do
describe '.new_report' do
let(:sender) { Fabricate(:account, username: 'John', user: Fabricate(:user)) }
let(:recipient) { Fabricate(:account, username: 'Mike', user: Fabricate(:user, locale: :en)) }
let(:report) { Fabricate(:report, account: sender, target_account: recipient) }
let(:mail) { described_class.new_report(recipient, report) }
it 'renders the headers' do
expect(mail.subject).to eq("New report for cb6e6126.ngrok.io (##{report.id})")
expect(mail.to).to eq [recipient.user_email]
expect(mail.from).to eq ['notifications@localhost']
end
it 'renders the body' do
expect(mail.body.encoded).to eq("Mike,\r\n\r\nJohn has reported Mike\r\n\r\nView: https://cb6e6126.ngrok.io/admin/reports/#{report.id}\r\n")
end
end
end

View File

@ -126,19 +126,7 @@ RSpec.describe NotificationMailer, type: :mailer do
end
end
it 'includes activities since the date specified by :since option' do
receiver.update!(last_emailed_at: '2000-02-01T00:00:00Z', current_sign_in_at: '2000-03-01T00:00:00Z')
mail = NotificationMailer.digest(receiver.account, since: Time.parse('2000-01-01T00:00:00Z'))
expect(mail.body.encoded).to include 'Jan 01, 2000, 00:00'
end
it 'includes activities since the receiver was last emailed if :since option is unavailable' do
receiver.update!(last_emailed_at: '2000-02-01T00:00:00Z', current_sign_in_at: '2000-03-01T00:00:00Z')
mail = NotificationMailer.digest(receiver.account)
expect(mail.body.encoded).to include 'Feb 01, 2000, 00:00'
end
it 'includes activities since the receiver last signed in if :since option and the last emailed date are unavailable' do
it 'includes activities since the receiver last signed in' do
receiver.update!(last_emailed_at: nil, current_sign_in_at: '2000-03-01T00:00:00Z')
mail = NotificationMailer.digest(receiver.account)
expect(mail.body.encoded).to include 'Mar 01, 2000, 00:00'

View File

@ -39,4 +39,9 @@ class UserMailerPreview < ActionMailer::Preview
def backup_ready
UserMailer.backup_ready(User.first, Backup.first)
end
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/warning
def warning
UserMailer.warning(User.first, AccountWarning.new(text: '', action: :silence))
end
end

View File

@ -2,10 +2,10 @@ require 'rails_helper'
describe AccountFilter do
describe 'with empty params' do
it 'defaults to recent account list' do
it 'defaults to recent local not-suspended account list' do
filter = described_class.new({})
expect(filter.results).to eq Account.recent
expect(filter.results).to eq Account.local.recent.without_suspended
end
end
@ -17,23 +17,6 @@ describe AccountFilter do
end
end
describe 'when an IP address is provided' do
it 'filters with IP when valid' do
filter = described_class.new(ip: '127.0.0.1')
allow(User).to receive(:with_recent_ip_address).and_return(User.none)
filter.results
expect(User).to have_received(:with_recent_ip_address).with('127.0.0.1')
end
it 'skips IP when invalid' do
filter = described_class.new(ip: '345.678.901.234')
expect(User).not_to receive(:with_recent_ip_address)
filter.results
end
end
describe 'with valid params' do
it 'combines filters on Account' do
filter = described_class.new(
@ -60,13 +43,13 @@ describe AccountFilter do
end
describe 'that call account methods' do
%i(local remote silenced alphabetic suspended).each do |option|
%i(local remote silenced suspended).each do |option|
it "delegates the #{option} option" do
allow(Account).to receive(option).and_return(Account.none)
filter = described_class.new({ option => true })
filter.results
expect(Account).to have_received(option)
expect(Account).to have_received(option).at_least(1)
end
end
end

View File

@ -1,5 +0,0 @@
require 'rails_helper'
RSpec.describe AccountPin, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -760,24 +760,6 @@ RSpec.describe Account, type: :model do
expect(Account.suspended).to match_array([account_1])
end
end
describe 'without_followers' do
it 'returns a relation of accounts without followers' do
account_1 = Fabricate(:account)
account_2 = Fabricate(:account)
Fabricate(:follow, account: account_1, target_account: account_2)
expect(Account.without_followers).to match_array([account_1])
end
end
describe 'with_followers' do
it 'returns a relation of accounts with followers' do
account_1 = Fabricate(:account)
account_2 = Fabricate(:account)
Fabricate(:follow, account: account_1, target_account: account_2)
expect(Account.with_followers).to match_array([account_2])
end
end
end
context 'when is local' do

View File

@ -0,0 +1,4 @@
require 'rails_helper'
RSpec.describe AccountStat, type: :model do
end

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe AccountTagStat, type: :model do
key = 'accounts_count'
let(:account_tag_stat) { Fabricate(:tag).account_tag_stat }
describe '#increment_count!' do
it 'calls #update' do
args = { key => account_tag_stat.public_send(key) + 1 }
expect(account_tag_stat).to receive(:update).with(args)
account_tag_stat.increment_count!(key)
end
it 'increments value by 1' do
expect do
account_tag_stat.increment_count!(key)
end.to change { account_tag_stat.accounts_count }.by(1)
end
end
describe '#decrement_count!' do
it 'calls #update' do
args = { key => [account_tag_stat.public_send(key) - 1, 0].max }
expect(account_tag_stat).to receive(:update).with(args)
account_tag_stat.decrement_count!(key)
end
it 'decrements value by 1' do
account_tag_stat.update(key => 1)
expect do
account_tag_stat.decrement_count!(key)
end.to change { account_tag_stat.accounts_count }.by(-1)
end
end
end

View File

@ -0,0 +1,4 @@
require 'rails_helper'
RSpec.describe Admin::AccountAction, type: :model do
end

View File

@ -118,5 +118,15 @@ describe StatusThreadingConcern do
viewer.block_domain!('example.com')
expect(status.descendants(4, viewer)).to_not include(reply2)
end
it 'promotes self-replies to the top while leaving the rest in order' do
a = Fabricate(:status, account: alice)
d = Fabricate(:status, account: jeff, thread: a)
e = Fabricate(:status, account: bob, thread: d)
c = Fabricate(:status, account: alice, thread: a)
f = Fabricate(:status, account: bob, thread: c)
expect(a.descendants(20)).to eq [c, d, e, f]
end
end
end

View File

@ -0,0 +1,70 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe CustomEmojiFilter do
describe '#results' do
let!(:custom_emoji_0) { Fabricate(:custom_emoji, domain: 'a') }
let!(:custom_emoji_1) { Fabricate(:custom_emoji, domain: 'b') }
let!(:custom_emoji_2) { Fabricate(:custom_emoji, domain: nil, shortcode: 'hoge') }
subject { described_class.new(params).results }
context 'params have values' do
context 'local' do
let(:params) { { local: true } }
it 'returns ActiveRecord::Relation' do
expect(subject).to be_kind_of(ActiveRecord::Relation)
expect(subject).to match_array([custom_emoji_2])
end
end
context 'remote' do
let(:params) { { remote: true } }
it 'returns ActiveRecord::Relation' do
expect(subject).to be_kind_of(ActiveRecord::Relation)
expect(subject).to match_array([custom_emoji_0, custom_emoji_1])
end
end
context 'by_domain' do
let(:params) { { by_domain: 'a' } }
it 'returns ActiveRecord::Relation' do
expect(subject).to be_kind_of(ActiveRecord::Relation)
expect(subject).to match_array([custom_emoji_0])
end
end
context 'shortcode' do
let(:params) { { shortcode: 'hoge' } }
it 'returns ActiveRecord::Relation' do
expect(subject).to be_kind_of(ActiveRecord::Relation)
expect(subject).to match_array([custom_emoji_2])
end
end
context 'else' do
let(:params) { { else: 'else' } }
it 'raises RuntimeError' do
expect do
subject
end.to raise_error(RuntimeError, /Unknown filter: else/)
end
end
end
context 'params without value' do
let(:params) { { hoge: nil } }
it 'returns ActiveRecord::Relation' do
expect(subject).to be_kind_of(ActiveRecord::Relation)
expect(subject).to match_array([custom_emoji_0, custom_emoji_1, custom_emoji_2])
end
end
end
end

View File

@ -75,4 +75,13 @@ RSpec.describe CustomEmoji, type: :model do
end
end
end
describe 'pre_validation' do
let(:custom_emoji) { Fabricate(:custom_emoji, domain: 'wWw.MaStOdOn.CoM') }
it 'should downcase' do
custom_emoji.valid?
expect(custom_emoji.domain).to eq('www.mastodon.com')
end
end
end

View File

@ -1,5 +1,16 @@
require 'rails_helper'
RSpec.describe Identity, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
describe '.find_for_oauth' do
let(:auth) { Fabricate(:identity, user: Fabricate(:user)) }
it 'calls .find_or_create_by' do
expect(described_class).to receive(:find_or_create_by).with(uid: auth.uid, provider: auth.provider)
described_class.find_for_oauth(auth)
end
it 'returns an instance of Identity' do
expect(described_class.find_for_oauth(auth)).to be_instance_of Identity
end
end
end

View File

@ -1,10 +1,6 @@
require 'rails_helper'
RSpec.describe Notification, type: :model do
describe '#from_account' do
pending
end
describe '#target_status' do
let(:notification) { Fabricate(:notification, activity: activity) }
let(:status) { Fabricate(:status) }
@ -101,7 +97,7 @@ RSpec.describe Notification, type: :model do
before do
allow(accounts_with_ids).to receive(:[]).with(stale_account1.id).and_return(account1)
allow(accounts_with_ids).to receive(:[]).with(stale_account2.id).and_return(account2)
allow(Account).to receive_message_chain(:where, :each_with_object).and_return(accounts_with_ids)
allow(Account).to receive_message_chain(:where, :includes, :each_with_object).and_return(accounts_with_ids)
end
let(:cached_items) do

View File

@ -0,0 +1,4 @@
require 'rails_helper'
RSpec.describe ScheduledStatus, type: :model do
end

View File

@ -1,5 +1,4 @@
require 'rails_helper'
RSpec.describe StatusStat, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -89,18 +89,6 @@ RSpec.describe User, type: :model do
expect(User.matches_email('specified')).to match_array([specified])
end
end
describe 'with_recent_ip_address' do
it 'returns a relation of users who is, or was at last time, online with the given IP address' do
specifieds = [
Fabricate(:user, current_sign_in_ip: '0.0.0.42', last_sign_in_ip: '0.0.0.0'),
Fabricate(:user, current_sign_in_ip: nil, last_sign_in_ip: '0.0.0.42')
]
Fabricate(:user, current_sign_in_ip: '0.0.0.0', last_sign_in_ip: '0.0.0.0')
expect(User.with_recent_ip_address('0.0.0.42')).to match_array(specifieds)
end
end
end
let(:account) { Fabricate(:account, username: 'alice') }
@ -118,19 +106,19 @@ RSpec.describe User, type: :model do
end
it 'should allow a non-blacklisted user to be created' do
user = User.new(email: 'foo@example.com', account: account, password: password)
user = User.new(email: 'foo@example.com', account: account, password: password, agreement: true)
expect(user.valid?).to be_truthy
end
it 'should not allow a blacklisted user to be created' do
user = User.new(email: 'foo@mvrht.com', account: account, password: password)
user = User.new(email: 'foo@mvrht.com', account: account, password: password, agreement: true)
expect(user.valid?).to be_falsey
end
it 'should not allow a subdomain blacklisted user to be created' do
user = User.new(email: 'foo@mvrht.com.topdomain.tld', account: account, password: password)
user = User.new(email: 'foo@mvrht.com.topdomain.tld', account: account, password: password, agreement: true)
expect(user.valid?).to be_falsey
end
@ -222,17 +210,17 @@ RSpec.describe User, type: :model do
end
it 'should not allow a user to be created unless they are whitelisted' do
user = User.new(email: 'foo@example.com', account: account, password: password)
user = User.new(email: 'foo@example.com', account: account, password: password, agreement: true)
expect(user.valid?).to be_falsey
end
it 'should allow a user to be created if they are whitelisted' do
user = User.new(email: 'foo@mastodon.space', account: account, password: password)
user = User.new(email: 'foo@mastodon.space', account: account, password: password, agreement: true)
expect(user.valid?).to be_truthy
end
it 'should not allow a user with a whitelisted top domain as subdomain in their email address to be created' do
user = User.new(email: 'foo@mastodon.space.userdomain.com', account: account, password: password)
user = User.new(email: 'foo@mastodon.space.userdomain.com', account: account, password: password, agreement: true)
expect(user.valid?).to be_falsey
end
@ -254,7 +242,7 @@ RSpec.describe User, type: :model do
it_behaves_like 'Settings-extended' do
def create!
User.create!(account: Fabricate(:account), email: 'foo@mastodon.space', password: 'abcd1234')
User.create!(account: Fabricate(:account), email: 'foo@mastodon.space', password: 'abcd1234', agreement: true)
end
def fabricate

View File

@ -0,0 +1,52 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe AccountModerationNotePolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :create? do
context 'staff' do
it 'grants to create' do
expect(subject).to permit(admin, AccountModerationNotePolicy)
end
end
context 'not staff' do
it 'denies to create' do
expect(subject).to_not permit(john, AccountModerationNotePolicy)
end
end
end
permissions :destroy? do
let(:account_moderation_note) do
Fabricate(:account_moderation_note,
account: john,
target_account: Fabricate(:account))
end
context 'admin' do
it 'grants to destroy' do
expect(subject).to permit(admin, AccountModerationNotePolicy)
end
end
context 'owner' do
it 'grants to destroy' do
expect(subject).to permit(john, account_moderation_note)
end
end
context 'neither admin nor owner' do
let(:kevin) { Fabricate(:user).account }
it 'denies to destroy' do
expect(subject).to_not permit(kevin, account_moderation_note)
end
end
end
end

View File

@ -0,0 +1,86 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe AccountPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :index?, :show?, :unsuspend?, :unsilence?, :remove_avatar?, :remove_header? do
context 'staff' do
it 'permits' do
expect(subject).to permit(admin)
end
end
context 'not staff' do
it 'denies' do
expect(subject).to_not permit(john)
end
end
end
permissions :redownload?, :subscribe?, :unsubscribe? do
context 'admin' do
it 'permits' do
expect(subject).to permit(admin)
end
end
context 'not admin' do
it 'denies' do
expect(subject).to_not permit(john)
end
end
end
permissions :suspend?, :silence? do
let(:staff) { Fabricate(:user, admin: true).account }
context 'staff' do
context 'record is staff' do
it 'denies' do
expect(subject).to_not permit(admin, staff)
end
end
context 'record is not staff' do
it 'permits' do
expect(subject).to permit(admin, john)
end
end
end
context 'not staff' do
it 'denies' do
expect(subject).to_not permit(john, Account)
end
end
end
permissions :memorialize? do
let(:other_admin) { Fabricate(:user, admin: true).account }
context 'admin' do
context 'record is admin' do
it 'denies' do
expect(subject).to_not permit(admin, other_admin)
end
end
context 'record is not admin' do
it 'permits' do
expect(subject).to permit(admin, john)
end
end
end
context 'not admin' do
it 'denies' do
expect(subject).to_not permit(john, Account)
end
end
end
end

View File

@ -0,0 +1,45 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe BackupPolicy do
let(:subject) { described_class }
let(:john) { Fabricate(:user).account }
permissions :create? do
context 'not user_signed_in?' do
it 'denies' do
expect(subject).to_not permit(nil, Backup)
end
end
context 'user_signed_in?' do
context 'no backups' do
it 'permits' do
expect(subject).to permit(john, Backup)
end
end
context 'backups are too old' do
it 'permits' do
travel(-8.days) do
Fabricate(:backup, user: john.user)
end
expect(subject).to permit(john, Backup)
end
end
context 'backups are newer' do
it 'denies' do
travel(-3.days) do
Fabricate(:backup, user: john.user)
end
expect(subject).to_not permit(john, Backup)
end
end
end
end
end

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe CustomEmojiPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :index?, :enable?, :disable? do
context 'staff' do
it 'permits' do
expect(subject).to permit(admin, CustomEmoji)
end
end
context 'not staff' do
it 'denies' do
expect(subject).to_not permit(john, CustomEmoji)
end
end
end
permissions :create?, :update?, :copy?, :destroy? do
context 'admin' do
it 'permits' do
expect(subject).to permit(admin, CustomEmoji)
end
end
context 'not admin' do
it 'denies' do
expect(subject).to_not permit(john, CustomEmoji)
end
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe DomainBlockPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :index?, :show?, :create?, :destroy? do
context 'admin' do
it 'permits' do
expect(subject).to permit(admin, DomainBlock)
end
end
context 'not admin' do
it 'denies' do
expect(subject).to_not permit(john, DomainBlock)
end
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe EmailDomainBlockPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :index?, :create?, :destroy? do
context 'admin' do
it 'permits' do
expect(subject).to permit(admin, EmailDomainBlock)
end
end
context 'not admin' do
it 'denies' do
expect(subject).to_not permit(john, EmailDomainBlock)
end
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe InstancePolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :index? do
context 'admin' do
it 'permits' do
expect(subject).to permit(admin, Instance)
end
end
context 'not admin' do
it 'denies' do
expect(subject).to_not permit(john, Instance)
end
end
end
end

View File

@ -0,0 +1,94 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe InvitePolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :index? do
context 'staff?' do
it 'permits' do
expect(subject).to permit(admin, Invite)
end
end
end
permissions :create? do
context 'min_required_role?' do
it 'permits' do
allow_any_instance_of(described_class).to receive(:min_required_role?) { true }
expect(subject).to permit(john, Invite)
end
end
context 'not min_required_role?' do
it 'denies' do
allow_any_instance_of(described_class).to receive(:min_required_role?) { false }
expect(subject).to_not permit(john, Invite)
end
end
end
permissions :deactivate_all? do
context 'admin?' do
it 'permits' do
expect(subject).to permit(admin, Invite)
end
end
context 'not admin?' do
it 'denies' do
expect(subject).to_not permit(john, Invite)
end
end
end
permissions :destroy? do
context 'owner?' do
it 'permits' do
expect(subject).to permit(john, Fabricate(:invite, user: john.user))
end
end
context 'not owner?' do
context 'Setting.min_invite_role == "admin"' do
before do
Setting.min_invite_role = 'admin'
end
context 'admin?' do
it 'permits' do
expect(subject).to permit(admin, Fabricate(:invite))
end
end
context 'not admin?' do
it 'denies' do
expect(subject).to_not permit(john, Fabricate(:invite))
end
end
end
context 'Setting.min_invite_role != "admin"' do
before do
Setting.min_invite_role = 'else'
end
context 'staff?' do
it 'permits' do
expect(subject).to permit(admin, Fabricate(:invite))
end
end
context 'not staff?' do
it 'denies' do
expect(subject).to_not permit(john, Fabricate(:invite))
end
end
end
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe RelayPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :update? do
context 'admin?' do
it 'permits' do
expect(subject).to permit(admin, Relay)
end
end
context '!admin?' do
it 'denies' do
expect(subject).to_not permit(john, Relay)
end
end
end
end

View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe ReportNotePolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :create? do
context 'staff?' do
it 'permits' do
expect(subject).to permit(admin, ReportNote)
end
end
context '!staff?' do
it 'denies' do
expect(subject).to_not permit(john, ReportNote)
end
end
end
permissions :destroy? do
context 'admin?' do
it 'permit' do
expect(subject).to permit(admin, ReportNote)
end
end
context 'admin?' do
context 'owner?' do
it 'permit' do
report_note = Fabricate(:report_note, account: john)
expect(subject).to permit(john, report_note)
end
end
context '!owner?' do
it 'denies' do
report_note = Fabricate(:report_note)
expect(subject).to_not permit(john, report_note)
end
end
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe ReportPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :update?, :index?, :show? do
context 'staff?' do
it 'permits' do
expect(subject).to permit(admin, Report)
end
end
context '!staff?' do
it 'denies' do
expect(subject).to_not permit(john, Report)
end
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe SettingsPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :update?, :show? do
context 'admin?' do
it 'permits' do
expect(subject).to permit(admin, Settings)
end
end
context '!admin?' do
it 'denies' do
expect(subject).to_not permit(john, Settings)
end
end
end
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
@ -118,4 +120,30 @@ RSpec.describe StatusPolicy, type: :model do
expect(subject).to_not permit(nil, status)
end
end
permissions :favourite? do
it 'grants access when viewer is not blocked' do
follow = Fabricate(:follow)
status.account = follow.target_account
expect(subject).to permit(follow.account, status)
end
it 'denies when viewer is blocked' do
block = Fabricate(:block)
status.account = block.target_account
expect(subject).to_not permit(block.account, status)
end
end
permissions :index?, :update? do
it 'grants access if staff' do
expect(subject).to permit(admin.account)
end
it 'denies access unless staff' do
expect(subject).to_not permit(alice)
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe SubscriptionPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :index? do
context 'admin?' do
it 'permits' do
expect(subject).to permit(admin, Subscription)
end
end
context '!admin?' do
it 'denies' do
expect(subject).to_not permit(john, Subscription)
end
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe TagPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :index?, :hide?, :unhide? do
context 'staff?' do
it 'permits' do
expect(subject).to permit(admin, Tag)
end
end
context '!staff?' do
it 'denies' do
expect(subject).to_not permit(john, Tag)
end
end
end
end

View File

@ -0,0 +1,167 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe UserPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :reset_password?, :change_email? do
context 'staff?' do
context '!record.staff?' do
it 'permits' do
expect(subject).to permit(admin, john.user)
end
end
context 'record.staff?' do
it 'denies' do
expect(subject).to_not permit(admin, admin.user)
end
end
end
context '!staff?' do
it 'denies' do
expect(subject).to_not permit(john, User)
end
end
end
permissions :disable_2fa? do
context 'admin?' do
context '!record.staff?' do
it 'permits' do
expect(subject).to permit(admin, john.user)
end
end
context 'record.staff?' do
it 'denies' do
expect(subject).to_not permit(admin, admin.user)
end
end
end
context '!admin?' do
it 'denies' do
expect(subject).to_not permit(john, User)
end
end
end
permissions :confirm? do
context 'staff?' do
context '!record.confirmed?' do
it 'permits' do
john.user.update(confirmed_at: nil)
expect(subject).to permit(admin, john.user)
end
end
context 'record.confirmed?' do
it 'denies' do
john.user.confirm!
expect(subject).to_not permit(admin, john.user)
end
end
end
context '!staff?' do
it 'denies' do
expect(subject).to_not permit(john, User)
end
end
end
permissions :enable? do
context 'staff?' do
it 'permits' do
expect(subject).to permit(admin, User)
end
end
context '!staff?' do
it 'denies' do
expect(subject).to_not permit(john, User)
end
end
end
permissions :disable? do
context 'staff?' do
context '!record.admin?' do
it 'permits' do
expect(subject).to permit(admin, john.user)
end
end
context 'record.admin?' do
it 'denies' do
expect(subject).to_not permit(admin, admin.user)
end
end
end
context '!staff?' do
it 'denies' do
expect(subject).to_not permit(john, User)
end
end
end
permissions :promote? do
context 'admin?' do
context 'promoteable?' do
it 'permits' do
expect(subject).to permit(admin, john.user)
end
end
context '!promoteable?' do
it 'denies' do
expect(subject).to_not permit(admin, admin.user)
end
end
end
context '!admin?' do
it 'denies' do
expect(subject).to_not permit(john, User)
end
end
end
permissions :demote? do
context 'admin?' do
context '!record.admin?' do
context 'demoteable?' do
it 'permits' do
john.user.update(moderator: true)
expect(subject).to permit(admin, john.user)
end
end
context '!demoteable?' do
it 'denies' do
expect(subject).to_not permit(admin, john.user)
end
end
end
context 'record.admin?' do
it 'denies' do
expect(subject).to_not permit(admin, admin.user)
end
end
end
context '!admin?' do
it 'denies' do
expect(subject).to_not permit(john, User)
end
end
end
end

View File

@ -111,4 +111,37 @@ describe InstancePresenter do
expect(instance_presenter.domain_count).to eq(345)
end
end
describe '#version_number' do
it 'returns Mastodon::Version' do
expect(instance_presenter.version_number).to be(Mastodon::Version)
end
end
describe '#source_url' do
it 'returns "https://github.com/tootsuite/mastodon"' do
expect(instance_presenter.source_url).to eq('https://github.com/tootsuite/mastodon')
end
end
describe '#thumbnail' do
it 'returns SiteUpload' do
thumbnail = Fabricate(:site_upload, var: 'thumbnail')
expect(instance_presenter.thumbnail).to eq(thumbnail)
end
end
describe '#hero' do
it 'returns SiteUpload' do
hero = Fabricate(:site_upload, var: 'hero')
expect(instance_presenter.hero).to eq(hero)
end
end
describe '#mascot' do
it 'returns SiteUpload' do
mascot = Fabricate(:site_upload, var: 'mascot')
expect(instance_presenter.mascot).to eq(mascot)
end
end
end

View File

@ -26,9 +26,9 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
context 'when actor differs from sender' do
let(:forwarder) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/other_account') }
it 'processes payload with sender if no signature exists' do
expect_any_instance_of(ActivityPub::LinkedDataSignature).not_to receive(:verify_account!)
expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), forwarder, instance_of(Hash))
it 'does not process payload if no signature exists' do
expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_account!).and_return(nil)
expect(ActivityPub::Activity).not_to receive(:factory)
subject.call(json, forwarder)
end

View File

@ -0,0 +1,41 @@
require 'rails_helper'
RSpec.describe AppSignUpService, type: :service do
let(:app) { Fabricate(:application, scopes: 'read write') }
let(:good_params) { { username: 'alice', password: '12345678', email: 'good@email.com', agreement: true } }
subject { described_class.new }
describe '#call' do
it 'returns nil when registrations are closed' do
Setting.open_registrations = false
expect(subject.call(app, good_params)).to be_nil
end
it 'raises an error when params are missing' do
expect { subject.call(app, {}) }.to raise_error ActiveRecord::RecordInvalid
end
it 'creates an unconfirmed user with access token' do
access_token = subject.call(app, good_params)
expect(access_token).to_not be_nil
user = User.find_by(id: access_token.resource_owner_id)
expect(user).to_not be_nil
expect(user.confirmed?).to be false
end
it 'creates access token with the app\'s scopes' do
access_token = subject.call(app, good_params)
expect(access_token).to_not be_nil
expect(access_token.scopes.to_s).to eq 'read write'
end
it 'creates an account' do
access_token = subject.call(app, good_params)
expect(access_token).to_not be_nil
user = User.find_by(id: access_token.resource_owner_id)
expect(user).to_not be_nil
expect(user.account).to_not be_nil
end
end
end

View File

@ -8,8 +8,8 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
let!(:jeff) { Fabricate(:user).account }
let!(:hank) { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
let(:status1) { PostStatusService.new.call(alice, 'Hello @bob@example.com') }
let(:status2) { PostStatusService.new.call(alice, 'Another status') }
let(:status1) { PostStatusService.new.call(alice, text: 'Hello @bob@example.com') }
let(:status2) { PostStatusService.new.call(alice, text: 'Another status') }
before do
allow(Redis.current).to receive_messages(publish: nil)

View File

@ -17,6 +17,8 @@ RSpec.describe FetchLinkCardService, type: :service do
stub_request(:head, 'https://github.com/qbi/WannaCry').to_return(status: 404)
stub_request(:head, 'http://example.com/test-').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
stub_request(:get, 'http://example.com/test-').to_return(request_fixture('idn.txt'))
stub_request(:head, 'http://example.com/windows-1251').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
stub_request(:get, 'http://example.com/windows-1251').to_return(request_fixture('windows-1251.txt'))
subject.call(status)
end
@ -57,6 +59,15 @@ RSpec.describe FetchLinkCardService, type: :service do
end
end
context do
let(:status) { Fabricate(:status, text: 'Check out http://example.com/windows-1251') }
it 'works with windows-1251' do
expect(a_request(:get, 'http://example.com/windows-1251')).to have_been_made.at_least_once
expect(status.preview_cards.first.title).to eq('сэмпл текст')
end
end
context do
let(:status) { Fabricate(:status, text: 'テストhttp://example.com/日本語') }

View File

@ -0,0 +1,60 @@
require 'rails_helper'
describe HashtagQueryService, type: :service do
describe '.call' do
let(:account) { Fabricate(:account) }
let(:tag1) { Fabricate(:tag) }
let(:tag2) { Fabricate(:tag) }
let!(:status1) { Fabricate(:status, tags: [tag1]) }
let!(:status2) { Fabricate(:status, tags: [tag2]) }
let!(:both) { Fabricate(:status, tags: [tag1, tag2]) }
it 'can add tags in "any" mode' do
results = subject.call(tag1, { any: [tag2.name] })
expect(results).to include status1
expect(results).to include status2
expect(results).to include both
end
it 'can remove tags in "all" mode' do
results = subject.call(tag1, { all: [tag2.name] })
expect(results).to_not include status1
expect(results).to_not include status2
expect(results).to include both
end
it 'can remove tags in "none" mode' do
results = subject.call(tag1, { none: [tag2.name] })
expect(results).to include status1
expect(results).to_not include status2
expect(results).to_not include both
end
it 'ignores an invalid mode' do
results = subject.call(tag1, { wark: [tag2.name] })
expect(results).to include status1
expect(results).to_not include status2
expect(results).to include both
end
it 'handles being passed non existant tag names' do
results = subject.call(tag1, { any: ['wark'] })
expect(results).to include status1
expect(results).to_not include status2
expect(results).to include both
end
it 'can restrict to an account' do
BlockService.new.call(account, status1.account)
results = subject.call(tag1, { none: [tag2.name] }, account)
expect(results).to_not include status1
end
it 'can restrict to local' do
status1.account.update(domain: 'example.com')
status1.update(local: false, uri: 'example.com/toot')
results = subject.call(tag1, { any: [tag2.name] }, nil, true)
expect(results).to_not include status1
end
end
end

View File

@ -7,7 +7,7 @@ RSpec.describe PostStatusService, type: :service do
account = Fabricate(:account)
text = "test status update"
status = subject.call(account, text)
status = subject.call(account, text: text)
expect(status).to be_persisted
expect(status.text).to eq text
@ -18,13 +18,37 @@ RSpec.describe PostStatusService, type: :service do
account = Fabricate(:account)
text = "test status update"
status = subject.call(account, text, in_reply_to_status)
status = subject.call(account, text: text, thread: in_reply_to_status)
expect(status).to be_persisted
expect(status.text).to eq text
expect(status.thread).to eq in_reply_to_status
end
it 'schedules a status' do
account = Fabricate(:account)
future = Time.now.utc + 2.hours
status = subject.call(account, text: 'Hi future!', scheduled_at: future)
expect(status).to be_a ScheduledStatus
expect(status.scheduled_at).to eq future
expect(status.params['text']).to eq 'Hi future!'
end
it 'creates response to the original status of boost' do
boosted_status = Fabricate(:status)
in_reply_to_status = Fabricate(:status, reblog: boosted_status)
account = Fabricate(:account)
text = "test status update"
status = subject.call(account, text: text, thread: in_reply_to_status)
expect(status).to be_persisted
expect(status.text).to eq text
expect(status.thread).to eq boosted_status
end
it 'creates a sensitive status' do
status = create_status_with_options(sensitive: true)
@ -55,6 +79,13 @@ RSpec.describe PostStatusService, type: :service do
expect(status.visibility).to eq "private"
end
it 'creates a status with limited visibility for silenced users' do
status = subject.call(Fabricate(:account, silenced: true), text: 'test', visibility: :public)
expect(status).to be_persisted
expect(status.visibility).to eq "unlisted"
end
it 'creates a status for the given application' do
application = Fabricate(:application)
@ -68,7 +99,7 @@ RSpec.describe PostStatusService, type: :service do
account = Fabricate(:account)
text = 'This is an English text.'
status = subject.call(account, text)
status = subject.call(account, text: text)
expect(status.language).to eq 'en'
end
@ -79,7 +110,7 @@ RSpec.describe PostStatusService, type: :service do
allow(ProcessMentionsService).to receive(:new).and_return(mention_service)
account = Fabricate(:account)
status = subject.call(account, "test status update")
status = subject.call(account, text: "test status update")
expect(ProcessMentionsService).to have_received(:new)
expect(mention_service).to have_received(:call).with(status)
@ -91,7 +122,7 @@ RSpec.describe PostStatusService, type: :service do
allow(ProcessHashtagsService).to receive(:new).and_return(hashtags_service)
account = Fabricate(:account)
status = subject.call(account, "test status update")
status = subject.call(account, text: "test status update")
expect(ProcessHashtagsService).to have_received(:new)
expect(hashtags_service).to have_received(:call).with(status)
@ -104,7 +135,7 @@ RSpec.describe PostStatusService, type: :service do
account = Fabricate(:account)
status = subject.call(account, "test status update")
status = subject.call(account, text: "test status update")
expect(DistributionWorker).to have_received(:perform_async).with(status.id)
expect(Pubsubhubbub::DistributionWorker).to have_received(:perform_async).with(status.stream_entry.id)
@ -115,7 +146,7 @@ RSpec.describe PostStatusService, type: :service do
allow(LinkCrawlWorker).to receive(:perform_async)
account = Fabricate(:account)
status = subject.call(account, "test status update")
status = subject.call(account, text: "test status update")
expect(LinkCrawlWorker).to have_received(:perform_async).with(status.id)
end
@ -126,8 +157,7 @@ RSpec.describe PostStatusService, type: :service do
status = subject.call(
account,
"test status update",
nil,
text: "test status update",
media_ids: [media.id],
)
@ -140,8 +170,7 @@ RSpec.describe PostStatusService, type: :service do
expect do
subject.call(
account,
"test status update",
nil,
text: "test status update",
media_ids: [
Fabricate(:media_attachment, account: account),
Fabricate(:media_attachment, account: account),
@ -162,8 +191,7 @@ RSpec.describe PostStatusService, type: :service do
expect do
subject.call(
account,
"test status update",
nil,
text: "test status update",
media_ids: [
Fabricate(:media_attachment, type: :video, account: account),
Fabricate(:media_attachment, type: :image, account: account),
@ -177,12 +205,12 @@ RSpec.describe PostStatusService, type: :service do
it 'returns existing status when used twice with idempotency key' do
account = Fabricate(:account)
status1 = subject.call(account, 'test', nil, idempotency: 'meepmeep')
status2 = subject.call(account, 'test', nil, idempotency: 'meepmeep')
status1 = subject.call(account, text: 'test', idempotency: 'meepmeep')
status2 = subject.call(account, text: 'test', idempotency: 'meepmeep')
expect(status2.id).to eq status1.id
end
def create_status_with_options(**options)
subject.call(Fabricate(:account), 'test', nil, options)
subject.call(Fabricate(:account), options.merge(text: 'test'))
end
end

View File

@ -19,7 +19,7 @@ RSpec.describe RemoveStatusService, type: :service do
jeff.follow!(alice)
hank.follow!(alice)
@status = PostStatusService.new.call(alice, 'Hello @bob@example.com')
@status = PostStatusService.new.call(alice, text: 'Hello @bob@example.com')
Fabricate(:status, account: bill, reblog: @status, uri: 'hoge')
subject.call(@status)
end

View File

@ -119,8 +119,6 @@ RSpec.describe ResolveAccountService, type: :service do
expect(account.actor_type).to eq 'Person'
end
end
pending
end
it 'processes one remote account at a time using locks' do

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe BlacklistedEmailValidator, type: :validator do
describe '#validate' do
let(:user) { double(email: 'info@mail.com', errors: errors) }
let(:errors) { double(add: nil) }
before do
allow_any_instance_of(described_class).to receive(:blocked_email?) { blocked_email }
described_class.new.validate(user)
end
context 'blocked_email?' do
let(:blocked_email) { true }
it 'calls errors.add' do
expect(errors).to have_received(:add).with(:email, I18n.t('users.invalid_email'))
end
end
context '!blocked_email?' do
let(:blocked_email) { false }
it 'not calls errors.add' do
expect(errors).not_to have_received(:add).with(:email, I18n.t('users.invalid_email'))
end
end
end
end

View File

@ -0,0 +1,46 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe DisallowedHashtagsValidator, type: :validator do
describe '#validate' do
before do
allow_any_instance_of(described_class).to receive(:select_tags) { tags }
described_class.new.validate(status)
end
let(:status) { double(errors: errors, local?: local, reblog?: reblog, text: '') }
let(:errors) { double(add: nil) }
context 'unless status.local? && !status.reblog?' do
let(:local) { false }
let(:reblog) { true }
it 'not calls errors.add' do
expect(errors).not_to have_received(:add).with(:text, any_args)
end
end
context 'status.local? && !status.reblog?' do
let(:local) { true }
let(:reblog) { false }
context 'tags.empty?' do
let(:tags) { [] }
it 'not calls errors.add' do
expect(errors).not_to have_received(:add).with(:text, any_args)
end
end
context '!tags.empty?' do
let(:tags) { %w(a b c) }
it 'calls errors.add' do
expect(errors).to have_received(:add)
.with(:text, I18n.t('statuses.disallowed_hashtags', tags: tags.join(', '), count: tags.size))
end
end
end
end
end

View File

@ -0,0 +1,75 @@
# frozen_string_literal: true
require 'rails_helper'
describe EmailMxValidator do
describe '#validate' do
let(:user) { double(email: 'foo@example.com', errors: double(add: nil)) }
it 'adds an error if there are no DNS records for the e-mail domain' do
resolver = double
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([])
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])
allow(resolver).to receive(:timeouts=).and_return(nil)
allow(Resolv::DNS).to receive(:open).and_yield(resolver)
subject.validate(user)
expect(user.errors).to have_received(:add)
end
it 'adds an error if a MX record exists but does not lead to an IP' do
resolver = double
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])
allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([])
allow(resolver).to receive(:timeouts=).and_return(nil)
allow(Resolv::DNS).to receive(:open).and_yield(resolver)
subject.validate(user)
expect(user.errors).to have_received(:add)
end
it 'adds an error if the A record is blacklisted' do
EmailDomainBlock.create!(domain: '1.2.3.4')
resolver = double
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([])
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([double(address: '1.2.3.4')])
allow(resolver).to receive(:timeouts=).and_return(nil)
allow(Resolv::DNS).to receive(:open).and_yield(resolver)
subject.validate(user)
expect(user.errors).to have_received(:add)
end
it 'adds an error if the MX record is blacklisted' do
EmailDomainBlock.create!(domain: '2.3.4.5')
resolver = double
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])
allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([double(address: '2.3.4.5')])
allow(resolver).to receive(:timeouts=).and_return(nil)
allow(Resolv::DNS).to receive(:open).and_yield(resolver)
subject.validate(user)
expect(user.errors).to have_received(:add)
end
it 'adds an error if the MX hostname is blacklisted' do
EmailDomainBlock.create!(domain: 'mail.example.com')
resolver = double
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])
allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([double(address: '2.3.4.5')])
allow(resolver).to receive(:timeouts=).and_return(nil)
allow(Resolv::DNS).to receive(:open).and_yield(resolver)
subject.validate(user)
expect(user.errors).to have_received(:add)
end
end
end

View File

@ -0,0 +1,51 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe FollowLimitValidator, type: :validator do
describe '#validate' do
before do
allow_any_instance_of(described_class).to receive(:limit_reached?).with(account) do
limit_reached
end
described_class.new.validate(follow)
end
let(:follow) { double(account: account, errors: errors) }
let(:errors) { double(add: nil) }
let(:account) { double(nil?: _nil, local?: local, following_count: 0, followers_count: 0) }
let(:_nil) { true }
let(:local) { false }
context 'follow.account.nil? || !follow.account.local?' do
let(:_nil) { true }
it 'not calls errors.add' do
expect(errors).not_to have_received(:add).with(:base, any_args)
end
end
context '!(follow.account.nil? || !follow.account.local?)' do
let(:_nil) { false }
let(:local) { true }
context 'limit_reached?' do
let(:limit_reached) { true }
it 'calls errors.add' do
expect(errors).to have_received(:add)
.with(:base, I18n.t('users.follow_limit_reached', limit: FollowLimitValidator::LIMIT))
end
end
context '!limit_reached?' do
let(:limit_reached) { false }
it 'not calls errors.add' do
expect(errors).not_to have_received(:add).with(:base, any_args)
end
end
end
end
end

View File

@ -4,8 +4,17 @@ require 'rails_helper'
describe StatusLengthValidator do
describe '#validate' do
it 'does not add errors onto remote statuses'
it 'does not add errors onto local reblogs'
it 'does not add errors onto remote statuses' do
status = double(local?: false)
subject.validate(status)
expect(status).not_to receive(:errors)
end
it 'does not add errors onto local reblogs' do
status = double(local?: false, reblog?: true)
subject.validate(status)
expect(status).not_to receive(:errors)
end
it 'adds an error when content warning is over 500 characters' do
status = double(spoiler_text: 'a' * 520, text: '', errors: double(add: nil), local?: true, reblog?: false)

View File

@ -0,0 +1,57 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe StatusPinValidator, type: :validator do
describe '#validate' do
before do
subject.validate(pin)
end
let(:pin) { double(account: account, errors: errors, status: status, account_id: pin_account_id) }
let(:status) { double(reblog?: reblog, account_id: status_account_id, visibility: visibility) }
let(:account) { double(status_pins: status_pins, local?: local) }
let(:status_pins) { double(count: count) }
let(:errors) { double(add: nil) }
let(:pin_account_id) { 1 }
let(:status_account_id) { 1 }
let(:visibility) { 'public' }
let(:local) { false }
let(:reblog) { false }
let(:count) { 0 }
context 'pin.status.reblog?' do
let(:reblog) { true }
it 'calls errors.add' do
expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.reblog'))
end
end
context 'pin.account_id != pin.status.account_id' do
let(:pin_account_id) { 1 }
let(:status_account_id) { 2 }
it 'calls errors.add' do
expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.ownership'))
end
end
context 'unless %w(public unlisted).include?(pin.status.visibility)' do
let(:visibility) { '' }
it 'calls errors.add' do
expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.private'))
end
end
context 'pin.account.status_pins.count > 4 && pin.account.local?' do
let(:count) { 5 }
let(:local) { true }
it 'calls errors.add' do
expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.limit'))
end
end
end
end

View File

@ -15,14 +15,6 @@ describe UniqueUsernameValidator do
expect(account).to be_valid
end
it 'adds an error when the username is already used with ignoring dots' do
pending 'allowing dots in username is still in development'
Fabricate(:account, username: 'abcd.ef')
account = double(username: 'ab.cdef', persisted?: false, errors: double(add: nil))
subject.validate(account)
expect(account.errors).to have_received(:add)
end
it 'adds an error when the username is already used with ignoring cases' do
Fabricate(:account, username: 'ABCdef')
account = double(username: 'abcDEF', persisted?: false, errors: double(add: nil))

View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe UnreservedUsernameValidator, type: :validator do
describe '#validate' do
before do
allow(validator).to receive(:reserved_username?) { reserved_username }
validator.validate(account)
end
let(:validator) { described_class.new }
let(:account) { double(username: username, errors: errors) }
let(:errors ) { double(add: nil) }
context '@username.nil?' do
let(:username) { nil }
it 'not calls errors.add' do
expect(errors).not_to have_received(:add).with(:username, any_args)
end
end
context '!@username.nil?' do
let(:username) { '' }
context 'reserved_username?' do
let(:reserved_username) { true }
it 'calls erros.add' do
expect(errors).to have_received(:add).with(:username, I18n.t('accounts.reserved_username'))
end
end
context '!reserved_username?' do
let(:reserved_username) { false }
it 'not calls erros.add' do
expect(errors).not_to have_received(:add).with(:username, any_args)
end
end
end
end
end

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe UrlValidator, type: :validator do
describe '#validate_each' do
before do
allow(validator).to receive(:compliant?).with(value) { compliant }
validator.validate_each(record, attribute, value)
end
let(:validator) { described_class.new(attributes: [attribute]) }
let(:record) { double(errors: errors) }
let(:errors) { double(add: nil) }
let(:value) { '' }
let(:attribute) { :foo }
context 'unless compliant?' do
let(:compliant) { false }
it 'calls errors.add' do
expect(errors).to have_received(:add).with(attribute, I18n.t('applications.invalid_url'))
end
end
context 'if compliant?' do
let(:compliant) { true }
it 'not calls errors.add' do
expect(errors).not_to have_received(:add).with(attribute, any_args)
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