From e8798a9e8444ca9ac6993ae7a392942326ee0793 Mon Sep 17 00:00:00 2001 From: Michael Becker <11881043-wandering_person@users.noreply.gitlab.com> Date: Fri, 12 May 2023 13:24:43 +0700 Subject: [PATCH 1/2] Fix edges in KeysetPaginationHelpers spec helper and add specs This is a followup change from a comment on [MR 116344][0] We think it makes more sense to return an empty array from this helper method rather than a `nil` resolves: https://gitlab.com/gitlab-org/gitlab/-/issues/404981 [0]:https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116344 --- .../helpers/keyset_pagination_helpers.rb | 7 +- .../helpers/keyset_pagination_helpers_spec.rb | 84 +++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 spec/support_specs/helpers/keyset_pagination_helpers_spec.rb diff --git a/spec/support/helpers/keyset_pagination_helpers.rb b/spec/support/helpers/keyset_pagination_helpers.rb index 4bc20098e8cbe9..4a476c47fda46a 100644 --- a/spec/support/helpers/keyset_pagination_helpers.rb +++ b/spec/support/helpers/keyset_pagination_helpers.rb @@ -7,14 +7,17 @@ def pagination_links(response) link.split(',').filter_map do |link| match = link.match(/<(?<url>.*)>; rel="(?<rel>\w+)"/) - break nil unless match + next unless match { url: match[:url], rel: match[:rel] } end end def pagination_params_from_next_url(response) - next_url = pagination_links(response).find { |link| link[:rel] == 'next' }[:url] + next_link = pagination_links(response).find { |link| link[:rel] == 'next' } + next_url = next_link&.fetch(:url) + return unless next_url + Rack::Utils.parse_query(URI.parse(next_url).query) end end diff --git a/spec/support_specs/helpers/keyset_pagination_helpers_spec.rb b/spec/support_specs/helpers/keyset_pagination_helpers_spec.rb new file mode 100644 index 00000000000000..4dad087208b496 --- /dev/null +++ b/spec/support_specs/helpers/keyset_pagination_helpers_spec.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe KeysetPaginationHelpers, feature_category: :api do + include described_class + + let(:headers) { { 'LINK' => "<#{url}>; rel=\"#{rel}\"" } } + let(:response) { instance_double('HTTParty::Response', headers: headers) } + let(:rel) { 'next' } + let(:url) do + 'http://127.0.0.1:3000/api/v4/projects/7/audit_eve' \ + 'nts?cursor=eyJpZCI6IjYyMjAiLCJfa2QiOiJuIn0%3D&id=7&o' \ + 'rder_by=id&page=1&pagination=keyset&per_page=2' + end + + describe '#pagination_links' do + subject { pagination_links(response) } + + let(:expected_result) { [{ url: url, rel: rel }] } + + it { is_expected.to eq expected_result } + + context 'with a partially malformed LINK header' do + let(:headers) do + { 'LINK' => "<#{url}>; rel=\"next\", GARBAGE, #{url}; rel=\"prev\"" } + end + + it { is_expected.to eq expected_result } + end + + context 'with a malformed LINK header' do + let(:headers) { { 'LINK' => "rel=\"next\", GARBAGE, #{url}; rel=\"prev\"" } } + let(:expected_result) { [] } + + it { is_expected.to eq expected_result } + end + end + + describe '#pagination_params_from_next_url' do + subject { pagination_params_from_next_url(response) } + + let(:expected_result) do + { + 'cursor' => 'eyJpZCI6IjYyMjAiLCJfa2QiOiJuIn0=', + 'id' => '7', + 'order_by' => 'id', + 'page' => '1', + 'pagination' => 'keyset', + 'per_page' => '2' + } + end + + it { is_expected.to eq expected_result } + + context 'with both prev and next rel links' do + let(:prev_url) do + 'http://127.0.0.1:3000/api/v4/projects/7/audit_eve' \ + 'nts?cursor=foocursor&id=8&o' \ + 'rder_by=id&page=0&pagination=keyset&per_page=2' + end + + let(:headers) do + { 'LINK' => "<#{url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"" } + end + + it { is_expected.to eq expected_result } + end + + context 'with a partially malformed LINK header' do + let(:headers) do + { 'LINK' => "<#{url}>; rel=\"next\", GARBAGE, #{url}; rel=\"prev\"" } + end + + it { is_expected.to eq expected_result } + end + + context 'with a malformed LINK header' do + let(:headers) { { 'LINK' => "rel=\"next\", GARBAGE, #{url}; rel=\"prev\"" } } + + it { is_expected.to be nil } + end + end +end -- GitLab From e78061aeebd5a9e827654a4959775258468cb6a0 Mon Sep 17 00:00:00 2001 From: Michael Becker <11881043-wandering_person@users.noreply.gitlab.com> Date: Mon, 15 May 2023 14:39:35 +0700 Subject: [PATCH 2/2] MR Feedback --- .../helpers/keyset_pagination_helpers_spec.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/spec/support_specs/helpers/keyset_pagination_helpers_spec.rb b/spec/support_specs/helpers/keyset_pagination_helpers_spec.rb index 4dad087208b496..ec63f33776c708 100644 --- a/spec/support_specs/helpers/keyset_pagination_helpers_spec.rb +++ b/spec/support_specs/helpers/keyset_pagination_helpers_spec.rb @@ -5,7 +5,7 @@ RSpec.describe KeysetPaginationHelpers, feature_category: :api do include described_class - let(:headers) { { 'LINK' => "<#{url}>; rel=\"#{rel}\"" } } + let(:headers) { { 'LINK' => %(<#{url}>; rel="#{rel}") } } let(:response) { instance_double('HTTParty::Response', headers: headers) } let(:rel) { 'next' } let(:url) do @@ -22,15 +22,17 @@ it { is_expected.to eq expected_result } context 'with a partially malformed LINK header' do + # malformed as the regxe is expecting the url to be surrounded by `<>` let(:headers) do - { 'LINK' => "<#{url}>; rel=\"next\", GARBAGE, #{url}; rel=\"prev\"" } + { 'LINK' => %(<#{url}>; rel="next", GARBAGE, #{url}; rel="prev") } end it { is_expected.to eq expected_result } end context 'with a malformed LINK header' do - let(:headers) { { 'LINK' => "rel=\"next\", GARBAGE, #{url}; rel=\"prev\"" } } + # malformed as the regxe is expecting the url to be surrounded by `<>` + let(:headers) { { 'LINK' => %(rel="next", GARBAGE, #{url}; rel="prev") } } let(:expected_result) { [] } it { is_expected.to eq expected_result } @@ -61,22 +63,24 @@ end let(:headers) do - { 'LINK' => "<#{url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"" } + { 'LINK' => %(<#{url}>; rel="next", <#{prev_url}>; rel="prev") } end it { is_expected.to eq expected_result } end context 'with a partially malformed LINK header' do + # malformed as the regxe is expecting the url to be surrounded by `<>` let(:headers) do - { 'LINK' => "<#{url}>; rel=\"next\", GARBAGE, #{url}; rel=\"prev\"" } + { 'LINK' => %(<#{url}>; rel="next", GARBAGE, #{url}; rel="prev") } end it { is_expected.to eq expected_result } end context 'with a malformed LINK header' do - let(:headers) { { 'LINK' => "rel=\"next\", GARBAGE, #{url}; rel=\"prev\"" } } + # malformed as the regxe is expecting the url to be surrounded by `<>` + let(:headers) { { 'LINK' => %(rel="next", GARBAGE, #{url}; rel="prev") } } it { is_expected.to be nil } end -- GitLab