Merge remote-tracking branch 'parent/main' into upstream-20240304

This commit is contained in:
KMY 2024-03-04 10:37:41 +09:00
commit 42b5727723
147 changed files with 1529 additions and 958 deletions

View file

@ -90,7 +90,7 @@ RSpec.describe ActivityPub::RepliesController do
context 'when there are few self-replies' do
it 'points next to replies from other people' do
expect(page_json).to be_a Hash
expect(Addressable::URI.parse(page_json[:next]).query.split('&')).to include('only_other_accounts=true', 'page=true')
expect(parsed_uri_query_values(page_json[:next])).to include('only_other_accounts=true', 'page=true')
end
end
@ -101,7 +101,7 @@ RSpec.describe ActivityPub::RepliesController do
it 'points next to other self-replies' do
expect(page_json).to be_a Hash
expect(Addressable::URI.parse(page_json[:next]).query.split('&')).to include('only_other_accounts=false', 'page=true')
expect(parsed_uri_query_values(page_json[:next])).to include('only_other_accounts=false', 'page=true')
end
end
end
@ -140,7 +140,7 @@ RSpec.describe ActivityPub::RepliesController do
it 'points next to other replies' do
expect(page_json).to be_a Hash
expect(Addressable::URI.parse(page_json[:next]).query.split('&')).to include('only_other_accounts=true', 'page=true')
expect(parsed_uri_query_values(page_json[:next])).to include('only_other_accounts=true', 'page=true')
end
end
end
@ -196,6 +196,13 @@ RSpec.describe ActivityPub::RepliesController do
private
def parsed_uri_query_values(uri)
Addressable::URI
.parse(uri)
.query
.split('&')
end
def ap_public_collection
ActivityPub::TagManager::COLLECTIONS[:public]
end

View file

@ -1,101 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V1::Accounts::StatusesController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
it 'returns expected headers', :aggregate_failures do
Fabricate(:status, account: user.account)
get :index, params: { account_id: user.account.id, limit: 1 }
expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2)
end
context 'with only media' do
it 'returns http success' do
get :index, params: { account_id: user.account.id, only_media: true }
expect(response).to have_http_status(200)
end
end
context 'with exclude replies' do
let!(:status) { Fabricate(:status, account: user.account) }
let!(:status_self_reply) { Fabricate(:status, account: user.account, thread: status) }
before do
Fabricate(:status, account: user.account, thread: Fabricate(:status)) # Reply to another user
get :index, params: { account_id: user.account.id, exclude_replies: true }
end
it 'returns posts along with self replies', :aggregate_failures do
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to have_attributes(size: 2)
.and contain_exactly(
include(id: status.id.to_s),
include(id: status_self_reply.id.to_s)
)
end
end
context 'with only own pinned' do
before do
Fabricate(:status_pin, account: user.account, status: Fabricate(:status, account: user.account))
end
it 'returns http success' do
get :index, params: { account_id: user.account.id, pinned: true }
expect(response).to have_http_status(200)
end
end
context "with someone else's pinned statuses" do
let(:account) { Fabricate(:account, username: 'bob', domain: 'example.com') }
let(:status) { Fabricate(:status, account: account) }
let(:private_status) { Fabricate(:status, account: account, visibility: :private) }
before do
Fabricate(:status_pin, account: account, status: status)
Fabricate(:status_pin, account: account, status: private_status)
end
it 'returns http success' do
get :index, params: { account_id: account.id, pinned: true }
expect(response).to have_http_status(200)
end
context 'when user does not follow account' do
it 'lists the public status only' do
get :index, params: { account_id: account.id, pinned: true }
json = body_as_json
expect(json.map { |item| item[:id].to_i }).to eq [status.id]
end
end
context 'when user follows account' do
before do
user.account.follow!(account)
end
it 'lists both the public and the private statuses' do
get :index, params: { account_id: account.id, pinned: true }
json = body_as_json
expect(json.map { |item| item[:id].to_i }).to contain_exactly(status.id, private_status.id)
end
end
end
end
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:software_update) do
version '99.99.99'
version { sequence(:version) { |point| "99.99.#{point}" } }
urgent false
type 'patch'
end

