diff options
Diffstat (limited to 'spec')
38 files changed, 454 insertions, 566 deletions
diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb index 73b50e721..7824854f9 100644 --- a/spec/controllers/admin/dashboard_controller_spec.rb +++ b/spec/controllers/admin/dashboard_controller_spec.rb @@ -3,9 +3,19 @@ require 'rails_helper' describe Admin::DashboardController, type: :controller do + render_views + describe 'GET #index' do - it 'returns 200' do + before do + allow(Admin::SystemCheck).to receive(:perform).and_return([ + Admin::SystemCheck::Message.new(:database_schema_check), + Admin::SystemCheck::Message.new(:rules_check, nil, admin_rules_path), + Admin::SystemCheck::Message.new(:sidekiq_process_check, 'foo, bar'), + ]) sign_in Fabricate(:user, admin: true) + end + + it 'returns 200' do get :index expect(response).to have_http_status(200) diff --git a/spec/controllers/api/v1/apps_controller_spec.rb b/spec/controllers/api/v1/apps_controller_spec.rb index 60a4c3b41..70cd62d48 100644 --- a/spec/controllers/api/v1/apps_controller_spec.rb +++ b/spec/controllers/api/v1/apps_controller_spec.rb @@ -4,23 +4,83 @@ RSpec.describe Api::V1::AppsController, type: :controller do render_views describe 'POST #create' do + let(:client_name) { 'Test app' } + let(:scopes) { nil } + let(:redirect_uris) { 'urn:ietf:wg:oauth:2.0:oob' } + let(:website) { nil } + + let(:app_params) do + { + client_name: client_name, + redirect_uris: redirect_uris, + scopes: scopes, + website: website, + } + end + before do - post :create, params: { client_name: 'Test app', redirect_uris: 'urn:ietf:wg:oauth:2.0:oob' } + post :create, params: app_params end - it 'returns http success' do - expect(response).to have_http_status(200) + context 'with valid params' do + it 'returns http success' do + expect(response).to have_http_status(200) + end + + it 'creates an OAuth app' do + expect(Doorkeeper::Application.find_by(name: client_name)).to_not be nil + end + + it 'returns client ID and client secret' do + json = body_as_json + + expect(json[:client_id]).to_not be_blank + expect(json[:client_secret]).to_not be_blank + end + end + + context 'with an unsupported scope' do + let(:scopes) { 'hoge' } + + it 'returns http unprocessable entity' do + expect(response).to have_http_status(422) + end end - it 'creates an OAuth app' do - expect(Doorkeeper::Application.find_by(name: 'Test app')).to_not be nil + context 'with many duplicate scopes' do + let(:scopes) { (%w(read) * 40).join(' ') } + + it 'returns http success' do + expect(response).to have_http_status(200) + end + + it 'only saves the scope once' do + expect(Doorkeeper::Application.find_by(name: client_name).scopes.to_s).to eq 'read' + end + end + + context 'with a too-long name' do + let(:client_name) { 'hoge' * 20 } + + it 'returns http unprocessable entity' do + expect(response).to have_http_status(422) + end + end + + context 'with a too-long website' do + let(:website) { 'https://foo.bar/' + ('hoge' * 2_000) } + + it 'returns http unprocessable entity' do + expect(response).to have_http_status(422) + end end - it 'returns client ID and client secret' do - json = body_as_json + context 'with a too-long redirect_uris' do + let(:redirect_uris) { 'https://foo.bar/' + ('hoge' * 2_000) } - expect(json[:client_id]).to_not be_blank - expect(json[:client_secret]).to_not be_blank + it 'returns http unprocessable entity' do + expect(response).to have_http_status(422) + end end end end diff --git a/spec/controllers/api/v1/push/subscriptions_controller_spec.rb b/spec/controllers/api/v1/push/subscriptions_controller_spec.rb index 01146294f..534d02879 100644 --- a/spec/controllers/api/v1/push/subscriptions_controller_spec.rb +++ b/spec/controllers/api/v1/push/subscriptions_controller_spec.rb @@ -27,20 +27,27 @@ describe Api::V1::Push::SubscriptionsController do let(:alerts_payload) do { data: { + policy: 'all', + alerts: { follow: true, + follow_request: true, favourite: false, reblog: true, mention: false, + poll: true, + status: false, } } }.with_indifferent_access end describe 'POST #create' do - it 'saves push subscriptions' do + before do post :create, params: create_payload + end + it 'saves push subscriptions' do push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]) expect(push_subscription.endpoint).to eq(create_payload[:subscription][:endpoint]) @@ -52,31 +59,34 @@ describe Api::V1::Push::SubscriptionsController do it 'replaces old subscription on repeat calls' do post :create, params: create_payload - post :create, params: create_payload - expect(Web::PushSubscription.where(endpoint: create_payload[:subscription][:endpoint]).count).to eq 1 end end describe 'PUT #update' do - it 'changes alert settings' do + before do post :create, params: create_payload put :update, params: alerts_payload + end + it 'changes alert settings' do push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]) - expect(push_subscription.data.dig('alerts', 'follow')).to eq(alerts_payload[:data][:alerts][:follow].to_s) - expect(push_subscription.data.dig('alerts', 'favourite')).to eq(alerts_payload[:data][:alerts][:favourite].to_s) - expect(push_subscription.data.dig('alerts', 'reblog')).to eq(alerts_payload[:data][:alerts][:reblog].to_s) - expect(push_subscription.data.dig('alerts', 'mention')).to eq(alerts_payload[:data][:alerts][:mention].to_s) + expect(push_subscription.data['policy']).to eq(alerts_payload[:data][:policy]) + + %w(follow follow_request favourite reblog mention poll status).each do |type| + expect(push_subscription.data['alerts'][type]).to eq(alerts_payload[:data][:alerts][type.to_sym].to_s) + end end end describe 'DELETE #destroy' do - it 'removes the subscription' do + before do post :create, params: create_payload delete :destroy + end + it 'removes the subscription' do expect(Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint])).to be_nil end end diff --git a/spec/controllers/api/web/push_subscriptions_controller_spec.rb b/spec/controllers/api/web/push_subscriptions_controller_spec.rb index 381cdeab9..bda4a7661 100644 --- a/spec/controllers/api/web/push_subscriptions_controller_spec.rb +++ b/spec/controllers/api/web/push_subscriptions_controller_spec.rb @@ -22,11 +22,16 @@ describe Api::Web::PushSubscriptionsController do let(:alerts_payload) do { data: { + policy: 'all', + alerts: { follow: true, + follow_request: false, favourite: false, reblog: true, mention: false, + poll: true, + status: false, } } } @@ -59,10 +64,11 @@ describe Api::Web::PushSubscriptionsController do push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]) - expect(push_subscription.data['alerts']['follow']).to eq(alerts_payload[:data][:alerts][:follow].to_s) - expect(push_subscription.data['alerts']['favourite']).to eq(alerts_payload[:data][:alerts][:favourite].to_s) - expect(push_subscription.data['alerts']['reblog']).to eq(alerts_payload[:data][:alerts][:reblog].to_s) - expect(push_subscription.data['alerts']['mention']).to eq(alerts_payload[:data][:alerts][:mention].to_s) + expect(push_subscription.data['policy']).to eq 'all' + + %w(follow follow_request favourite reblog mention poll status).each do |type| + expect(push_subscription.data['alerts'][type]).to eq(alerts_payload[:data][:alerts][type.to_sym].to_s) + end end end end @@ -81,10 +87,11 @@ describe Api::Web::PushSubscriptionsController do push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]) - expect(push_subscription.data['alerts']['follow']).to eq(alerts_payload[:data][:alerts][:follow].to_s) - expect(push_subscription.data['alerts']['favourite']).to eq(alerts_payload[:data][:alerts][:favourite].to_s) - expect(push_subscription.data['alerts']['reblog']).to eq(alerts_payload[:data][:alerts][:reblog].to_s) - expect(push_subscription.data['alerts']['mention']).to eq(alerts_payload[:data][:alerts][:mention].to_s) + expect(push_subscription.data['policy']).to eq 'all' + + %w(follow follow_request favourite reblog mention poll status).each do |type| + expect(push_subscription.data['alerts'][type]).to eq(alerts_payload[:data][:alerts][type.to_sym].to_s) + end end end end diff --git a/spec/controllers/auth/confirmations_controller_spec.rb b/spec/controllers/auth/confirmations_controller_spec.rb index 0b6b74ff9..8469119d2 100644 --- a/spec/controllers/auth/confirmations_controller_spec.rb +++ b/spec/controllers/auth/confirmations_controller_spec.rb @@ -32,6 +32,52 @@ describe Auth::ConfirmationsController, type: :controller do end end + context 'when user is unconfirmed and unapproved' do + let!(:user) { Fabricate(:user, confirmation_token: 'foobar', confirmed_at: nil, approved: false) } + + before do + allow(BootstrapTimelineWorker).to receive(:perform_async) + @request.env['devise.mapping'] = Devise.mappings[:user] + get :show, params: { confirmation_token: 'foobar' } + end + + it 'redirects to login' do + expect(response).to redirect_to(new_user_session_path) + end + end + + context 'when user is already confirmed' do + let!(:user) { Fabricate(:user) } + + before do + allow(BootstrapTimelineWorker).to receive(:perform_async) + @request.env['devise.mapping'] = Devise.mappings[:user] + sign_in(user, scope: :user) + get :show, params: { confirmation_token: 'foobar' } + end + + it 'redirects to root path' do + expect(response).to redirect_to(root_path) + end + end + + context 'when user is already confirmed but unapproved' do + let!(:user) { Fabricate(:user, approved: false) } + + before do + allow(BootstrapTimelineWorker).to receive(:perform_async) + @request.env['devise.mapping'] = Devise.mappings[:user] + user.approved = false + user.save! + sign_in(user, scope: :user) + get :show, params: { confirmation_token: 'foobar' } + end + + it 'redirects to settings' do + expect(response).to redirect_to(edit_user_registration_path) + end + end + context 'when user is updating email' do let!(:user) { Fabricate(:user, confirmation_token: 'foobar', unconfirmed_email: 'new-email@example.com') } diff --git a/spec/controllers/relationships_controller_spec.rb b/spec/controllers/relationships_controller_spec.rb index 16e255afe..2056a2ac2 100644 --- a/spec/controllers/relationships_controller_spec.rb +++ b/spec/controllers/relationships_controller_spec.rb @@ -36,11 +36,7 @@ describe RelationshipsController do end describe 'PATCH #update' do - let(:poopfeast) { Fabricate(:account, username: 'poopfeast', domain: 'example.com', salmon_url: 'http://example.com/salmon') } - - before do - stub_request(:post, 'http://example.com/salmon').to_return(status: 200) - end + let(:poopfeast) { Fabricate(:account, username: 'poopfeast', domain: 'example.com') } shared_examples 'redirects back to followers page' do it 'redirects back to followers page' do diff --git a/spec/fabricators/canonical_email_block_fabricator.rb b/spec/fabricators/canonical_email_block_fabricator.rb new file mode 100644 index 000000000..a0b6e0d22 --- /dev/null +++ b/spec/fabricators/canonical_email_block_fabricator.rb @@ -0,0 +1,4 @@ +Fabricator(:canonical_email_block) do + email "test@example.com" + reference_account { Fabricate(:account) } +end diff --git a/spec/fabricators/follow_recommendation_suppression_fabricator.rb b/spec/fabricators/follow_recommendation_suppression_fabricator.rb new file mode 100644 index 000000000..4a6a07a66 --- /dev/null +++ b/spec/fabricators/follow_recommendation_suppression_fabricator.rb @@ -0,0 +1,3 @@ +Fabricator(:follow_recommendation_suppression) do + account +end diff --git a/spec/lib/activitypub/activity/delete_spec.rb b/spec/lib/activitypub/activity/delete_spec.rb index 37b93ecf7..9dfb8a61b 100644 --- a/spec/lib/activitypub/activity/delete_spec.rb +++ b/spec/lib/activitypub/activity/delete_spec.rb @@ -49,4 +49,24 @@ RSpec.describe ActivityPub::Activity::Delete do end end end + + context 'when the status has been reported' do + describe '#perform' do + subject { described_class.new(json, sender) } + let!(:reporter) { Fabricate(:account) } + + before do + reporter.reports.create!(target_account: status.account, status_ids: [status.id], forwarded: false) + subject.perform + end + + it 'marks the status as deleted' do + expect(Status.find_by(id: status.id)).to be_nil + end + + it 'actually keeps a copy for inspection' do + expect(Status.with_discarded.find_by(id: status.id)).to_not be_nil + end + end + end end diff --git a/spec/lib/activitypub/activity/update_spec.rb b/spec/lib/activitypub/activity/update_spec.rb index 42da29860..1c9bcf43b 100644 --- a/spec/lib/activitypub/activity/update_spec.rb +++ b/spec/lib/activitypub/activity/update_spec.rb @@ -13,7 +13,7 @@ RSpec.describe ActivityPub::Activity::Update do end let(:modified_sender) do - sender.dup.tap do |modified_sender| + sender.tap do |modified_sender| modified_sender.display_name = 'Totally modified now' end end diff --git a/spec/lib/spam_check_spec.rb b/spec/lib/spam_check_spec.rb deleted file mode 100644 index 159d83257..000000000 --- a/spec/lib/spam_check_spec.rb +++ /dev/null @@ -1,192 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe SpamCheck do - let!(:sender) { Fabricate(:account) } - let!(:alice) { Fabricate(:account, username: 'alice') } - let!(:bob) { Fabricate(:account, username: 'bob') } - - def status_with_html(text, options = {}) - status = PostStatusService.new.call(sender, { text: text }.merge(options)) - status.update_columns(text: Formatter.instance.format(status), local: false) - status - end - - describe '#hashable_text' do - it 'removes mentions from HTML for remote statuses' do - status = status_with_html('@alice Hello') - expect(described_class.new(status).hashable_text).to eq 'hello' - end - - it 'removes mentions from text for local statuses' do - status = PostStatusService.new.call(alice, text: "Hey @#{sender.username}, how are you?") - expect(described_class.new(status).hashable_text).to eq 'hey , how are you?' - end - end - - describe '#insufficient_data?' do - it 'returns true when there is no text' do - status = status_with_html('@alice') - expect(described_class.new(status).insufficient_data?).to be true - end - - it 'returns false when there is text' do - status = status_with_html('@alice h') - expect(described_class.new(status).insufficient_data?).to be false - end - end - - describe '#digest' do - it 'returns a string' do - status = status_with_html('@alice Hello world') - expect(described_class.new(status).digest).to be_a String - end - end - - describe '#spam?' do - it 'returns false for a unique status' do - status = status_with_html('@alice Hello') - expect(described_class.new(status).spam?).to be false - end - - it 'returns false for different statuses to the same recipient' do - status1 = status_with_html('@alice Hello') - described_class.new(status1).remember! - status2 = status_with_html('@alice Are you available to talk?') - expect(described_class.new(status2).spam?).to be false - end - - it 'returns false for statuses with different content warnings' do - status1 = status_with_html('@alice Are you available to talk?') - described_class.new(status1).remember! - status2 = status_with_html('@alice Are you available to talk?', spoiler_text: 'This is a completely different matter than what I was talking about previously, I swear!') - expect(described_class.new(status2).spam?).to be false - end - - it 'returns false for different statuses to different recipients' do - status1 = status_with_html('@alice How is it going?') - described_class.new(status1).remember! - status2 = status_with_html('@bob Are you okay?') - expect(described_class.new(status2).spam?).to be false - end - - it 'returns false for very short different statuses to different recipients' do - status1 = status_with_html('@alice 🙄') - described_class.new(status1).remember! - status2 = status_with_html('@bob Huh?') - expect(described_class.new(status2).spam?).to be false - end - - it 'returns false for statuses with no text' do - status1 = status_with_html('@alice') - described_class.new(status1).remember! - status2 = status_with_html('@bob') - expect(described_class.new(status2).spam?).to be false - end - - it 'returns true for duplicate statuses to the same recipient' do - described_class::THRESHOLD.times do - status1 = status_with_html('@alice Hello') - described_class.new(status1).remember! - end - - status2 = status_with_html('@alice Hello') - expect(described_class.new(status2).spam?).to be true - end - - it 'returns true for duplicate statuses to different recipients' do - described_class::THRESHOLD.times do - status1 = status_with_html('@alice Hello') - described_class.new(status1).remember! - end - - status2 = status_with_html('@bob Hello') - expect(described_class.new(status2).spam?).to be true - end - - it 'returns true for nearly identical statuses with random numbers' do - source_text = 'Sodium, atomic number 11, was first isolated by Humphry Davy in 1807. A chemical component of salt, he named it Na in honor of the saltiest region on earth, North America.' - - described_class::THRESHOLD.times do - status1 = status_with_html('@alice ' + source_text + ' 1234') - described_class.new(status1).remember! - end - - status2 = status_with_html('@bob ' + source_text + ' 9568') - expect(described_class.new(status2).spam?).to be true - end - end - - describe '#skip?' do - it 'returns true when the sender is already silenced' do - status = status_with_html('@alice Hello') - sender.silence! - expect(described_class.new(status).skip?).to be true - end - - it 'returns true when the mentioned person follows the sender' do - status = status_with_html('@alice Hello') - alice.follow!(sender) - expect(described_class.new(status).skip?).to be true - end - - it 'returns false when even one mentioned person doesn\'t follow the sender' do - status = status_with_html('@alice @bob Hello') - alice.follow!(sender) - expect(described_class.new(status).skip?).to be false - end - - it 'returns true when the sender is replying to a status that mentions the sender' do - parent = PostStatusService.new.call(alice, text: "Hey @#{sender.username}, how are you?") - status = status_with_html('@alice @bob Hello', thread: parent) - expect(described_class.new(status).skip?).to be true - end - end - - describe '#remember!' do - let(:status) { status_with_html('@alice') } - let(:spam_check) { described_class.new(status) } - let(:redis_key) { spam_check.send(:redis_key) } - - it 'remembers' do - expect(Redis.current.exists?(redis_key)).to be true - spam_check.remember! - expect(Redis.current.exists?(redis_key)).to be true - end - end - - describe '#reset!' do - let(:status) { status_with_html('@alice') } - let(:spam_check) { described_class.new(status) } - let(:redis_key) { spam_check.send(:redis_key) } - - before do - spam_check.remember! - end - - it 'resets' do - expect(Redis.current.exists?(redis_key)).to be true - spam_check.reset! - expect(Redis.current.exists?(redis_key)).to be false - end - end - - describe '#flag!' do - let!(:status1) { status_with_html('@alice General Kenobi you are a bold one') } - let!(:status2) { status_with_html('@alice @bob General Kenobi, you are a bold one') } - - before do - described_class.new(status1).remember! - described_class.new(status2).flag! - end - - it 'creates a report about the account' do - expect(sender.targeted_reports.unresolved.count).to eq 1 - end - - it 'attaches both matching statuses to the report' do - expect(sender.targeted_reports.first.status_ids).to include(status1.id, status2.id) - end - end -end diff --git a/spec/lib/tag_manager_spec.rb b/spec/lib/tag_manager_spec.rb index e9a7aa934..2230f9710 100644 --- a/spec/lib/tag_manager_spec.rb +++ b/spec/lib/tag_manager_spec.rb @@ -83,40 +83,4 @@ RSpec.describe TagManager do expect(TagManager.instance.local_url?('https://domainn.test/')).to eq false end end - - describe '#same_acct?' do - # The following comparisons MUST be case-insensitive. - - it 'returns true if the needle has a correct username and domain for remote user' do - expect(TagManager.instance.same_acct?('username@domain.test', 'UsErNaMe@DoMaIn.Test')).to eq true - end - - it 'returns false if the needle is missing a domain for remote user' do - expect(TagManager.instance.same_acct?('username@domain.test', 'UsErNaMe')).to eq false - end - - it 'returns false if the needle has an incorrect domain for remote user' do - expect(TagManager.instance.same_acct?('username@domain.test', 'UsErNaMe@incorrect.test')).to eq false - end - - it 'returns false if the needle has an incorrect username for remote user' do - expect(TagManager.instance.same_acct?('username@domain.test', 'incorrect@DoMaIn.test')).to eq false - end - - it 'returns true if the needle has a correct username and domain for local user' do - expect(TagManager.instance.same_acct?('username', 'UsErNaMe@Cb6E6126.nGrOk.Io')).to eq true - end - - it 'returns true if the needle is missing a domain for local user' do - expect(TagManager.instance.same_acct?('username', 'UsErNaMe')).to eq true - end - - it 'returns false if the needle has an incorrect username for local user' do - expect(TagManager.instance.same_acct?('username', 'UsErNaM@Cb6E6126.nGrOk.Io')).to eq false - end - - it 'returns false if the needle has an incorrect domain for local user' do - expect(TagManager.instance.same_acct?('username', 'incorrect@Cb6E6126.nGrOk.Io')).to eq false - end - end end diff --git a/spec/mailers/notification_mailer_spec.rb b/spec/mailers/notification_mailer_spec.rb index 38916b54f..9b645bad8 100644 --- a/spec/mailers/notification_mailer_spec.rb +++ b/spec/mailers/notification_mailer_spec.rb @@ -10,12 +10,12 @@ RSpec.describe NotificationMailer, type: :mailer do it 'renders subject localized for the locale of the receiver' do locale = %i(de en).sample receiver.update!(locale: locale) - expect(mail.subject).to eq I18n.t(*args, kwrest.merge(locale: locale)) + expect(mail.subject).to eq I18n.t(*args, **kwrest.merge(locale: locale)) end it 'renders subject localized for the default locale if the locale of the receiver is unavailable' do receiver.update!(locale: nil) - expect(mail.subject).to eq I18n.t(*args, kwrest.merge(locale: I18n.default_locale)) + expect(mail.subject).to eq I18n.t(*args, **kwrest.merge(locale: I18n.default_locale)) end end @@ -59,12 +59,12 @@ RSpec.describe NotificationMailer, type: :mailer do include_examples 'localized subject', 'notification_mailer.favourite.subject', name: 'bob' it "renders the headers" do - expect(mail.subject).to eq("bob favourited your status") + expect(mail.subject).to eq("bob favourited your post") expect(mail.to).to eq([receiver.email]) end it "renders the body" do - expect(mail.body.encoded).to match("Your status was favourited by bob") + expect(mail.body.encoded).to match("Your post was favourited by bob") expect(mail.body.encoded).to include 'The body of the own status' end end @@ -76,12 +76,12 @@ RSpec.describe NotificationMailer, type: :mailer do include_examples 'localized subject', 'notification_mailer.reblog.subject', name: 'bob' it "renders the headers" do - expect(mail.subject).to eq("bob boosted your status") + expect(mail.subject).to eq("bob boosted your post") expect(mail.to).to eq([receiver.email]) end it "renders the body" do - expect(mail.body.encoded).to match("Your status was boosted by bob") + expect(mail.body.encoded).to match("Your post was boosted by bob") expect(mail.body.encoded).to include 'The body of the own status' end end diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 6b430b505..9c866788f 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -9,12 +9,12 @@ describe UserMailer, type: :mailer do it 'renders subject localized for the locale of the receiver' do locale = I18n.available_locales.sample receiver.update!(locale: locale) - expect(mail.subject).to eq I18n.t(*args, kwrest.merge(locale: locale)) + expect(mail.subject).to eq I18n.t(*args, **kwrest.merge(locale: locale)) end it 'renders subject localized for the default locale if the locale of the receiver is unavailable' do receiver.update!(locale: nil) - expect(mail.subject).to eq I18n.t(*args, kwrest.merge(locale: I18n.default_locale)) + expect(mail.subject).to eq I18n.t(*args, **kwrest.merge(locale: I18n.default_locale)) end end diff --git a/spec/models/account_tag_stat_spec.rb b/spec/models/account_tag_stat_spec.rb deleted file mode 100644 index 6d3057f35..000000000 --- a/spec/models/account_tag_stat_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# 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 diff --git a/spec/models/canonical_email_block_spec.rb b/spec/models/canonical_email_block_spec.rb new file mode 100644 index 000000000..8e0050d65 --- /dev/null +++ b/spec/models/canonical_email_block_spec.rb @@ -0,0 +1,47 @@ +require 'rails_helper' + +RSpec.describe CanonicalEmailBlock, type: :model do + describe '#email=' do + let(:target_hash) { '973dfe463ec85785f5f95af5ba3906eedb2d931c24e69824a89ea65dba4e813b' } + + it 'sets canonical_email_hash' do + subject.email = 'test@example.com' + expect(subject.canonical_email_hash).to eq target_hash + end + + it 'sets the same hash even with dot permutations' do + subject.email = 't.e.s.t@example.com' + expect(subject.canonical_email_hash).to eq target_hash + end + + it 'sets the same hash even with extensions' do + subject.email = 'test+mastodon1@example.com' + expect(subject.canonical_email_hash).to eq target_hash + end + + it 'sets the same hash with different casing' do + subject.email = 'Test@EXAMPLE.com' + expect(subject.canonical_email_hash).to eq target_hash + end + end + + describe '.block?' do + let!(:canonical_email_block) { Fabricate(:canonical_email_block, email: 'foo@bar.com') } + + it 'returns true for the same email' do + expect(described_class.block?('foo@bar.com')).to be true + end + + it 'returns true for the same email with dots' do + expect(described_class.block?('f.oo@bar.com')).to be true + end + + it 'returns true for the same email with extensions' do + expect(described_class.block?('foo+spam@bar.com')).to be true + end + + it 'returns false for different email' do + expect(described_class.block?('hoge@bar.com')).to be false + end + end +end diff --git a/spec/models/follow_recommendation_suppression_spec.rb b/spec/models/follow_recommendation_suppression_spec.rb new file mode 100644 index 000000000..39107a2b0 --- /dev/null +++ b/spec/models/follow_recommendation_suppression_spec.rb @@ -0,0 +1,4 @@ +require 'rails_helper' + +RSpec.describe FollowRecommendationSuppression, type: :model do +end diff --git a/spec/models/follow_request_spec.rb b/spec/models/follow_request_spec.rb index 7c8e121d9..b0e854f09 100644 --- a/spec/models/follow_request_spec.rb +++ b/spec/models/follow_request_spec.rb @@ -7,7 +7,7 @@ RSpec.describe FollowRequest, type: :model do let(:target_account) { Fabricate(:account) } it 'calls Account#follow!, MergeWorker.perform_async, and #destroy!' do - expect(account).to receive(:follow!).with(target_account, reblogs: true, notify: false, uri: follow_request.uri) + expect(account).to receive(:follow!).with(target_account, reblogs: true, notify: false, uri: follow_request.uri, bypass_limit: true) expect(MergeWorker).to receive(:perform_async).with(target_account.id, account.id) expect(follow_request).to receive(:destroy!) follow_request.authorize! diff --git a/spec/models/session_activation_spec.rb b/spec/models/session_activation_spec.rb index 2aa695037..450dc1399 100644 --- a/spec/models/session_activation_spec.rb +++ b/spec/models/session_activation_spec.rb @@ -74,13 +74,13 @@ RSpec.describe SessionActivation, type: :model do let(:options) { { user: Fabricate(:user), session_id: '1' } } it 'calls create! and purge_old' do - expect(described_class).to receive(:create!).with(options) + expect(described_class).to receive(:create!).with(**options) expect(described_class).to receive(:purge_old) - described_class.activate(options) + described_class.activate(**options) end it 'returns an instance of SessionActivation' do - expect(described_class.activate(options)).to be_kind_of SessionActivation + expect(described_class.activate(**options)).to be_kind_of SessionActivation end end diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb index df876593c..3949dbce5 100644 --- a/spec/models/tag_spec.rb +++ b/spec/models/tag_spec.rb @@ -96,6 +96,20 @@ RSpec.describe Tag, type: :model do end end + describe '.matches_name' do + it 'returns tags for multibyte case-insensitive names' do + upcase_string = 'abcABCabcABCやゆよ' + downcase_string = 'abcabcabcabcやゆよ'; + + tag = Fabricate(:tag, name: downcase_string) + expect(Tag.matches_name(upcase_string)).to eq [tag] + end + + it 'uses the LIKE operator' do + expect(Tag.matches_name('100%abc').to_sql).to eq %q[SELECT "tags".* FROM "tags" WHERE LOWER("tags"."name") LIKE LOWER('100\\%abc%')] + end + end + describe '.matching_name' do it 'returns tags for multibyte case-insensitive names' do upcase_string = 'abcABCabcABCやゆよ' diff --git a/spec/models/trending_tags_spec.rb b/spec/models/trending_tags_spec.rb index b6122c994..dfbc7d6f8 100644 --- a/spec/models/trending_tags_spec.rb +++ b/spec/models/trending_tags_spec.rb @@ -7,9 +7,9 @@ RSpec.describe TrendingTags do describe '.update!' do let!(:at_time) { Time.now.utc } - let!(:tag1) { Fabricate(:tag, name: 'Catstodon') } - let!(:tag2) { Fabricate(:tag, name: 'DogsOfMastodon') } - let!(:tag3) { Fabricate(:tag, name: 'OCs') } + let!(:tag1) { Fabricate(:tag, name: 'Catstodon', trendable: true) } + let!(:tag2) { Fabricate(:tag, name: 'DogsOfMastodon', trendable: true) } + let!(:tag3) { Fabricate(:tag, name: 'OCs', trendable: true) } before do allow(Redis.current).to receive(:pfcount) do |key| diff --git a/spec/models/web/push_subscription_spec.rb b/spec/models/web/push_subscription_spec.rb index c6665611c..b44904369 100644 --- a/spec/models/web/push_subscription_spec.rb +++ b/spec/models/web/push_subscription_spec.rb @@ -1,16 +1,94 @@ require 'rails_helper' RSpec.describe Web::PushSubscription, type: :model do - let(:alerts) { { mention: true, reblog: false, follow: true, follow_request: false, favourite: true } } - let(:push_subscription) { Web::PushSubscription.new(data: { alerts: alerts }) } + let(:account) { Fabricate(:account) } + + let(:policy) { 'all' } + + let(:data) do + { + policy: policy, + + alerts: { + mention: true, + reblog: false, + follow: true, + follow_request: false, + favourite: true, + }, + } + end + + subject { described_class.new(data: data) } describe '#pushable?' do - it 'obeys alert settings' do - expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'Mention'))).to eq true - expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'Status'))).to eq false - expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'Follow'))).to eq true - expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'FollowRequest'))).to eq false - expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'Favourite'))).to eq true + let(:notification_type) { :mention } + let(:notification) { Fabricate(:notification, account: account, type: notification_type) } + + %i(mention reblog follow follow_request favourite).each do |type| + context "when notification is a #{type}" do + let(:notification_type) { type } + + it "returns boolean corresonding to alert setting" do + expect(subject.pushable?(notification)).to eq data[:alerts][type] + end + end + end + + context 'when policy is all' do + let(:policy) { 'all' } + + it 'returns true' do + expect(subject.pushable?(notification)).to eq true + end + end + + context 'when policy is none' do + let(:policy) { 'none' } + + it 'returns false' do + expect(subject.pushable?(notification)).to eq false + end + end + + context 'when policy is followed' do + let(:policy) { 'followed' } + + context 'and notification is from someone you follow' do + before do + account.follow!(notification.from_account) + end + + it 'returns true' do + expect(subject.pushable?(notification)).to eq true + end + end + + context 'and notification is not from someone you follow' do + it 'returns false' do + expect(subject.pushable?(notification)).to eq false + end + end + end + + context 'when policy is follower' do + let(:policy) { 'follower' } + + context 'and notification is from someone who follows you' do + before do + notification.from_account.follow!(account) + end + + it 'returns true' do + expect(subject.pushable?(notification)).to eq true + end + end + + context 'and notification is not from someone who follows you' do + it 'returns false' do + expect(subject.pushable?(notification)).to eq false + end + end end end end diff --git a/spec/presenters/account_relationships_presenter_spec.rb b/spec/presenters/account_relationships_presenter_spec.rb index f8b048d38..edfbbb354 100644 --- a/spec/presenters/account_relationships_presenter_spec.rb +++ b/spec/presenters/account_relationships_presenter_spec.rb @@ -13,7 +13,7 @@ RSpec.describe AccountRelationshipsPresenter do allow(Account).to receive(:domain_blocking_map).with(account_ids, current_account_id).and_return(default_map) end - let(:presenter) { AccountRelationshipsPresenter.new(account_ids, current_account_id, options) } + let(:presenter) { AccountRelationshipsPresenter.new(account_ids, current_account_id, **options) } let(:current_account_id) { Fabricate(:account).id } let(:account_ids) { [Fabricate(:account).id] } let(:default_map) { { 1 => true } } diff --git a/spec/services/after_block_service_spec.rb b/spec/services/after_block_service_spec.rb index f63b2045a..fe5b26b2b 100644 --- a/spec/services/after_block_service_spec.rb +++ b/spec/services/after_block_service_spec.rb @@ -5,12 +5,14 @@ RSpec.describe AfterBlockService, type: :service do -> { described_class.new.call(account, target_account) } end - let(:account) { Fabricate(:account) } - let(:target_account) { Fabricate(:account) } + let(:account) { Fabricate(:account) } + let(:target_account) { Fabricate(:account) } + let(:status) { Fabricate(:status, account: target_account) } + let(:other_status) { Fabricate(:status, account: target_account) } + let(:other_account_status) { Fabricate(:status) } + let(:other_account_reblog) { Fabricate(:status, reblog_of_id: other_status.id) } describe 'home timeline' do - let(:status) { Fabricate(:status, account: target_account) } - let(:other_account_status) { Fabricate(:status) } let(:home_timeline_key) { FeedManager.instance.key(:home, account.id) } before do @@ -20,10 +22,30 @@ RSpec.describe AfterBlockService, type: :service do it "clears account's statuses" do FeedManager.instance.push_to_home(account, status) FeedManager.instance.push_to_home(account, other_account_status) + FeedManager.instance.push_to_home(account, other_account_reblog) is_expected.to change { Redis.current.zrange(home_timeline_key, 0, -1) - }.from([status.id.to_s, other_account_status.id.to_s]).to([other_account_status.id.to_s]) + }.from([status.id.to_s, other_account_status.id.to_s, other_account_reblog.id.to_s]).to([other_account_status.id.to_s]) + end + end + + describe 'lists' do + let(:list) { Fabricate(:list, account: account) } + let(:list_timeline_key) { FeedManager.instance.key(:list, list.id) } + + before do + Redis.current.del(list_timeline_key) + end + + it "clears account's statuses" do + FeedManager.instance.push_to_list(list, status) + FeedManager.instance.push_to_list(list, other_account_status) + FeedManager.instance.push_to_list(list, other_account_reblog) + + is_expected.to change { + Redis.current.zrange(list_timeline_key, 0, -1) + }.from([status.id.to_s, other_account_status.id.to_s, other_account_reblog.id.to_s]).to([other_account_status.id.to_s]) end end end diff --git a/spec/services/authorize_follow_service_spec.rb b/spec/services/authorize_follow_service_spec.rb index ce56d57a6..8e5d8fb03 100644 --- a/spec/services/authorize_follow_service_spec.rb +++ b/spec/services/authorize_follow_service_spec.rb @@ -22,24 +22,6 @@ RSpec.describe AuthorizeFollowService, type: :service do end end - describe 'remote OStatus' do - let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account } - - before do - FollowRequest.create(account: bob, target_account: sender) - stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {}) - subject.call(bob, sender) - end - - it 'removes follow request' do - expect(bob.requested?(sender)).to be false - end - - it 'creates follow relation' do - expect(bob.following?(sender)).to be true - end - end - describe 'remote ActivityPub' do let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account } diff --git a/spec/services/batched_remove_status_service_spec.rb b/spec/services/batched_remove_status_service_spec.rb index c1f54a6fd..4203952c6 100644 --- a/spec/services/batched_remove_status_service_spec.rb +++ b/spec/services/batched_remove_status_service_spec.rb @@ -4,7 +4,7 @@ RSpec.describe BatchedRemoveStatusService, type: :service do subject { BatchedRemoveStatusService.new } let!(:alice) { Fabricate(:account) } - let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://example.com/salmon') } + let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') } let!(:jeff) { Fabricate(:user).account } let!(:hank) { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } diff --git a/spec/services/block_service_spec.rb b/spec/services/block_service_spec.rb index de20dd026..3714f09e9 100644 --- a/spec/services/block_service_spec.rb +++ b/spec/services/block_service_spec.rb @@ -17,19 +17,6 @@ RSpec.describe BlockService, type: :service do end end - describe 'remote OStatus' do - let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account } - - before do - stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {}) - subject.call(sender, bob) - end - - it 'creates a blocking relation' do - expect(sender.blocking?(bob)).to be true - end - end - describe 'remote ActivityPub' do let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account } diff --git a/spec/services/bootstrap_timeline_service_spec.rb b/spec/services/bootstrap_timeline_service_spec.rb index a28d2407c..880ca4f0d 100644 --- a/spec/services/bootstrap_timeline_service_spec.rb +++ b/spec/services/bootstrap_timeline_service_spec.rb @@ -1,42 +1,4 @@ require 'rails_helper' RSpec.describe BootstrapTimelineService, type: :service do - subject { described_class.new } - - describe '#call' do - let(:source_account) { Fabricate(:account) } - - context 'when setting is empty' do - let!(:admin) { Fabricate(:user, admin: true) } - - before do - Setting.bootstrap_timeline_accounts = nil - subject.call(source_account) - end - - it 'follows admin accounts from account' do - expect(source_account.following?(admin.account)).to be true - end - end - - context 'when setting is set' do - let!(:alice) { Fabricate(:account, username: 'alice') } - let!(:bob) { Fabricate(:account, username: 'bob') } - let!(:eve) { Fabricate(:account, username: 'eve', suspended: true) } - - before do - Setting.bootstrap_timeline_accounts = 'alice, @bob, eve, unknown' - subject.call(source_account) - end - - it 'follows found accounts from account' do - expect(source_account.following?(alice)).to be true - expect(source_account.following?(bob)).to be true - end - - it 'does not follow suspended account' do - expect(source_account.following?(eve)).to be false - end - end - end end diff --git a/spec/services/favourite_service_spec.rb b/spec/services/favourite_service_spec.rb index 4c29ea77b..fc7f58eb4 100644 --- a/spec/services/favourite_service_spec.rb +++ b/spec/services/favourite_service_spec.rb @@ -18,20 +18,6 @@ RSpec.describe FavouriteService, type: :service do end end - describe 'remote OStatus' do - let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com')).account } - let(:status) { Fabricate(:status, account: bob, uri: 'tag:example.com:blahblah') } - - before do - stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {}) - subject.call(sender, status) - end - - it 'creates a favourite' do - expect(status.favourites.first).to_not be_nil - end - end - describe 'remote ActivityPub' do let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :activitypub, username: 'bob', domain: 'example.com', inbox_url: 'http://example.com/inbox')).account } let(:status) { Fabricate(:status, account: bob) } diff --git a/spec/services/fetch_remote_status_service_spec.rb b/spec/services/fetch_remote_status_service_spec.rb index 1c4b4fee2..0e63cc9eb 100644 --- a/spec/services/fetch_remote_status_service_spec.rb +++ b/spec/services/fetch_remote_status_service_spec.rb @@ -31,56 +31,4 @@ RSpec.describe FetchRemoteStatusService, type: :service do expect(status.text).to eq 'Lorem ipsum' end end - - context 'protocol is :ostatus' do - subject { described_class.new } - - before do - Fabricate(:account, username: 'tracer', domain: 'real.domain', remote_url: 'https://real.domain/users/tracer') - end - - it 'does not create status with author at different domain' do - status_body = <<-XML.squish - <?xml version="1.0"?> - <entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>tag:real.domain,2017-04-27:objectId=4487555:objectType=Status</id> - <published>2017-04-27T13:49:25Z</published> - <updated>2017-04-27T13:49:25Z</updated> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <author> - <id>https://real.domain/users/tracer</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://real.domain/users/tracer</uri> - <name>tracer</name> - </author> - <content type="html">Overwatch rocks</content> - </entry> - XML - - expect(subject.call('https://fake.domain/foo', status_body)).to be_nil - end - - it 'does not create status with wrong id when id uses http format' do - status_body = <<-XML.squish - <?xml version="1.0"?> - <entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://other-real.domain/statuses/123</id> - <published>2017-04-27T13:49:25Z</published> - <updated>2017-04-27T13:49:25Z</updated> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <author> - <id>https://real.domain/users/tracer</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://real.domain/users/tracer</uri> - <name>tracer</name> - </author> - <content type="html">Overwatch rocks</content> - </entry> - XML - - expect(subject.call('https://real.domain/statuses/456', status_body)).to be_nil - end - end end diff --git a/spec/services/process_mentions_service_spec.rb b/spec/services/process_mentions_service_spec.rb index c30de8eeb..3b2f9d698 100644 --- a/spec/services/process_mentions_service_spec.rb +++ b/spec/services/process_mentions_service_spec.rb @@ -7,37 +7,6 @@ RSpec.describe ProcessMentionsService, type: :service do subject { ProcessMentionsService.new } - context 'OStatus with public toot' do - let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') } - - before do - stub_request(:post, remote_user.salmon_url) - subject.call(status) - end - - it 'does not create a mention' do - expect(remote_user.mentions.where(status: status).count).to eq 0 - end - end - - context 'OStatus with private toot' do - let(:visibility) { :private } - let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') } - - before do - stub_request(:post, remote_user.salmon_url) - subject.call(status) - end - - it 'does not create a mention' do - expect(remote_user.mentions.where(status: status).count).to eq 0 - end - - it 'does not post to remote user\'s Salmon end point' do - expect(a_request(:post, remote_user.salmon_url)).to_not have_been_made - end - end - context 'ActivityPub' do context do let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } diff --git a/spec/services/reblog_service_spec.rb b/spec/services/reblog_service_spec.rb index 58fb46f0f..e2077f282 100644 --- a/spec/services/reblog_service_spec.rb +++ b/spec/services/reblog_service_spec.rb @@ -32,22 +32,6 @@ RSpec.describe ReblogService, type: :service do 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') } - - subject { ReblogService.new } - - before do - stub_request(:post, 'http://salmon.example.com') - subject.call(alice, status) - end - - it 'creates a reblog' do - expect(status.reblogs.count).to eq 1 - end - end - context 'ActivityPub' do let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } let(:status) { Fabricate(:status, account: bob) } diff --git a/spec/services/reject_follow_service_spec.rb b/spec/services/reject_follow_service_spec.rb index 1aec060db..732cb07f7 100644 --- a/spec/services/reject_follow_service_spec.rb +++ b/spec/services/reject_follow_service_spec.rb @@ -22,24 +22,6 @@ RSpec.describe RejectFollowService, type: :service do end end - describe 'remote OStatus' do - let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account } - - before do - FollowRequest.create(account: bob, target_account: sender) - stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {}) - subject.call(bob, sender) - end - - it 'removes follow request' do - expect(bob.requested?(sender)).to be false - end - - it 'does not create follow relation' do - expect(bob.following?(sender)).to be false - end - end - describe 'remote ActivityPub' do let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account } diff --git a/spec/services/remove_status_service_spec.rb b/spec/services/remove_status_service_spec.rb index 7ce75b2c7..21fb0cd35 100644 --- a/spec/services/remove_status_service_spec.rb +++ b/spec/services/remove_status_service_spec.rb @@ -4,7 +4,7 @@ RSpec.describe RemoveStatusService, type: :service do subject { RemoveStatusService.new } let!(:alice) { Fabricate(:account, user: Fabricate(:user)) } - let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://example.com/salmon') } + let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') } let!(:jeff) { Fabricate(:account) } let!(:hank) { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } let!(:bill) { Fabricate(:account, username: 'bill', protocol: :activitypub, domain: 'example2.com', inbox_url: 'http://example2.com/inbox') } diff --git a/spec/services/unblock_service_spec.rb b/spec/services/unblock_service_spec.rb index 6350c6834..c43ab24b0 100644 --- a/spec/services/unblock_service_spec.rb +++ b/spec/services/unblock_service_spec.rb @@ -18,20 +18,6 @@ RSpec.describe UnblockService, type: :service do end end - describe 'remote OStatus' do - let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account } - - before do - sender.block!(bob) - stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {}) - subject.call(sender, bob) - end - - it 'destroys the blocking relation' do - expect(sender.blocking?(bob)).to be false - end - end - describe 'remote ActivityPub' do let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account } diff --git a/spec/services/unfollow_service_spec.rb b/spec/services/unfollow_service_spec.rb index 84b5dafbc..7f0b575e4 100644 --- a/spec/services/unfollow_service_spec.rb +++ b/spec/services/unfollow_service_spec.rb @@ -18,20 +18,6 @@ RSpec.describe UnfollowService, type: :service do end end - describe 'remote OStatus' do - let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com')).account } - - before do - sender.follow!(bob) - stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {}) - subject.call(sender, bob) - end - - it 'destroys the following relation' do - expect(sender.following?(bob)).to be false - end - end - describe 'remote ActivityPub' do let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account } diff --git a/spec/validators/blacklisted_email_validator_spec.rb b/spec/validators/blacklisted_email_validator_spec.rb index 53b355a57..f7d5e01bc 100644 --- a/spec/validators/blacklisted_email_validator_spec.rb +++ b/spec/validators/blacklisted_email_validator_spec.rb @@ -9,23 +9,36 @@ RSpec.describe BlacklistedEmailValidator, type: :validator do before do allow(user).to receive(:valid_invitation?) { false } - allow_any_instance_of(described_class).to receive(:blocked_email?) { blocked_email } - described_class.new.validate(user) + allow_any_instance_of(described_class).to receive(:blocked_email_provider?) { blocked_email } end - context 'blocked_email?' do + subject { described_class.new.validate(user); errors } + + context 'when e-mail provider is blocked' do let(:blocked_email) { true } - it 'calls errors.add' do - expect(errors).to have_received(:add).with(:email, :blocked) + it 'adds error' do + expect(subject).to have_received(:add).with(:email, :blocked) end end - context '!blocked_email?' do + context 'when e-mail provider is not blocked' do let(:blocked_email) { false } - it 'not calls errors.add' do - expect(errors).not_to have_received(:add).with(:email, :blocked) + it 'does not add errors' do + expect(subject).not_to have_received(:add).with(:email, :blocked) + end + + context 'when canonical e-mail is blocked' do + let(:other_user) { Fabricate(:user, email: 'i.n.f.o@mail.com') } + + before do + other_user.account.suspend! + end + + it 'adds error' do + expect(subject).to have_received(:add).with(:email, :taken) + end end end end diff --git a/spec/workers/web/push_notification_worker_spec.rb b/spec/workers/web/push_notification_worker_spec.rb new file mode 100644 index 000000000..5bc24f888 --- /dev/null +++ b/spec/workers/web/push_notification_worker_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Web::PushNotificationWorker do + subject { described_class.new } + + let(:p256dh) { 'BN4GvZtEZiZuqFxSKVZfSfluwKBD7UxHNBmWkfiZfCtgDE8Bwh-_MtLXbBxTBAWH9r7IPKL0lhdcaqtL1dfxU5E=' } + let(:auth) { 'Q2BoAjC09xH3ywDLNJr-dA==' } + let(:endpoint) { 'https://updates.push.services.mozilla.com/push/v1/subscription-id' } + let(:user) { Fabricate(:user) } + let(:notification) { Fabricate(:notification) } + let(:subscription) { Fabricate(:web_push_subscription, user_id: user.id, key_p256dh: p256dh, key_auth: auth, endpoint: endpoint, data: { alerts: { notification.type => true } }) } + let(:vapid_public_key) { 'BB37UCyc8LLX4PNQSe-04vSFvpUWGrENubUaslVFM_l5TxcGVMY0C3RXPeUJAQHKYlcOM2P4vTYmkoo0VZGZTM4=' } + let(:vapid_private_key) { 'OPrw1Sum3gRoL4-DXfSCC266r-qfFSRZrnj8MgIhRHg=' } + let(:vapid_key) { Webpush::VapidKey.from_keys(vapid_public_key, vapid_private_key) } + let(:contact_email) { 'sender@example.com' } + let(:ciphertext) { "+\xB8\xDBT}\x13\xB6\xDD.\xF9\xB0\xA7\xC8\xD2\x80\xFD\x99#\xF7\xAC\x83\xA4\xDB,\x1F\xB5\xB9w\x85>\xF7\xADr" } + let(:salt) { "X\x97\x953\xE4X\xF8_w\xE7T\x95\xC51q\xFE" } + let(:server_public_key) { "\x04\b-RK9w\xDD$\x16lFz\xF9=\xB4~\xC6\x12k\xF3\xF40t\xA9\xC1\fR\xC3\x81\x80\xAC\f\x7F\xE4\xCC\x8E\xC2\x88 n\x8BB\xF1\x9C\x14\a\xFA\x8D\xC9\x80\xA1\xDDyU\\&c\x01\x88#\x118Ua" } + let(:shared_secret) { "\t\xA7&\x85\t\xC5m\b\xA8\xA7\xF8B{1\xADk\xE1y'm\xEDE\xEC\xDD\xEDj\xB3$s\xA9\xDA\xF0" } + let(:payload) { { ciphertext: ciphertext, salt: salt, server_public_key: server_public_key, shared_secret: shared_secret } } + + describe 'perform' do + before do + allow_any_instance_of(subscription.class).to receive(:contact_email).and_return(contact_email) + allow_any_instance_of(subscription.class).to receive(:vapid_key).and_return(vapid_key) + allow(Webpush::Encryption).to receive(:encrypt).and_return(payload) + allow(JWT).to receive(:encode).and_return('jwt.encoded.payload') + + stub_request(:post, endpoint).to_return(status: 201, body: '') + + subject.perform(subscription.id, notification.id) + end + + it 'calls the relevant service with the correct headers' do + expect(a_request(:post, endpoint).with(headers: { + 'Content-Encoding' => 'aesgcm', + 'Content-Type' => 'application/octet-stream', + 'Crypto-Key' => 'dh=BAgtUks5d90kFmxGevk9tH7GEmvz9DB0qcEMUsOBgKwMf-TMjsKIIG6LQvGcFAf6jcmAod15VVwmYwGIIxE4VWE;p256ecdsa=' + vapid_public_key.delete('='), + 'Encryption' => 'salt=WJeVM-RY-F9351SVxTFx_g', + 'Ttl' => '172800', + 'Urgency' => 'normal', + 'Authorization' => 'WebPush jwt.encoded.payload', + }, body: "+\xB8\xDBT}\u0013\xB6\xDD.\xF9\xB0\xA7\xC8Ҁ\xFD\x99#\xF7\xAC\x83\xA4\xDB,\u001F\xB5\xB9w\x85>\xF7\xADr")).to have_been_made + end + end +end |