2022-01-26 12:08:38 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
|
|
|
RSpec.describe Resolvers::PackagePipelinesResolver do
|
|
|
|
include GraphqlHelpers
|
|
|
|
|
|
|
|
let_it_be_with_reload(:package) { create(:package) }
|
|
|
|
let_it_be(:pipelines) { create_list(:ci_pipeline, 3, project: package.project) }
|
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
let(:user) { package.project.first_owner }
|
2022-01-26 12:08:38 +05:30
|
|
|
|
|
|
|
describe '#resolve' do
|
2022-07-16 23:28:13 +05:30
|
|
|
let(:returned_pipelines) { graphql_dig_at(subject, 'data', 'package', 'pipelines', 'nodes') }
|
|
|
|
let(:returned_errors) { graphql_dig_at(subject, 'errors', 'message') }
|
|
|
|
let(:pagination_args) { {} }
|
|
|
|
let(:query) do
|
|
|
|
pipelines_nodes = 'nodes { id }'
|
|
|
|
graphql_query_for(
|
|
|
|
:package,
|
|
|
|
{ id: global_id_of(package) },
|
|
|
|
query_graphql_field('pipelines', pagination_args, pipelines_nodes)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
subject do
|
|
|
|
GitlabSchema.execute(query, context: { current_user: user })
|
|
|
|
end
|
2022-01-26 12:08:38 +05:30
|
|
|
|
|
|
|
before do
|
2022-04-04 11:22:00 +05:30
|
|
|
pipelines.each do |pipeline|
|
|
|
|
create(:package_build_info, package: package, pipeline: pipeline)
|
|
|
|
end
|
2022-01-26 12:08:38 +05:30
|
|
|
end
|
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
it 'contains the expected pipelines' do
|
|
|
|
expect_to_contain_exactly(*pipelines)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with valid after' do
|
|
|
|
let(:pagination_args) { { first: 1, after: encode_cursor(id: pipelines[1].id) } }
|
|
|
|
|
|
|
|
it 'contains the expected pipelines' do
|
|
|
|
expect_to_contain_exactly(pipelines[0])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with valid before' do
|
|
|
|
let(:pagination_args) { { last: 1, before: encode_cursor(id: pipelines[1].id) } }
|
|
|
|
|
|
|
|
it 'contains the expected pipelines' do
|
|
|
|
expect_to_contain_exactly(pipelines[2])
|
|
|
|
end
|
|
|
|
end
|
2022-01-26 12:08:38 +05:30
|
|
|
|
|
|
|
context 'with invalid after' do
|
2022-07-16 23:28:13 +05:30
|
|
|
let(:pagination_args) { { first: 1, after: 'not_json_string' } }
|
2022-01-26 12:08:38 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it 'generates an argument error' do
|
2022-07-16 23:28:13 +05:30
|
|
|
expect(returned_errors).to include('Please provide a valid cursor')
|
2022-01-26 12:08:38 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with invalid after key' do
|
2022-07-16 23:28:13 +05:30
|
|
|
let(:pagination_args) { { first: 1, after: encode_cursor(foo: 3) } }
|
2022-01-26 12:08:38 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it 'generates an argument error' do
|
2022-07-16 23:28:13 +05:30
|
|
|
expect(returned_errors).to include('Please provide a valid cursor')
|
2022-01-26 12:08:38 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with invalid before' do
|
2022-07-16 23:28:13 +05:30
|
|
|
let(:pagination_args) { { last: 1, before: 'not_json_string' } }
|
2022-01-26 12:08:38 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it 'generates an argument error' do
|
2022-07-16 23:28:13 +05:30
|
|
|
expect(returned_errors).to include('Please provide a valid cursor')
|
2022-01-26 12:08:38 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with invalid before key' do
|
2022-07-16 23:28:13 +05:30
|
|
|
let(:pagination_args) { { last: 1, before: encode_cursor(foo: 3) } }
|
2022-01-26 12:08:38 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it 'generates an argument error' do
|
2022-07-16 23:28:13 +05:30
|
|
|
expect(returned_errors).to include('Please provide a valid cursor')
|
2022-01-26 12:08:38 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
context 'with unauthorized user' do
|
|
|
|
let_it_be(:user) { create(:user) }
|
2022-01-26 12:08:38 +05:30
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
it 'returns nothing' do
|
|
|
|
expect(returned_pipelines).to be_nil
|
2022-01-26 12:08:38 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
context 'with many packages' do
|
|
|
|
let_it_be_with_reload(:other_package) { create(:package, project: package.project) }
|
|
|
|
let_it_be(:other_pipelines) { create_list(:ci_pipeline, 3, project: package.project) }
|
|
|
|
|
|
|
|
let(:returned_pipelines) do
|
|
|
|
graphql_dig_at(subject, 'data', 'project', 'packages', 'nodes', 'pipelines', 'nodes')
|
|
|
|
end
|
2022-01-26 12:08:38 +05:30
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
let(:query) do
|
|
|
|
pipelines_query = query_graphql_field('pipelines', pagination_args, 'nodes { id }')
|
|
|
|
<<~QUERY
|
|
|
|
{
|
|
|
|
project(fullPath: "#{package.project.full_path}") {
|
|
|
|
packages {
|
|
|
|
nodes { #{pipelines_query} }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QUERY
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
other_pipelines.each do |pipeline|
|
|
|
|
create(:package_build_info, package: other_package, pipeline: pipeline)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'contains the expected pipelines' do
|
|
|
|
expect_to_contain_exactly(*(pipelines + other_pipelines))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'handles n+1 situations' do
|
|
|
|
control = ActiveRecord::QueryRecorder.new do
|
|
|
|
GitlabSchema.execute(query, context: { current_user: user })
|
|
|
|
end
|
|
|
|
|
|
|
|
create_package_with_pipelines(package.project)
|
|
|
|
|
|
|
|
expectation = expect { GitlabSchema.execute(query, context: { current_user: user }) }
|
|
|
|
|
|
|
|
expectation.not_to exceed_query_limit(control)
|
|
|
|
end
|
|
|
|
|
|
|
|
def create_package_with_pipelines(project)
|
|
|
|
extra_package = create(:package, project: project)
|
|
|
|
create_list(:ci_pipeline, 3, project: project).each do |pipeline|
|
|
|
|
create(:package_build_info, package: extra_package, pipeline: pipeline)
|
|
|
|
end
|
|
|
|
end
|
2022-01-26 12:08:38 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def encode_cursor(json)
|
|
|
|
GitlabSchema.cursor_encoder.encode(
|
|
|
|
Gitlab::Json.dump(json),
|
|
|
|
nonce: true
|
|
|
|
)
|
|
|
|
end
|
2022-07-16 23:28:13 +05:30
|
|
|
|
|
|
|
def expect_to_contain_exactly(*pipelines)
|
|
|
|
entities = pipelines.map { |pipeline| a_graphql_entity_for(pipeline) }
|
|
|
|
expect(returned_pipelines).to match_array(entities)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.field options' do
|
|
|
|
let(:field) do
|
|
|
|
field_options = described_class.field_options.merge(
|
|
|
|
owner: resolver_parent,
|
|
|
|
name: 'dummy_field'
|
|
|
|
)
|
|
|
|
::Types::BaseField.new(**field_options)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'sets them properly' do
|
|
|
|
expect(field).not_to be_connection
|
|
|
|
expect(field.extras).to match_array([:lookahead])
|
|
|
|
end
|
2022-01-26 12:08:38 +05:30
|
|
|
end
|
|
|
|
end
|