2020-03-13 15:44:24 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
2020-07-28 23:09:34 +05:30
|
|
|
RSpec.describe API::Helpers::PaginationStrategies do
|
2020-03-13 15:44:24 +05:30
|
|
|
subject { Class.new.include(described_class).new }
|
|
|
|
|
|
|
|
let(:expected_result) { double("result") }
|
2020-05-24 23:13:21 +05:30
|
|
|
let(:relation) { double("relation", klass: "SomeClass") }
|
2020-03-13 15:44:24 +05:30
|
|
|
let(:params) { {} }
|
|
|
|
|
|
|
|
before do
|
|
|
|
allow(subject).to receive(:params).and_return(params)
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#paginate_with_strategies' do
|
|
|
|
let(:paginator) { double("paginator", paginate: expected_result, finalize: nil) }
|
|
|
|
|
|
|
|
before do
|
2020-05-24 23:13:21 +05:30
|
|
|
allow(subject).to receive(:paginator).with(relation, nil).and_return(paginator)
|
2020-03-13 15:44:24 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'yields paginated relation' do
|
2020-05-24 23:13:21 +05:30
|
|
|
expect { |b| subject.paginate_with_strategies(relation, nil, &b) }.to yield_with_args(expected_result)
|
2020-03-13 15:44:24 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'calls #finalize with first value returned from block' do
|
|
|
|
return_value = double
|
|
|
|
expect(paginator).to receive(:finalize).with(return_value)
|
|
|
|
|
2020-05-24 23:13:21 +05:30
|
|
|
subject.paginate_with_strategies(relation, nil) do |records|
|
2020-03-13 15:44:24 +05:30
|
|
|
some_options = {}
|
|
|
|
[return_value, some_options]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns whatever the block returns' do
|
|
|
|
return_value = [double, double]
|
|
|
|
|
2020-05-24 23:13:21 +05:30
|
|
|
result = subject.paginate_with_strategies(relation, nil) do |records|
|
2020-03-13 15:44:24 +05:30
|
|
|
return_value
|
|
|
|
end
|
|
|
|
|
|
|
|
expect(result).to eq(return_value)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#paginator' do
|
|
|
|
context 'offset pagination' do
|
2020-05-24 23:13:21 +05:30
|
|
|
let(:plan_limits) { Plan.default.actual_limits }
|
|
|
|
let(:offset_limit) { plan_limits.offset_pagination_limit }
|
2020-03-13 15:44:24 +05:30
|
|
|
let(:paginator) { double("paginator") }
|
|
|
|
|
|
|
|
before do
|
|
|
|
allow(subject).to receive(:keyset_pagination_enabled?).and_return(false)
|
|
|
|
end
|
|
|
|
|
2022-08-13 15:12:31 +05:30
|
|
|
context 'when keyset pagination is available and enforced for the relation' do
|
2020-05-24 23:13:21 +05:30
|
|
|
before do
|
|
|
|
allow(Gitlab::Pagination::Keyset).to receive(:available_for_type?).and_return(true)
|
2022-08-13 15:12:31 +05:30
|
|
|
allow(Gitlab::Pagination::CursorBasedKeyset).to receive(:enforced_for_type?).and_return(true)
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
2020-03-13 15:44:24 +05:30
|
|
|
|
2020-05-24 23:13:21 +05:30
|
|
|
context 'when a request scope is given' do
|
|
|
|
let(:params) { { per_page: 100, page: offset_limit / 100 + 1 } }
|
|
|
|
let(:request_scope) { double("scope", actual_limits: plan_limits) }
|
|
|
|
|
|
|
|
context 'when the scope limit is exceeded' do
|
|
|
|
it 'renders a 405 error' do
|
|
|
|
expect(subject).to receive(:error!).with(/maximum allowed offset/, 405)
|
|
|
|
|
|
|
|
subject.paginator(relation, request_scope)
|
|
|
|
end
|
2022-08-13 15:12:31 +05:30
|
|
|
|
|
|
|
context 'when keyset pagination is not enforced' do
|
|
|
|
before do
|
|
|
|
allow(Gitlab::Pagination::CursorBasedKeyset).to receive(:enforced_for_type?).and_return(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns no errors' do
|
|
|
|
expect(subject).not_to receive(:error!)
|
|
|
|
|
|
|
|
subject.paginator(relation, request_scope)
|
|
|
|
end
|
|
|
|
end
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the scope limit is not exceeded' do
|
|
|
|
let(:params) { { per_page: 100, page: offset_limit / 100 } }
|
|
|
|
|
|
|
|
it 'delegates to OffsetPagination' do
|
|
|
|
expect(Gitlab::Pagination::OffsetPagination).to receive(:new).with(subject).and_return(paginator)
|
|
|
|
|
|
|
|
expect(subject.paginator(relation, request_scope)).to eq(paginator)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when a request scope is not given' do
|
|
|
|
context 'when the default limits are exceeded' do
|
|
|
|
let(:params) { { per_page: 100, page: offset_limit / 100 + 1 } }
|
|
|
|
|
|
|
|
it 'renders a 405 error' do
|
|
|
|
expect(subject).to receive(:error!).with(/maximum allowed offset/, 405)
|
|
|
|
|
|
|
|
subject.paginator(relation)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the default limits are not exceeded' do
|
|
|
|
let(:params) { { per_page: 100, page: offset_limit / 100 } }
|
|
|
|
|
|
|
|
it 'delegates to OffsetPagination' do
|
|
|
|
expect(Gitlab::Pagination::OffsetPagination).to receive(:new).with(subject).and_return(paginator)
|
|
|
|
|
|
|
|
expect(subject.paginator(relation)).to eq(paginator)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when keyset pagination is not available for the relation' do
|
|
|
|
let(:params) { { per_page: 100, page: offset_limit / 100 + 1 } }
|
|
|
|
|
|
|
|
before do
|
|
|
|
allow(Gitlab::Pagination::Keyset).to receive(:available_for_type?).and_return(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'delegates to OffsetPagination' do
|
|
|
|
expect(Gitlab::Pagination::OffsetPagination).to receive(:new).with(subject).and_return(paginator)
|
|
|
|
|
|
|
|
expect(subject.paginator(relation)).to eq(paginator)
|
|
|
|
end
|
2020-03-13 15:44:24 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'for keyset pagination' do
|
|
|
|
let(:params) { { pagination: 'keyset' } }
|
|
|
|
let(:request_context) { double('request context') }
|
|
|
|
let(:pager) { double('pager') }
|
|
|
|
|
|
|
|
before do
|
|
|
|
allow(subject).to receive(:keyset_pagination_enabled?).and_return(true)
|
|
|
|
allow(Gitlab::Pagination::Keyset::RequestContext).to receive(:new).with(subject).and_return(request_context)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when keyset pagination is available' do
|
|
|
|
before do
|
|
|
|
allow(Gitlab::Pagination::Keyset).to receive(:available?).and_return(true)
|
|
|
|
allow(Gitlab::Pagination::Keyset::Pager).to receive(:new).with(request_context).and_return(pager)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'delegates to Pager' do
|
|
|
|
expect(subject.paginator(relation)).to eq(pager)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when keyset pagination is not available' do
|
|
|
|
before do
|
|
|
|
allow(Gitlab::Pagination::Keyset).to receive(:available?).with(request_context, relation).and_return(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'renders a 501 error' do
|
|
|
|
expect(subject).to receive(:error!).with(/not yet available/, 405)
|
|
|
|
|
|
|
|
subject.paginator(relation)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|