View file

@ -3,7 +3,32 @@
require 'rails_helper'
describe IpBlock do
describe 'to_log_human_identifier' do
describe 'validations' do
it 'validates ip presence', :aggregate_failures do
ip_block = described_class.new(ip: nil, severity: :no_access)
expect(ip_block).to_not be_valid
expect(ip_block).to model_have_error_on_field(:ip)
end
it 'validates severity presence', :aggregate_failures do
ip_block = described_class.new(ip: '127.0.0.1', severity: nil)
expect(ip_block).to_not be_valid
expect(ip_block).to model_have_error_on_field(:severity)
end
it 'validates ip uniqueness', :aggregate_failures do
described_class.create!(ip: '127.0.0.1', severity: :no_access)
ip_block = described_class.new(ip: '127.0.0.1', severity: :no_access)
expect(ip_block).to_not be_valid
expect(ip_block).to model_have_error_on_field(:ip)
end
end
describe '#to_log_human_identifier' do
let(:ip_block) { described_class.new(ip: '192.168.0.1') }
it 'combines the IP and prefix into a string' do
@ -12,4 +37,30 @@ describe IpBlock do
expect(result).to eq('192.168.0.1/32')
end
end
describe '.blocked?' do
context 'when the IP is blocked' do
it 'returns true' do
described_class.create!(ip: '127.0.0.1', severity: :no_access)
expect(described_class.blocked?('127.0.0.1')).to be true
end
end
context 'when the IP is not blocked' do
it 'returns false' do
expect(described_class.blocked?('127.0.0.1')).to be false
end
end
end
describe 'after_commit' do
it 'resets the cache' do
allow(Rails.cache).to receive(:delete)
described_class.create!(ip: '127.0.0.1', severity: :no_access)
expect(Rails.cache).to have_received(:delete).with(described_class::CACHE_KEY)
end
end
end

View file

@ -139,7 +139,7 @@ RSpec.describe UserRole do
end
it 'has negative position' do
expect(subject.position).to eq(-1)
expect(subject.position).to eq(described_class::NOBODY_POSITION)
end
end
@ -159,7 +159,7 @@ RSpec.describe UserRole do
end
it 'has negative position' do
expect(subject.position).to eq(-1)
expect(subject.position).to eq(described_class::NOBODY_POSITION)
end
end

View file

