diff options
Diffstat (limited to 'spec')
41 files changed, 598 insertions, 102 deletions
diff --git a/spec/controllers/api/salmon_controller_spec.rb b/spec/controllers/api/salmon_controller_spec.rb index 323d85b61..8af8b83a8 100644 --- a/spec/controllers/api/salmon_controller_spec.rb +++ b/spec/controllers/api/salmon_controller_spec.rb @@ -40,7 +40,7 @@ RSpec.describe Api::SalmonController, type: :controller do end end - context 'with invalid post data' do + context 'with empty post data' do before do request.env['RAW_POST_DATA'] = '' post :update, params: { id: account.id } @@ -50,5 +50,19 @@ RSpec.describe Api::SalmonController, type: :controller do expect(response).to have_http_status(400) end end + + context 'with invalid post data' do + before do + service = double(call: false) + allow(VerifySalmonService).to receive(:new).and_return(service) + + request.env['RAW_POST_DATA'] = File.read(File.join(Rails.root, 'spec', 'fixtures', 'salmon', 'mention.xml')) + post :update, params: { id: account.id } + end + + it 'returns http client error' do + expect(response).to have_http_status(401) + end + end end end diff --git a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb index 508415fc8..e0de790c8 100644 --- a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb @@ -66,6 +66,28 @@ describe Api::V1::Accounts::RelationshipsController do expect(json.second[:requested]).to be false expect(json.second[:domain_blocking]).to be false end + + it 'returns JSON with correct data on cached requests too' do + get :index, params: { id: [simon.id] } + + json = body_as_json + + expect(json).to be_a Enumerable + expect(json.first[:following]).to be true + expect(json.first[:showing_reblogs]).to be true + end + + it 'returns JSON with correct data after change too' do + user.account.unfollow!(simon) + + get :index, params: { id: [simon.id] } + + json = body_as_json + + expect(json).to be_a Enumerable + expect(json.first[:following]).to be false + expect(json.first[:showing_reblogs]).to be false + end end end end diff --git a/spec/controllers/authorize_follows_controller_spec.rb b/spec/controllers/authorize_follows_controller_spec.rb index 26e46a23c..b1cbef7ea 100644 --- a/spec/controllers/authorize_follows_controller_spec.rb +++ b/spec/controllers/authorize_follows_controller_spec.rb @@ -30,7 +30,7 @@ describe AuthorizeFollowsController do it 'renders error when account cant be found' do service = double - allow(ResolveRemoteAccountService).to receive(:new).and_return(service) + allow(ResolveAccountService).to receive(:new).and_return(service) allow(service).to receive(:call).with('missing@hostname').and_return(nil) get :show, params: { acct: 'acct:missing@hostname' } @@ -54,7 +54,7 @@ describe AuthorizeFollowsController do it 'sets account from acct uri' do account = Account.new service = double - allow(ResolveRemoteAccountService).to receive(:new).and_return(service) + allow(ResolveAccountService).to receive(:new).and_return(service) allow(service).to receive(:call).with('found@hostname').and_return(account) get :show, params: { acct: 'acct:found@hostname' } diff --git a/spec/controllers/concerns/localized_spec.rb b/spec/controllers/concerns/localized_spec.rb index c917ce85e..f71c96aff 100644 --- a/spec/controllers/concerns/localized_spec.rb +++ b/spec/controllers/concerns/localized_spec.rb @@ -16,49 +16,24 @@ describe ApplicationController, type: :controller do end shared_examples 'default locale' do - context 'when DEFAULT_LOCALE environment variable is set' do - around do |example| - ClimateControl.modify 'DEFAULT_LOCALE' => 'ca', &example.method(:run) - I18n.locale = I18n.default_locale - end + after { I18n.locale = I18n.default_locale } - it 'sets language specified by ENV if preferred' do - request.headers['Accept-Language'] = 'ca, fa' - get 'success' - expect(I18n.locale).to eq :ca - end - - it 'sets available and preferred language if language specified by ENV is not preferred' do - request.headers['Accept-Language'] = 'ca-ES, fa' - get 'success' - expect(I18n.locale).to eq :fa - end - - it 'sets language specified by ENV if it is compatible and none of available languages are preferred' do - request.headers['Accept-Language'] = 'ca-ES, fa-IR' - get 'success' - expect(I18n.locale).to eq :ca - end - - it 'sets available and compatible langauge if language specified by ENV is not compatible none of available languages are preferred' do - request.headers['Accept-Language'] = 'fa-IR' - get 'success' - expect(I18n.locale).to eq :fa - end + it 'sets available and preferred language' do + request.headers['Accept-Language'] = 'ca-ES, fa' + get 'success' + expect(I18n.locale).to eq :fa + end - it 'sets language specified by ENV if none of available languages are compatible' do - request.headers['Accept-Language'] = '' - get 'success' - expect(I18n.locale).to eq :ca - end + it 'sets available and compatible langauge if none of available languages are preferred' do + request.headers['Accept-Language'] = 'fa-IR' + get 'success' + expect(I18n.locale).to eq :fa end - context 'when DEFAULT_LOCALE environment variable is not set' do - it 'sets default locale if none of available languages are compatible' do - request.headers['Accept-Language'] = '' - get 'success' - expect(I18n.locale).to eq :en - end + it 'sets default locale if none of available languages are compatible' do + request.headers['Accept-Language'] = '' + get 'success' + expect(I18n.locale).to eq :en end end diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb index 1077a7288..f43cf0c27 100644 --- a/spec/controllers/home_controller_spec.rb +++ b/spec/controllers/home_controller_spec.rb @@ -4,21 +4,24 @@ RSpec.describe HomeController, type: :controller do render_views describe 'GET #index' do + subject { get :index } + context 'when not signed in' do + context 'when requested path is tag timeline' do + before { @request.path = '/web/timelines/tag/name' } + it { is_expected.to redirect_to '/tags/name' } + end + it 'redirects to about page' do @request.path = '/' - get :index - expect(response).to redirect_to(about_path) + is_expected.to redirect_to(about_path) end end context 'when signed in' do let(:user) { Fabricate(:user) } - subject do - sign_in(user) - get :index - end + before { sign_in(user) } it 'assigns @body_classes' do subject diff --git a/spec/controllers/settings/imports_controller_spec.rb b/spec/controllers/settings/imports_controller_spec.rb index 4810be701..59b10e0da 100644 --- a/spec/controllers/settings/imports_controller_spec.rb +++ b/spec/controllers/settings/imports_controller_spec.rb @@ -17,7 +17,7 @@ RSpec.describe Settings::ImportsController, type: :controller do describe 'POST #create' do it 'redirects to settings path with successful following import' do service = double(call: nil) - allow(ResolveRemoteAccountService).to receive(:new).and_return(service) + allow(ResolveAccountService).to receive(:new).and_return(service) post :create, params: { import: { type: 'following', @@ -30,7 +30,7 @@ RSpec.describe Settings::ImportsController, type: :controller do it 'redirects to settings path with successful blocking import' do service = double(call: nil) - allow(ResolveRemoteAccountService).to receive(:new).and_return(service) + allow(ResolveAccountService).to receive(:new).and_return(service) post :create, params: { import: { type: 'blocking', diff --git a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb index 0676d6161..aee82a3d8 100644 --- a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb @@ -6,6 +6,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do render_views let(:user) { Fabricate(:user, email: 'local-part@domain', otp_secret: 'thisisasecretforthespecofnewview') } + let(:user_without_otp_secret) { Fabricate(:user, email: 'local-part@domain') } shared_examples 'renders :new' do it 'renders the new view' do @@ -33,6 +34,12 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do get :new expect(response).to redirect_to('/auth/sign_in') end + + it 'redirects if user do not have otp_secret' do + sign_in user_without_otp_secret, scope: :user + get :new + expect(response).to redirect_to('/settings/two_factor_authentication') + end end describe 'POST #create' do diff --git a/spec/fabricators/backup_fabricator.rb b/spec/fabricators/backup_fabricator.rb new file mode 100644 index 000000000..99a5bdcda --- /dev/null +++ b/spec/fabricators/backup_fabricator.rb @@ -0,0 +1,3 @@ +Fabricator(:backup) do + user +end diff --git a/spec/fabricators/identity_fabricator.rb b/spec/fabricators/identity_fabricator.rb new file mode 100644 index 000000000..bc832df9f --- /dev/null +++ b/spec/fabricators/identity_fabricator.rb @@ -0,0 +1,5 @@ +Fabricator(:identity) do + user nil + provider "MyString" + uid "MyString" +end diff --git a/spec/fabricators/list_fabricator.rb b/spec/fabricators/list_fabricator.rb index d249c2029..2a61b317b 100644 --- a/spec/fabricators/list_fabricator.rb +++ b/spec/fabricators/list_fabricator.rb @@ -1,4 +1,4 @@ Fabricator(:list) do - account nil + account title "MyString" end diff --git a/spec/fixtures/requests/webfinger-hacker3.txt b/spec/fixtures/requests/webfinger-hacker3.txt new file mode 100644 index 000000000..c59f518bd --- /dev/null +++ b/spec/fixtures/requests/webfinger-hacker3.txt @@ -0,0 +1,11 @@ +HTTP/1.1 200 OK +Server: nginx/1.6.2 +Date: Sun, 20 Mar 2016 11:13:16 GMT +Content-Type: application/jrd+json +Transfer-Encoding: chunked +Connection: keep-alive +Access-Control-Allow-Origin: * +Vary: Accept-Encoding,Cookie +Strict-Transport-Security: max-age=31536000; includeSubdomains; + +{"subject":"acct:localhost@kickass.zone","aliases":["https:\/\/kickass.zone\/user\/7477","https:\/\/kickass.zone\/gargron","https:\/\/kickass.zone\/index.php\/user\/7477","https:\/\/kickass.zone\/index.php\/gargron"],"links":[{"rel":"http:\/\/webfinger.net\/rel\/profile-page","type":"text\/html","href":"https:\/\/kickass.zone\/gargron"},{"rel":"http:\/\/gmpg.org\/xfn\/11","type":"text\/html","href":"https:\/\/kickass.zone\/gargron"},{"rel":"describedby","type":"application\/rdf+xml","href":"https:\/\/kickass.zone\/gargron\/foaf"},{"rel":"http:\/\/apinamespace.org\/atom","type":"application\/atomsvc+xml","href":"https:\/\/kickass.zone\/api\/statusnet\/app\/service\/gargron.xml"},{"rel":"http:\/\/apinamespace.org\/twitter","href":"https:\/\/kickass.zone\/api\/"},{"rel":"http:\/\/specs.openid.net\/auth\/2.0\/provider","href":"https:\/\/kickass.zone\/gargron"},{"rel":"http:\/\/schemas.google.com\/g\/2010#updates-from","type":"application\/atom+xml","href":"https:\/\/kickass.zone\/api\/statuses\/user_timeline\/7477.atom"},{"rel":"magic-public-key","href":"data:application\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB"},{"rel":"salmon","href":"https:\/\/kickass.zone\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-replies","href":"https:\/\/kickass.zone\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-mention","href":"https:\/\/kickass.zone\/main\/salmon\/user\/7477"},{"rel":"http:\/\/ostatus.org\/schema\/1.0\/subscribe","template":"https:\/\/kickass.zone\/main\/ostatussub?profile={uri}"}]} diff --git a/spec/helpers/instance_helper_spec.rb b/spec/helpers/instance_helper_spec.rb index bc5950d91..c2e26dbed 100644 --- a/spec/helpers/instance_helper_spec.rb +++ b/spec/helpers/instance_helper_spec.rb @@ -15,12 +15,6 @@ describe InstanceHelper do expect(helper.site_title).to eq 'New site title' end - - it 'returns empty string when Setting.site_title is nil' do - Setting.site_title = nil - - expect(helper.site_title).to eq 'cb6e6126.ngrok.io' - end end describe 'site_hostname' do diff --git a/spec/lib/activitypub/activity/add_spec.rb b/spec/lib/activitypub/activity/add_spec.rb new file mode 100644 index 000000000..3ebab4e37 --- /dev/null +++ b/spec/lib/activitypub/activity/add_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Add do + let(:sender) { Fabricate(:account, featured_collection_url: 'https://example.com/featured') } + let(:status) { Fabricate(:status, account: sender) } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Add', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(status), + target: sender.featured_collection_url, + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + subject.perform + end + + it 'creates a pin' do + expect(sender.pinned?(status)).to be true + end + end +end diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 51f54a398..62b9db8c2 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -202,7 +202,7 @@ RSpec.describe ActivityPub::Activity::Create do attachment: [ { type: 'Document', - mime_type: 'image/png', + mediaType: 'image/png', url: 'http://example.com/attachment.png', }, ], @@ -217,6 +217,31 @@ RSpec.describe ActivityPub::Activity::Create do end end + context 'with media attachments with focal points' do + let(:object_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + type: 'Note', + content: 'Lorem ipsum', + attachment: [ + { + type: 'Document', + mediaType: 'image/png', + url: 'http://example.com/attachment.png', + focalPoint: [0.5, -0.7], + }, + ], + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.media_attachments.map(&:focus)).to include('0.5,-0.7') + end + end + context 'with media attachments missing url' do let(:object_json) do { @@ -226,7 +251,7 @@ RSpec.describe ActivityPub::Activity::Create do attachment: [ { type: 'Document', - mime_type: 'image/png', + mediaType: 'image/png', }, ], } diff --git a/spec/lib/activitypub/activity/flag_spec.rb b/spec/lib/activitypub/activity/flag_spec.rb new file mode 100644 index 000000000..3f082a813 --- /dev/null +++ b/spec/lib/activitypub/activity/flag_spec.rb @@ -0,0 +1,37 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Flag do + let(:sender) { Fabricate(:account, domain: 'example.com') } + let(:flagged) { Fabricate(:account) } + let(:status) { Fabricate(:status, account: flagged, uri: 'foobar') } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: nil, + type: 'Flag', + content: 'Boo!!', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: [ + ActivityPub::TagManager.instance.uri_for(flagged), + ActivityPub::TagManager.instance.uri_for(status), + ], + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + subject.perform + end + + it 'creates a report' do + report = Report.find_by(account: sender, target_account: flagged) + + expect(report).to_not be_nil + expect(report.comment).to eq 'Boo!!' + expect(report.status_ids).to eq [status.id] + end + end +end diff --git a/spec/lib/activitypub/activity/remove_spec.rb b/spec/lib/activitypub/activity/remove_spec.rb new file mode 100644 index 000000000..4209dfde2 --- /dev/null +++ b/spec/lib/activitypub/activity/remove_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Remove do + let(:sender) { Fabricate(:account, featured_collection_url: 'https://example.com/featured') } + let(:status) { Fabricate(:status, account: sender) } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Add', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: ActivityPub::TagManager.instance.uri_for(status), + target: sender.featured_collection_url, + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + StatusPin.create!(account: sender, status: status) + subject.perform + end + + it 'removes a pin' do + expect(sender.pinned?(status)).to be false + end + end +end diff --git a/spec/lib/activitypub/activity/update_spec.rb b/spec/lib/activitypub/activity/update_spec.rb index ea308e35c..fbfc585cf 100644 --- a/spec/lib/activitypub/activity/update_spec.rb +++ b/spec/lib/activitypub/activity/update_spec.rb @@ -7,6 +7,7 @@ RSpec.describe ActivityPub::Activity::Update do stub_request(:get, actor_json[:outbox]).to_return(status: 404) stub_request(:get, actor_json[:followers]).to_return(status: 404) stub_request(:get, actor_json[:following]).to_return(status: 404) + stub_request(:get, actor_json[:featured]).to_return(status: 404) sender.update!(uri: ActivityPub::TagManager.instance.uri_for(sender)) end diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb index f87ef383a..3f91bba4e 100644 --- a/spec/lib/feed_manager_spec.rb +++ b/spec/lib/feed_manager_spec.rb @@ -1,7 +1,14 @@ require 'rails_helper' RSpec.describe FeedManager do - it 'tracks at least as many statuses as reblogs' do + before do |example| + unless example.metadata[:skip_stub] + stub_const 'FeedManager::MAX_ITEMS', 10 + stub_const 'FeedManager::REBLOG_FALLOFF', 4 + end + end + + it 'tracks at least as many statuses as reblogs', skip_stub: true do expect(FeedManager::REBLOG_FALLOFF).to be <= FeedManager::MAX_ITEMS end @@ -218,7 +225,7 @@ RSpec.describe FeedManager do end end - describe '#push' do + describe '#push_to_home' do it 'trims timelines if they will have more than FeedManager::MAX_ITEMS' do account = Fabricate(:account) status = Fabricate(:status) @@ -309,6 +316,39 @@ RSpec.describe FeedManager do expect(FeedManager.instance.push_to_home(account, reblogs.last)).to be true end end + + it "does not push when the given status's reblog is already inserted" do + account = Fabricate(:account) + reblog = Fabricate(:status) + status = Fabricate(:status, reblog: reblog) + FeedManager.instance.push_to_home(account, status) + + expect(FeedManager.instance.push_to_home(account, reblog)).to eq false + end + end + + describe '#push_to_list' do + it "does not push when the given status's reblog is already inserted" do + list = Fabricate(:list) + reblog = Fabricate(:status) + status = Fabricate(:status, reblog: reblog) + FeedManager.instance.push_to_list(list, status) + + expect(FeedManager.instance.push_to_list(list, reblog)).to eq false + end + end + + describe '#merge_into_timeline' do + it "does not push source account's statuses whose reblogs are already inserted" do + account = Fabricate(:account, id: 0) + reblog = Fabricate(:status) + status = Fabricate(:status, reblog: reblog) + FeedManager.instance.push_to_home(account, status) + + FeedManager.instance.merge_into_timeline(account, reblog.account) + + expect(Redis.current.zscore("feed:home:0", reblog.id)).to eq nil + end end describe '#trim' do diff --git a/spec/lib/request_spec.rb b/spec/lib/request_spec.rb index 782f14b18..dc7daa52c 100644 --- a/spec/lib/request_spec.rb +++ b/spec/lib/request_spec.rb @@ -38,17 +38,32 @@ describe Request do end describe '#perform' do - before do - stub_request(:get, 'http://example.com') - subject.perform - end + context 'with valid host' do + before do + stub_request(:get, 'http://example.com') + subject.perform + end + + it 'executes a HTTP request' do + expect(a_request(:get, 'http://example.com')).to have_been_made.once + end - it 'executes a HTTP request' do - expect(a_request(:get, 'http://example.com')).to have_been_made.once + it 'sets headers' do + expect(a_request(:get, 'http://example.com').with(headers: subject.headers)).to have_been_made + end end - it 'sets headers' do - expect(a_request(:get, 'http://example.com').with(headers: subject.headers)).to have_been_made + context 'with private host' do + around do |example| + WebMock.disable! + example.run + WebMock.enable! + end + + it 'raises Mastodon::ValidationError' do + allow(IPSocket).to receive(:getaddress).with('example.com').and_return('0.0.0.0') + expect{ subject.perform }.to raise_error Mastodon::ValidationError + end end end end diff --git a/spec/mailers/notification_mailer_spec.rb b/spec/mailers/notification_mailer_spec.rb index 811435606..1be01e8ba 100644 --- a/spec/mailers/notification_mailer_spec.rb +++ b/spec/mailers/notification_mailer_spec.rb @@ -8,7 +8,7 @@ RSpec.describe NotificationMailer, type: :mailer do shared_examples 'localized subject' do |*args, **kwrest| it 'renders subject localized for the locale of the receiver' do - locale = I18n.available_locales.sample + locale = %i(de en).sample receiver.update!(locale: locale) expect(mail.subject).to eq I18n.t(*args, kwrest.merge(locale: locale)) end diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb index 8d2a9368d..d9cdb9264 100644 --- a/spec/mailers/previews/user_mailer_preview.rb +++ b/spec/mailers/previews/user_mailer_preview.rb @@ -34,4 +34,9 @@ class UserMailerPreview < ActionMailer::Preview def welcome UserMailer.welcome(User.first) end + + # Preview this email at http://localhost:3000/rails/mailers/user_mailer/backup_ready + def backup_ready + UserMailer.backup_ready(User.first, Backup.first) + end end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 7501c498c..3ac7208ed 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -185,8 +185,8 @@ RSpec.describe Account, type: :model do expect(account.refresh!).to be_nil end - it 'calls not ResolveRemoteAccountService#call' do - expect_any_instance_of(ResolveRemoteAccountService).not_to receive(:call).with(acct) + it 'calls not ResolveAccountService#call' do + expect_any_instance_of(ResolveAccountService).not_to receive(:call).with(acct) account.refresh! end end @@ -194,8 +194,8 @@ RSpec.describe Account, type: :model do context 'domain is present' do let(:domain) { 'example.com' } - it 'calls ResolveRemoteAccountService#call' do - expect_any_instance_of(ResolveRemoteAccountService).to receive(:call).with(acct).once + it 'calls ResolveAccountService#call' do + expect_any_instance_of(ResolveAccountService).to receive(:call).with(acct).once account.refresh! end end diff --git a/spec/models/backup_spec.rb b/spec/models/backup_spec.rb new file mode 100644 index 000000000..fabcdc845 --- /dev/null +++ b/spec/models/backup_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Backup, type: :model do + +end diff --git a/spec/models/glitch/keyword_mute_helper_spec.rb b/spec/models/glitch/keyword_mute_helper_spec.rb new file mode 100644 index 000000000..b3f991d5b --- /dev/null +++ b/spec/models/glitch/keyword_mute_helper_spec.rb @@ -0,0 +1,50 @@ +require 'rails_helper' + +RSpec.describe Glitch::KeywordMuteHelper do + describe '#matches?' do + let(:alice) { Fabricate(:account, username: 'alice').tap(&:save!) } + let(:helper) { Glitch::KeywordMuteHelper.new(alice) } + + it 'ignores names of HTML tags in status text' do + status = Fabricate(:status, text: '<addr>uh example</addr>') + Glitch::KeywordMute.create!(account: alice, keyword: 'addr') + + expect(helper.matches?(status)).to be false + end + + it 'ignores properties of HTML tags in status text' do + status = Fabricate(:status, text: '<a href="https://www.example.org">uh example</a>') + Glitch::KeywordMute.create!(account: alice, keyword: 'href') + + expect(helper.matches?(status)).to be false + end + + it 'matches text inside HTML tags' do + status = Fabricate(:status, text: '<p>HEY THIS IS SOMETHING ANNOYING</p>') + Glitch::KeywordMute.create!(account: alice, keyword: 'annoying') + + expect(helper.matches?(status)).to be true + end + + it 'matches < in HTML-stripped text' do + status = Fabricate(:status, text: '<p>I <3 oats</p>') + Glitch::KeywordMute.create!(account: alice, keyword: '<3') + + expect(helper.matches?(status)).to be true + end + + it 'matches < in HTML text' do + status = Fabricate(:status, text: '<p>I <3 oats</p>') + Glitch::KeywordMute.create!(account: alice, keyword: '<3') + + expect(helper.matches?(status)).to be true + end + + it 'matches link hrefs in HTML text' do + status = Fabricate(:status, text: '<p><a href="https://example.com/it-was-milk">yep</a></p>') + Glitch::KeywordMute.create!(account: alice, keyword: 'milk') + + expect(helper.matches?(status)).to be true + end + end +end diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb new file mode 100644 index 000000000..53f355410 --- /dev/null +++ b/spec/models/identity_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Identity, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb index b40a641f7..d2230b6d0 100644 --- a/spec/models/media_attachment_spec.rb +++ b/spec/models/media_attachment_spec.rb @@ -92,7 +92,6 @@ RSpec.describe MediaAttachment, type: :model do it 'sets meta' do expect(media.file.meta["original"]["width"]).to eq 128 expect(media.file.meta["original"]["height"]).to eq 128 - expect(media.file.meta["original"]["aspect"]).to eq 1.0 end end diff --git a/spec/models/setting_spec.rb b/spec/models/setting_spec.rb index e99dfc0d7..1cc528674 100644 --- a/spec/models/setting_spec.rb +++ b/spec/models/setting_spec.rb @@ -42,17 +42,12 @@ RSpec.describe Setting, type: :model do described_class[key] end - it 'calls Rails.cache.fetch' do - expect(Rails).to receive_message_chain(:cache, :fetch).with(cache_key) - described_class[key] - end - context 'Rails.cache does not exists' do before do allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object) allow(described_class).to receive(:default_settings).and_return(default_settings) allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records) - Rails.cache.clear(cache_key) + Rails.cache.delete(cache_key) end let(:object) { nil } @@ -103,6 +98,14 @@ RSpec.describe Setting, type: :model do Rails.cache.write(cache_key, cache_value) end + it 'does not query the database' do + expect do |callback| + ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do + described_class[key] + end + end.not_to yield_control + end + it 'returns the cached value' do expect(described_class[key]).to eq cache_value end diff --git a/spec/presenters/instance_presenter_spec.rb b/spec/presenters/instance_presenter_spec.rb index 7c47aed61..006403925 100644 --- a/spec/presenters/instance_presenter_spec.rb +++ b/spec/presenters/instance_presenter_spec.rb @@ -90,9 +90,7 @@ describe InstancePresenter do describe "user_count" do it "returns the number of site users" do - cache = double - allow(Rails).to receive(:cache).and_return(cache) - allow(cache).to receive(:fetch).with("user_count").and_return(123) + Rails.cache.write 'user_count', 123 expect(instance_presenter.user_count).to eq(123) end @@ -100,9 +98,7 @@ describe InstancePresenter do describe "status_count" do it "returns the number of local statuses" do - cache = double - allow(Rails).to receive(:cache).and_return(cache) - allow(cache).to receive(:fetch).with("local_status_count").and_return(234) + Rails.cache.write 'local_status_count', 234 expect(instance_presenter.status_count).to eq(234) end @@ -110,9 +106,7 @@ describe InstancePresenter do describe "domain_count" do it "returns the number of known domains" do - cache = double - allow(Rails).to receive(:cache).and_return(cache) - allow(cache).to receive(:fetch).with("distinct_domain_count").and_return(345) + Rails.cache.write 'distinct_domain_count', 345 expect(instance_presenter.domain_count).to eq(345) end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 4f7399505..dc1f32e08 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -51,6 +51,8 @@ RSpec.configure do |config| end config.after :each do + Rails.cache.clear + keys = Redis.current.keys Redis.current.del(keys) if keys.any? end diff --git a/spec/services/account_search_service_spec.rb b/spec/services/account_search_service_spec.rb index 4685e619f..9bb27edad 100644 --- a/spec/services/account_search_service_spec.rb +++ b/spec/services/account_search_service_spec.rb @@ -123,7 +123,7 @@ describe AccountSearchService do describe 'when there is a domain but no exact match' do it 'follows the remote account when resolve is true' do service = double(call: nil) - allow(ResolveRemoteAccountService).to receive(:new).and_return(service) + allow(ResolveAccountService).to receive(:new).and_return(service) results = subject.call('newuser@remote.com', 10, nil, resolve: true) expect(service).to have_received(:call).with('newuser@remote.com') @@ -131,7 +131,7 @@ describe AccountSearchService do it 'does not follow the remote account when resolve is false' do service = double(call: nil) - allow(ResolveRemoteAccountService).to receive(:new).and_return(service) + allow(ResolveAccountService).to receive(:new).and_return(service) results = subject.call('newuser@remote.com', 10, nil, resolve: false) expect(service).not_to have_received(:call) diff --git a/spec/services/fetch_atom_service_spec.rb b/spec/services/fetch_atom_service_spec.rb index 5491fd027..2bd127e92 100644 --- a/spec/services/fetch_atom_service_spec.rb +++ b/spec/services/fetch_atom_service_spec.rb @@ -1,4 +1,89 @@ require 'rails_helper' RSpec.describe FetchAtomService do + describe '#call' do + let(:url) { 'http://example.com' } + subject { FetchAtomService.new.call(url) } + + context 'url is blank' do + let(:url) { '' } + it { is_expected.to be_nil } + end + + context 'request failed' do + before do + WebMock.stub_request(:get, url).to_return(status: 500, body: '', headers: {}) + end + + it { is_expected.to be_nil } + end + + context 'raise OpenSSL::SSL::SSLError' do + before do + allow(Request).to receive_message_chain(:new, :add_headers, :perform).and_raise(OpenSSL::SSL::SSLError) + end + + it 'output log and return nil' do + expect_any_instance_of(ActiveSupport::Logger).to receive(:debug).with('SSL error: OpenSSL::SSL::SSLError') + is_expected.to be_nil + end + end + + context 'raise HTTP::ConnectionError' do + before do + allow(Request).to receive_message_chain(:new, :add_headers, :perform).and_raise(HTTP::ConnectionError) + end + + it 'output log and return nil' do + expect_any_instance_of(ActiveSupport::Logger).to receive(:debug).with('HTTP ConnectionError: HTTP::ConnectionError') + is_expected.to be_nil + end + end + + context 'response success' do + let(:body) { '' } + let(:headers) { { 'Content-Type' => content_type } } + let(:json) { + { id: 1, + '@context': ActivityPub::TagManager::CONTEXT, + type: 'Note', + }.to_json + } + + before do + WebMock.stub_request(:get, url).to_return(status: 200, body: body, headers: headers) + end + + context 'content type is application/atom+xml' do + let(:content_type) { 'application/atom+xml' } + + it { is_expected.to eq [url, {:prefetched_body=>""}, :ostatus] } + end + + context 'content_type is json' do + let(:content_type) { 'application/activity+json' } + let(:body) { json } + + it { is_expected.to eq [1, { prefetched_body: body, id: true }, :activitypub] } + end + + before do + WebMock.stub_request(:get, url).to_return(status: 200, body: body, headers: headers) + WebMock.stub_request(:get, 'http://example.com/foo').to_return(status: 200, body: json, headers: { 'Content-Type' => 'application/activity+json' }) + end + + context 'has link header' do + let(:headers) { { 'Link' => '<http://example.com/foo>; rel="alternate"; type="application/activity+json"', } } + + it { is_expected.to eq [1, { prefetched_body: json, id: true }, :activitypub] } + end + + context 'content type is text/html' do + let(:content_type) { 'text/html' } + let(:body) { '<html><head><link rel="alternate" href="http://example.com/foo" type="application/activity+json"/></head></html>' } + + it { is_expected.to eq [1, { prefetched_body: json, id: true }, :activitypub] } + end + end + end end diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb index ba61d22c3..edacc4425 100644 --- a/spec/services/fetch_link_card_service_spec.rb +++ b/spec/services/fetch_link_card_service_spec.rb @@ -15,6 +15,8 @@ RSpec.describe FetchLinkCardService do stub_request(:head, 'http://example.com/日本語').to_return(status: 200, headers: { 'Content-Type' => 'text/html' }) stub_request(:get, 'http://example.com/日本語').to_return(request_fixture('sjis.txt')) 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')) subject.call(status) end @@ -63,6 +65,14 @@ RSpec.describe FetchLinkCardService do expect(status.preview_cards.first.title).to eq("SJISのページ") end end + + context do + let(:status) { Fabricate(:status, text: 'test http://example.com/test-') } + + it 'works with a URL ending with a hyphen' do + expect(a_request(:get, 'http://example.com/test-')).to have_been_made.at_least_once + end + end end context 'in a remote status' do diff --git a/spec/services/fetch_remote_account_service_spec.rb b/spec/services/fetch_remote_account_service_spec.rb index bb1877c7a..4388d4cf4 100644 --- a/spec/services/fetch_remote_account_service_spec.rb +++ b/spec/services/fetch_remote_account_service_spec.rb @@ -1,4 +1,71 @@ require 'rails_helper' RSpec.describe FetchRemoteAccountService do + let(:url) { 'https://example.com' } + let(:prefetched_body) { nil } + let(:protocol) { :ostatus } + subject { FetchRemoteAccountService.new.call(url, prefetched_body, protocol) } + + let(:actor) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'https://example.com/alice', + type: 'Person', + preferredUsername: 'alice', + name: 'Alice', + summary: 'Foo bar', + inbox: 'http://example.com/alice/inbox', + } + end + + let(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } + let(:xml) { File.read(File.join(Rails.root, 'spec', 'fixtures', 'xml', 'mastodon.atom')) } + + shared_examples 'return Account' do + it { is_expected.to be_an Account } + end + + context 'protocol is :activitypub' do + let(:prefetched_body) { Oj.dump(actor) } + let(:protocol) { :activitypub } + + before do + stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) + end + + include_examples 'return Account' + end + + context 'protocol is :ostatus' do + let(:prefetched_body) { xml } + let(:protocol) { :ostatus } + + before do + stub_request(:get, "https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone").to_return(request_fixture('webfinger-hacker3.txt')) + stub_request(:get, "https://kickass.zone/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt')) + end + + include_examples 'return Account' + end + + context 'when prefetched_body is nil' do + context 'protocol is :activitypub' do + before do + stub_request(:get, url).to_return(status: 200, body: Oj.dump(actor), headers: { 'Content-Type' => 'application/activity+json' }) + stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) + end + + include_examples 'return Account' + end + + context 'protocol is :ostatus' do + before do + stub_request(:get, url).to_return(status: 200, body: xml, headers: { 'Content-Type' => 'application/atom+xml' }) + stub_request(:get, "https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone").to_return(request_fixture('webfinger-hacker3.txt')) + stub_request(:get, "https://kickass.zone/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt')) + end + + include_examples 'return Account' + end + end end diff --git a/spec/services/fetch_remote_status_service_spec.rb b/spec/services/fetch_remote_status_service_spec.rb index cbdecbf25..fa5782b94 100644 --- a/spec/services/fetch_remote_status_service_spec.rb +++ b/spec/services/fetch_remote_status_service_spec.rb @@ -1,4 +1,35 @@ require 'rails_helper' RSpec.describe FetchRemoteStatusService do + let(:account) { Fabricate(:account) } + let(:prefetched_body) { nil } + let(:valid_domain) { Rails.configuration.x.local_domain } + + let(:note) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: "https://#{valid_domain}/@foo/1234", + type: 'Note', + content: 'Lorem ipsum', + attributedTo: ActivityPub::TagManager.instance.uri_for(account), + } + end + + context 'protocol is :activitypub' do + subject { described_class.new.call(note[:id], prefetched_body, protocol) } + let(:prefetched_body) { Oj.dump(note) } + let(:protocol) { :activitypub } + + before do + account.update(uri: ActivityPub::TagManager.instance.uri_for(account)) + subject + end + + it 'creates status' do + status = account.statuses.first + + expect(status).to_not be_nil + expect(status.text).to eq 'Lorem ipsum' + end + end end diff --git a/spec/services/precompute_feed_service_spec.rb b/spec/services/precompute_feed_service_spec.rb index 396a3c3fb..43340bffc 100644 --- a/spec/services/precompute_feed_service_spec.rb +++ b/spec/services/precompute_feed_service_spec.rb @@ -9,14 +9,11 @@ RSpec.describe PrecomputeFeedService do let(:account) { Fabricate(:account) } it 'fills a user timeline with statuses' do account = Fabricate(:account) - followed_account = Fabricate(:account) - Fabricate(:follow, account: account, target_account: followed_account) - reblog = Fabricate(:status, account: followed_account) - status = Fabricate(:status, account: account, reblog: reblog) + status = Fabricate(:status, account: account) subject.call(account) - expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to be_within(0.1).of(status.id.to_f) + expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), status.id)).to be_within(0.1).of(status.id.to_f) end it 'does not raise an error even if it could not find any status' do diff --git a/spec/services/report_service_spec.rb b/spec/services/report_service_spec.rb new file mode 100644 index 000000000..2f926ef00 --- /dev/null +++ b/spec/services/report_service_spec.rb @@ -0,0 +1,25 @@ +require 'rails_helper' + +RSpec.describe ReportService do + subject { described_class.new } + + let(:source_account) { Fabricate(:account) } + + context 'for a remote account' do + let(:remote_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') } + + before do + stub_request(:post, 'http://example.com/inbox').to_return(status: 200) + end + + it 'sends ActivityPub payload when forward is true' do + subject.call(source_account, remote_account, forward: true) + expect(a_request(:post, 'http://example.com/inbox')).to have_been_made + end + + it 'does not send anything when forward is false' do + subject.call(source_account, remote_account, forward: false) + expect(a_request(:post, 'http://example.com/inbox')).to_not have_been_made + end + end +end diff --git a/spec/services/resolve_remote_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb index d0bb6a137..5f1b4467b 100644 --- a/spec/services/resolve_remote_account_service_spec.rb +++ b/spec/services/resolve_account_service_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -RSpec.describe ResolveRemoteAccountService do +RSpec.describe ResolveAccountService do subject { described_class.new } before do diff --git a/spec/services/fetch_remote_resource_service_spec.rb b/spec/services/resolve_url_service_spec.rb index b80fb2475..1e9be4c07 100644 --- a/spec/services/fetch_remote_resource_service_spec.rb +++ b/spec/services/resolve_url_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe FetchRemoteResourceService do +describe ResolveURLService do subject { described_class.new } describe '#call' do diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index 3ffcc389b..957b60c7d 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -26,7 +26,7 @@ describe SearchService do context 'that does not find anything' do it 'returns the empty results' do service = double(call: nil) - allow(FetchRemoteResourceService).to receive(:new).and_return(service) + allow(ResolveURLService).to receive(:new).and_return(service) results = subject.call(@query, 10) expect(service).to have_received(:call).with(@query) @@ -38,7 +38,7 @@ describe SearchService do it 'includes the account in the results' do account = Account.new service = double(call: account) - allow(FetchRemoteResourceService).to receive(:new).and_return(service) + allow(ResolveURLService).to receive(:new).and_return(service) results = subject.call(@query, 10) expect(service).to have_received(:call).with(@query) @@ -50,7 +50,7 @@ describe SearchService do it 'includes the status in the results' do status = Status.new service = double(call: status) - allow(FetchRemoteResourceService).to receive(:new).and_return(service) + allow(ResolveURLService).to receive(:new).and_return(service) results = subject.call(@query, 10) expect(service).to have_received(:call).with(@query) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index eecaec4ac..a0466dd4b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -25,6 +25,10 @@ RSpec.configure do |config| end end + config.before :suite do + Chewy.strategy(:bypass) + end + config.after :suite do gc_counter = 0 FileUtils.rm_rf(Dir["#{Rails.root}/spec/test_files/"]) diff --git a/spec/views/about/show.html.haml_spec.rb b/spec/views/about/show.html.haml_spec.rb index ca59fa9e3..be1320ed3 100644 --- a/spec/views/about/show.html.haml_spec.rb +++ b/spec/views/about/show.html.haml_spec.rb @@ -18,6 +18,9 @@ describe 'about/show.html.haml', without_verify_partial_doubles: true do source_url: 'https://github.com/tootsuite/mastodon', open_registrations: false, thumbnail: nil, + hero: nil, + user_count: 0, + status_count: 0, closed_registrations_message: 'yes', commit_hash: commit_hash) |