@ -0,0 +1,149 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'API V1 Accounts Statuses' do
let(:user) { Fabricate(:user) }
let(:scopes) { 'read:statuses' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/accounts/:account_id/statuses' do
it 'returns expected headers', :aggregate_failures do
Fabricate(:status, account: user.account)
get "/api/v1/accounts/#{user.account.id}/statuses", params: { limit: 1 }, headers: headers
expect(response).to have_http_status(200)
expect(links_from_header.size)
.to eq(2)
end
context 'with only media' do
it 'returns http success' do
get "/api/v1/accounts/#{user.account.id}/statuses", params: { only_media: true }, headers: headers
expect(response).to have_http_status(200)
end
end
context 'with exclude replies' do
let!(:status) { Fabricate(:status, account: user.account) }
let!(:status_self_reply) { Fabricate(:status, account: user.account, thread: status) }
before do
Fabricate(:status, account: user.account, thread: Fabricate(:status)) # Reply to another user
get "/api/v1/accounts/#{user.account.id}/statuses", params: { exclude_replies: true }, headers: headers
end
it 'returns posts along with self replies', :aggregate_failures do
expect(response)
.to have_http_status(200)
expect(body_as_json)
.to have_attributes(size: 2)
.and contain_exactly(
include(id: status.id.to_s),
include(id: status_self_reply.id.to_s)
)
end
end
context 'with only own pinned' do
before do
Fabricate(:status_pin, account: user.account, status: Fabricate(:status, account: user.account))
end
it 'returns http success and includes a header link' do
get "/api/v1/accounts/#{user.account.id}/statuses", params: { pinned: true }, headers: headers
expect(response).to have_http_status(200)
expect(links_from_header.size)
.to eq(1)
expect(links_from_header)
.to contain_exactly(
have_attributes(
href: /pinned=true/,
attr_pairs: contain_exactly(['rel', 'prev'])
)
)
end
end
context 'with enough pinned statuses to paginate' do
before do
stub_const 'Api::BaseController::DEFAULT_STATUSES_LIMIT', 1
2.times { Fabricate(:status_pin, account: user.account) }
end
it 'returns http success and header pagination links to prev and next' do
get "/api/v1/accounts/#{user.account.id}/statuses", params: { pinned: true }, headers: headers
expect(response).to have_http_status(200)
expect(links_from_header.size)
.to eq(2)
expect(links_from_header)
.to contain_exactly(
have_attributes(
href: /pinned=true/,
attr_pairs: contain_exactly(['rel', 'next'])
),
have_attributes(
href: /pinned=true/,
attr_pairs: contain_exactly(['rel', 'prev'])
)
)
end
end
context "with someone else's pinned statuses" do
let(:account) { Fabricate(:account, username: 'bob', domain: 'example.com') }
let(:status) { Fabricate(:status, account: account) }
let(:private_status) { Fabricate(:status, account: account, visibility: :private) }
before do
Fabricate(:status_pin, account: account, status: status)
Fabricate(:status_pin, account: account, status: private_status)
end
it 'returns http success' do
get "/api/v1/accounts/#{account.id}/statuses", params: { pinned: true }, headers: headers
expect(response).to have_http_status(200)
end
context 'when user does not follow account' do
it 'lists the public status only' do
get "/api/v1/accounts/#{account.id}/statuses", params: { pinned: true }, headers: headers
expect(body_as_json)
.to contain_exactly(
a_hash_including(id: status.id.to_s)
)
end
end
context 'when user follows account' do
before do
user.account.follow!(account)
end
it 'lists both the public and the private statuses' do
get "/api/v1/accounts/#{account.id}/statuses", params: { pinned: true }, headers: headers
expect(body_as_json)
.to contain_exactly(
a_hash_including(id: status.id.to_s),
a_hash_including(id: private_status.id.to_s)
)
end
end
end
end
private
def links_from_header
response
.headers['Link']
.links
end
end

View file

@ -2,31 +2,26 @@
require 'rails_helper'
describe Api::V1::Admin::Trends::StatusesController do
render_views
describe 'API V1 Admin Trends Statuses' do
let(:role) { UserRole.find_by(name: 'Admin') }
let(:user) { Fabricate(:user, role: role) }
let(:scopes) { 'admin:read admin:write' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:account) { Fabricate(:account) }
let(:status) { Fabricate(:status) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
describe 'GET /api/v1/admin/trends/statuses' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
get '/api/v1/admin/trends/statuses', params: { account_id: account.id, limit: 2 }, headers: headers
expect(response).to have_http_status(200)
end
end
describe 'POST #approve' do
describe 'POST /api/v1/admin/trends/statuses/:id/approve' do
before do
post :approve, params: { id: status.id }
post "/api/v1/admin/trends/statuses/#{status.id}/approve", headers: headers
end
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
@ -37,9 +32,9 @@ describe Api::V1::Admin::Trends::StatusesController do
end
end
describe 'POST #reject' do
describe 'POST /api/v1/admin/trends/statuses/:id/unapprove' do
before do
post :reject, params: { id: status.id }
post "/api/v1/admin/trends/statuses/#{status.id}/reject", headers: headers
end
it_behaves_like 'forbidden for wrong scope', 'write:statuses'

View file

@ -2,31 +2,26 @@
require 'rails_helper'
describe Api::V1::Admin::Trends::TagsController do
render_views
describe 'API V1 Admin Trends Tags' do
let(:role) { UserRole.find_by(name: 'Admin') }
let(:user) { Fabricate(:user, role: role) }
let(:scopes) { 'admin:read admin:write' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:account) { Fabricate(:account) }
let(:tag) { Fabricate(:tag) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
describe 'GET /api/v1/admin/trends/tags' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
get '/api/v1/admin/trends/tags', params: { account_id: account.id, limit: 2 }, headers: headers
expect(response).to have_http_status(200)
end
end
describe 'POST #approve' do
describe 'POST /api/v1/admin/trends/tags/:id/approve' do
before do
post :approve, params: { id: tag.id }
post "/api/v1/admin/trends/tags/#{tag.id}/approve", headers: headers
end
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
@ -37,9 +32,9 @@ describe Api::V1::Admin::Trends::TagsController do
end
end
describe 'POST #reject' do
describe 'POST /api/v1/admin/trends/tags/:id/reject' do
before do
post :reject, params: { id: tag.id }
post "/api/v1/admin/trends/tags/#{tag.id}/reject", headers: headers
end
it_behaves_like 'forbidden for wrong scope', 'write:statuses'

View file

@ -2,27 +2,26 @@
require 'rails_helper'
RSpec.describe Api::V1::Announcements::ReactionsController do
render_views
RSpec.describe 'API V1 Announcements Reactions' do
let(:user) { Fabricate(:user) }
let(:scopes) { 'write:favourites' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let!(:announcement) { Fabricate(:announcement) }
describe 'PUT #update' do
describe 'PUT /api/v1/announcements/:announcement_id/reactions/:id' do
context 'without token' do
it 'returns http unauthorized' do
put :update, params: { announcement_id: announcement.id, id: '😂' }
put "/api/v1/announcements/#{announcement.id}/reactions/#{escaped_emoji}"
expect(response).to have_http_status 401
end
end
context 'with token' do
before do
allow(controller).to receive(:doorkeeper_token) { token }
put :update, params: { announcement_id: announcement.id, id: '😂' }
put "/api/v1/announcements/#{announcement.id}/reactions/#{escaped_emoji}", headers: headers
end
it 'creates reaction', :aggregate_failures do
@ -32,22 +31,21 @@ RSpec.describe Api::V1::Announcements::ReactionsController do
end
end
describe 'DELETE #destroy' do
describe 'DELETE /api/v1/announcements/:announcement_id/reactions/:id' do
before do
announcement.announcement_reactions.create!(account: user.account, name: '😂')
end
context 'without token' do
it 'returns http unauthorized' do
delete :destroy, params: { announcement_id: announcement.id, id: '😂' }
delete "/api/v1/announcements/#{announcement.id}/reactions/#{escaped_emoji}"
expect(response).to have_http_status 401
end
end
context 'with token' do
before do
allow(controller).to receive(:doorkeeper_token) { token }
delete :destroy, params: { announcement_id: announcement.id, id: '😂' }
delete "/api/v1/announcements/#{announcement.id}/reactions/#{escaped_emoji}", headers: headers
end
it 'creates reaction', :aggregate_failures do
@ -56,4 +54,8 @@ RSpec.describe Api::V1::Announcements::ReactionsController do
end
end
end
def escaped_emoji
CGI.escape('😂')
end
end

View file

@ -2,27 +2,26 @@
require 'rails_helper'
RSpec.describe Api::V1::AnnouncementsController do
render_views
let(:user) { Fabricate(:user) }
let(:scopes) { 'read' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
RSpec.describe 'API V1 Announcements' do
let(:user) { Fabricate(:user) }
let(:scopes) { 'read' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let!(:announcement) { Fabricate(:announcement) }
describe 'GET #index' do
describe 'GET /api/v1/announcements' do
context 'without token' do
it 'returns http unprocessable entity' do
get :index
get '/api/v1/announcements'
expect(response).to have_http_status 422
end
end
context 'with token' do
before do
allow(controller).to receive(:doorkeeper_token) { token }
get :index
get '/api/v1/announcements', headers: headers
end
it 'returns http success' do
@ -31,10 +30,11 @@ RSpec.describe Api::V1::AnnouncementsController do
end
end
describe 'POST #dismiss' do
describe 'POST /api/v1/announcements/:id/dismiss' do
context 'without token' do
it 'returns http unauthorized' do
post :dismiss, params: { id: announcement.id }
post "/api/v1/announcements/#{announcement.id}/dismiss"
expect(response).to have_http_status 401
end
end
@ -43,8 +43,7 @@ RSpec.describe Api::V1::AnnouncementsController do
let(:scopes) { 'write:accounts' }
before do
allow(controller).to receive(:doorkeeper_token) { token }
post :dismiss, params: { id: announcement.id }
post "/api/v1/announcements/#{announcement.id}/dismiss", headers: headers
end
it 'dismisses announcement', :aggregate_failures do

View file

@ -2,53 +2,48 @@
require 'rails_helper'
RSpec.describe Api::V1::ConversationsController do
render_views
RSpec.describe 'API V1 Conversations' do
let!(:user) { Fabricate(:user, account_attributes: { username: 'alice' }) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read:statuses' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:other) { Fabricate(:user) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index', :sidekiq_inline do
let(:scopes) { 'read:statuses' }
describe 'GET /api/v1/conversations', :sidekiq_inline do
before do
PostStatusService.new.call(other.account, text: 'Hey @alice', visibility: 'direct')
PostStatusService.new.call(user.account, text: 'Hey, nobody here', visibility: 'direct')
end
it 'returns pagination headers', :aggregate_failures do
get :index, params: { limit: 1 }
get '/api/v1/conversations', params: { limit: 1 }, headers: headers
expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2)
end
it 'returns conversations', :aggregate_failures do
get :index
json = body_as_json
expect(json.size).to eq 2
expect(json[0][:accounts].size).to eq 1
get '/api/v1/conversations', headers: headers
expect(body_as_json.size).to eq 2
expect(body_as_json[0][:accounts].size).to eq 1
end
context 'with since_id' do
context 'when requesting old posts' do
it 'returns conversations' do
get :index, params: { since_id: Mastodon::Snowflake.id_at(1.hour.ago, with_random: false) }
json = body_as_json
expect(json.size).to eq 2
get '/api/v1/conversations', params: { since_id: Mastodon::Snowflake.id_at(1.hour.ago, with_random: false) }, headers: headers
expect(body_as_json.size).to eq 2
end
end
context 'when requesting posts in the future' do
it 'returns no conversation' do
get :index, params: { since_id: Mastodon::Snowflake.id_at(1.hour.from_now, with_random: false) }
json = body_as_json
expect(json.size).to eq 0
get '/api/v1/conversations', params: { since_id: Mastodon::Snowflake.id_at(1.hour.from_now, with_random: false) }, headers: headers
expect(body_as_json.size).to eq 0
end
end
end

View file

@ -2,23 +2,18 @@
require 'rails_helper'
RSpec.describe Api::V1::FiltersController do
render_views
RSpec.describe 'API V1 Filters' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
describe 'GET /api/v1/filters' do
let(:scopes) { 'read:filters' }
let!(:filter) { Fabricate(:custom_filter, account: user.account) }
let!(:custom_filter_keyword) { Fabricate(:custom_filter_keyword, custom_filter: filter) }
it 'returns http success' do
get :index
get '/api/v1/filters', headers: headers
expect(response).to have_http_status(200)
expect(body_as_json)
.to contain_exactly(
@ -27,13 +22,13 @@ RSpec.describe Api::V1::FiltersController do
end
end
describe 'POST #create' do
describe 'POST /api/v1/filters' do
let(:scopes) { 'write:filters' }
let(:irreversible) { true }
let(:whole_word) { false }
before do
post :create, params: { phrase: 'magic', context: %w(home), irreversible: irreversible, whole_word: whole_word }
post '/api/v1/filters', params: { phrase: 'magic', context: %w(home), irreversible: irreversible, whole_word: whole_word }, headers: headers
end
it 'creates a filter', :aggregate_failures do
@ -64,24 +59,25 @@ RSpec.describe Api::V1::FiltersController do
end
end
describe 'GET #show' do
describe 'GET /api/v1/filters/:id' do
let(:scopes) { 'read:filters' }
let(:filter) { Fabricate(:custom_filter, account: user.account) }
let(:keyword) { Fabricate(:custom_filter_keyword, custom_filter: filter) }
it 'returns http success' do
get :show, params: { id: keyword.id }
get "/api/v1/filters/#{keyword.id}", headers: headers
expect(response).to have_http_status(200)
end
end
describe 'PUT #update' do
describe 'PUT /api/v1/filters/:id' do
let(:scopes) { 'write:filters' }
let(:filter) { Fabricate(:custom_filter, account: user.account) }
let(:keyword) { Fabricate(:custom_filter_keyword, custom_filter: filter) }
before do
put :update, params: { id: keyword.id, phrase: 'updated' }
put "/api/v1/filters/#{keyword.id}", headers: headers, params: { phrase: 'updated' }
end
it 'updates the filter', :aggregate_failures do
@ -90,13 +86,13 @@ RSpec.describe Api::V1::FiltersController do
end
end
describe 'DELETE #destroy' do
describe 'DELETE /api/v1/filters/:id' do
let(:scopes) { 'write:filters' }
let(:filter) { Fabricate(:custom_filter, account: user.account) }
let(:keyword) { Fabricate(:custom_filter_keyword, custom_filter: filter) }
before do
delete :destroy, params: { id: keyword.id }
delete "/api/v1/filters/#{keyword.id}", headers: headers
end
it 'removes the filter', :aggregate_failures do

View file

@ -2,30 +2,32 @@
require 'rails_helper'
RSpec.describe Api::V1::Polls::VotesController do
render_views
RSpec.describe 'API V1 Polls Votes' do
let(:user) { Fabricate(:user) }
let(:scopes) { 'write:statuses' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
before { allow(controller).to receive(:doorkeeper_token) { token } }
describe 'POST #create' do
describe 'POST /api/v1/polls/:poll_id/votes' do
let(:poll) { Fabricate(:poll) }
before do
post :create, params: { poll_id: poll.id, choices: %w(1) }
post "/api/v1/polls/#{poll.id}/votes", params: { choices: %w(1) }, headers: headers
end
it 'creates a vote', :aggregate_failures do
expect(response).to have_http_status(200)
vote = poll.votes.where(account: user.account).first
expect(vote).to_not be_nil
expect(vote.choice).to eq 1
expect(poll.reload.cached_tallies).to eq [0, 1]
end
private
def vote
poll.votes.where(account: user.account).first
end
end
end

View file

@ -2,9 +2,7 @@
require 'rails_helper'
describe Api::V1::Push::SubscriptionsController do
render_views
describe 'API V1 Push Subscriptions' do
let(:user) { Fabricate(:user) }
let(:create_payload) do
{
@ -34,15 +32,13 @@ describe Api::V1::Push::SubscriptionsController do
},
}.with_indifferent_access
end
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'push') }
let(:scopes) { 'push' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST #create' do
describe 'POST /api/v1/push/subscription' do
before do
post :create, params: create_payload
post '/api/v1/push/subscription', params: create_payload, headers: headers
end
it 'saves push subscriptions' do
@ -56,19 +52,23 @@ describe Api::V1::Push::SubscriptionsController do
end
it 'replaces old subscription on repeat calls' do
post :create, params: create_payload
post '/api/v1/push/subscription', params: create_payload, headers: headers
expect(Web::PushSubscription.where(endpoint: create_payload[:subscription][:endpoint]).count).to eq 1
end
it 'returns the expected JSON' do
expect(body_as_json.with_indifferent_access).to include({ endpoint: create_payload[:subscription][:endpoint], alerts: {}, policy: 'all' })
expect(body_as_json.with_indifferent_access)
.to include(
{ endpoint: create_payload[:subscription][:endpoint], alerts: {}, policy: 'all' }
)
end
end
describe 'PUT #update' do
describe 'PUT /api/v1/push/subscription' do
before do
post :create, params: create_payload
put :update, params: alerts_payload
post '/api/v1/push/subscription', params: create_payload, headers: headers
put '/api/v1/push/subscription', params: alerts_payload, headers: headers
end
it 'changes alert settings' do
@ -82,14 +82,17 @@ describe Api::V1::Push::SubscriptionsController do
end
it 'returns the expected JSON' do
expect(body_as_json.with_indifferent_access).to include({ endpoint: create_payload[:subscription][:endpoint], alerts: alerts_payload[:data][:alerts], policy: alerts_payload[:data][:policy] })
expect(body_as_json.with_indifferent_access)
.to include(
{ endpoint: create_payload[:subscription][:endpoint], alerts: alerts_payload[:data][:alerts], policy: alerts_payload[:data][:policy] }
)
end
end
describe 'DELETE #destroy' do
describe 'DELETE /api/v1/push/subscription' do
before do
post :create, params: create_payload
delete :destroy
post '/api/v1/push/subscription', params: create_payload, headers: headers
delete '/api/v1/push/subscription', headers: headers
end
it 'removes the subscription' do

View file

@ -2,7 +2,7 @@
require 'rails_helper'
describe Api::V1::StreamingController do
describe 'API V1 Streaming' do
around do |example|
before = Rails.configuration.x.streaming_api_base_url
Rails.configuration.x.streaming_api_base_url = "wss://#{Rails.configuration.x.web_domain}"
@ -10,14 +10,13 @@ describe Api::V1::StreamingController do
Rails.configuration.x.streaming_api_base_url = before
end
before do
request.headers.merge! Host: Rails.configuration.x.web_domain
end
let(:headers) { { 'Host' => Rails.configuration.x.web_domain } }
context 'with streaming api on same host' do
describe 'GET #index' do
describe 'GET /api/v1/streaming' do
it 'raises ActiveRecord::RecordNotFound' do
get :index
get '/api/v1/streaming', headers: headers
expect(response).to have_http_status(404)
end
end
@ -28,20 +27,33 @@ describe Api::V1::StreamingController do
Rails.configuration.x.streaming_api_base_url = "wss://streaming-#{Rails.configuration.x.web_domain}"
end
describe 'GET #index' do
describe 'GET /api/v1/streaming' do
it 'redirects to streaming host' do
get :index, params: { access_token: 'deadbeef', stream: 'public' }
expect(response).to have_http_status(301)
request_uri = URI.parse(request.url)
redirect_to_uri = URI.parse(response.location)
[:scheme, :path, :query, :fragment].each do |part|
expect(redirect_to_uri.send(part)).to eq(request_uri.send(part)), "redirect target #{part}"
end
expect(redirect_to_uri.host).to eq(streaming_host), 'redirect target host'
get '/api/v1/streaming', headers: headers, params: { access_token: 'deadbeef', stream: 'public' }
expect(response)
.to have_http_status(301)
expect(redirect_to_uri)
.to have_attributes(
fragment: request_uri.fragment,
host: eq(streaming_host),
path: request_uri.path,
query: request_uri.query,
scheme: request_uri.scheme
)
end
private
def request_uri
URI.parse(request.url)
end
def redirect_to_uri
URI.parse(response.location)
end
def streaming_host
URI.parse(Rails.configuration.x.streaming_api_base_url).host
end