Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/graphql')
-rw-r--r--spec/graphql/mutations/boards/lists/create_spec.rb78
-rw-r--r--spec/graphql/mutations/concerns/mutations/can_mutate_spammable_spec.rb46
-rw-r--r--spec/graphql/mutations/merge_requests/update_spec.rb21
-rw-r--r--spec/graphql/mutations/security/ci_configuration/configure_sast_spec.rb120
-rw-r--r--spec/graphql/resolvers/base_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/board_list_issues_resolver_spec.rb6
-rw-r--r--spec/graphql/resolvers/board_lists_resolver_spec.rb12
-rw-r--r--spec/graphql/resolvers/ci/config_resolver_spec.rb3
-rw-r--r--spec/graphql/resolvers/container_repositories_resolver_spec.rb28
-rw-r--r--spec/graphql/resolvers/group_labels_resolver_spec.rb96
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb12
-rw-r--r--spec/graphql/resolvers/labels_resolver_spec.rb96
-rw-r--r--spec/graphql/resolvers/merge_requests_resolver_spec.rb62
-rw-r--r--spec/graphql/resolvers/package_details_resolver_spec.rb5
-rw-r--r--spec/graphql/resolvers/packages_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/release_milestones_resolver_spec.rb9
-rw-r--r--spec/graphql/resolvers/release_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/terraform/states_resolver_spec.rb20
-rw-r--r--spec/graphql/types/ci/pipeline_type_spec.rb2
-rw-r--r--spec/graphql/types/ci_configuration/sast/analyzers_entity_input_type_spec.rb9
-rw-r--r--spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/entity_input_type_spec.rb9
-rw-r--r--spec/graphql/types/ci_configuration/sast/entity_type_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/input_type_spec.rb9
-rw-r--r--spec/graphql/types/ci_configuration/sast/options_entity_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/type_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/ui_component_size_enum_spec.rb11
-rw-r--r--spec/graphql/types/container_repository_sort_enum_spec.rb15
-rw-r--r--spec/graphql/types/event_type_spec.rb11
-rw-r--r--spec/graphql/types/eventable_type_spec.rb9
-rw-r--r--spec/graphql/types/group_type_spec.rb4
-rw-r--r--spec/graphql/types/merge_request_state_event_enum_spec.rb12
-rw-r--r--spec/graphql/types/packages/composer/details_type_spec.rb23
-rw-r--r--spec/graphql/types/packages/composer/metadatum_type_spec.rb4
-rw-r--r--spec/graphql/types/packages/package_type_enum_spec.rb2
-rw-r--r--spec/graphql/types/packages/package_type_spec.rb7
-rw-r--r--spec/graphql/types/packages/package_without_versions_type_spec.rb13
-rw-r--r--spec/graphql/types/project_type_spec.rb172
-rw-r--r--spec/graphql/types/query_type_spec.rb6
-rw-r--r--spec/graphql/types/user_type_spec.rb1
40 files changed, 828 insertions, 157 deletions
diff --git a/spec/graphql/mutations/boards/lists/create_spec.rb b/spec/graphql/mutations/boards/lists/create_spec.rb
index 894dd1f34b4..815064e7c58 100644
--- a/spec/graphql/mutations/boards/lists/create_spec.rb
+++ b/spec/graphql/mutations/boards/lists/create_spec.rb
@@ -3,84 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::Boards::Lists::Create do
- include GraphqlHelpers
-
let_it_be(:group) { create(:group, :private) }
let_it_be(:board) { create(:board, group: group) }
- let_it_be(:user) { create(:user) }
- let_it_be(:guest) { create(:user) }
-
- let(:current_user) { user }
- let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
- let(:list_create_params) { {} }
-
- before_all do
- group.add_reporter(user)
- group.add_guest(guest)
- end
-
- subject { mutation.resolve(board_id: board.to_global_id.to_s, **list_create_params) }
-
- describe '#ready?' do
- it 'raises an error if required arguments are missing' do
- expect { mutation.ready?(board_id: 'some id') }
- .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/)
- end
-
- it 'raises an error if too many required arguments are specified' do
- expect { mutation.ready?(board_id: 'some id', backlog: true, label_id: 'some label') }
- .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/)
- end
- end
-
- describe '#resolve' do
- context 'with proper permissions' do
- describe 'backlog list' do
- let(:list_create_params) { { backlog: true } }
-
- it 'creates one and only one backlog' do
- expect { subject }.to change { board.lists.backlog.count }.from(0).to(1)
- expect(board.lists.backlog.first.list_type).to eq 'backlog'
-
- backlog_id = board.lists.backlog.first.id
-
- expect { subject }.not_to change { board.lists.backlog.count }
- expect(board.lists.backlog.last.id).to eq backlog_id
- end
- end
-
- describe 'label list' do
- let_it_be(:dev_label) do
- create(:group_label, title: 'Development', color: '#FFAABB', group: group)
- end
-
- let(:list_create_params) { { label_id: dev_label.to_global_id.to_s } }
-
- it 'creates a new issue board list for labels' do
- expect { subject }.to change { board.lists.count }.from(1).to(2)
-
- new_list = subject[:list]
-
- expect(new_list.title).to eq dev_label.title
- expect(new_list.position).to eq 0
- end
-
- context 'when label not found' do
- let(:list_create_params) { { label_id: "gid://gitlab/Label/#{non_existing_record_id}" } }
-
- it 'returns an error' do
- expect(subject[:errors]).to include 'Label not found'
- end
- end
- end
- end
-
- context 'without proper permissions' do
- let(:current_user) { guest }
- it 'raises an error' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
- end
- end
- end
+ it_behaves_like 'board lists create mutation'
end
diff --git a/spec/graphql/mutations/concerns/mutations/can_mutate_spammable_spec.rb b/spec/graphql/mutations/concerns/mutations/can_mutate_spammable_spec.rb
new file mode 100644
index 00000000000..ee8db7a1f31
--- /dev/null
+++ b/spec/graphql/mutations/concerns/mutations/can_mutate_spammable_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::CanMutateSpammable do
+ let(:mutation_class) do
+ Class.new(Mutations::BaseMutation) do
+ include Mutations::CanMutateSpammable
+ end
+ end
+
+ let(:request) { double(:request) }
+ let(:query) { double(:query, schema: GitlabSchema) }
+ let(:context) { GraphQL::Query::Context.new(query: query, object: nil, values: { request: request }) }
+
+ subject(:mutation) { mutation_class.new(object: nil, context: context, field: nil) }
+
+ describe '#additional_spam_params' do
+ it 'returns additional spam-related params' do
+ expect(subject.send(:additional_spam_params)).to eq({ api: true, request: request })
+ end
+ end
+
+ describe '#with_spam_action_fields' do
+ let(:spam_log) { double(:spam_log, id: 1) }
+ let(:spammable) { double(:spammable, spam?: true, render_recaptcha?: true, spam_log: spam_log) }
+
+ before do
+ allow(Gitlab::CurrentSettings).to receive(:recaptcha_site_key) { 'abc123' }
+ end
+
+ it 'merges in spam action fields from spammable' do
+ result = subject.send(:with_spam_action_fields, spammable) do
+ { other_field: true }
+ end
+ expect(result)
+ .to eq({
+ spam: true,
+ needs_captcha_response: true,
+ spam_log_id: 1,
+ captcha_site_key: 'abc123',
+ other_field: true
+ })
+ end
+ end
+end
diff --git a/spec/graphql/mutations/merge_requests/update_spec.rb b/spec/graphql/mutations/merge_requests/update_spec.rb
index 8acd2562ea8..206abaf34ce 100644
--- a/spec/graphql/mutations/merge_requests/update_spec.rb
+++ b/spec/graphql/mutations/merge_requests/update_spec.rb
@@ -12,10 +12,11 @@ RSpec.describe Mutations::MergeRequests::Update do
describe '#resolve' do
let(:attributes) { { title: 'new title', description: 'new description', target_branch: 'new-branch' } }
+ let(:arguments) { attributes }
let(:mutated_merge_request) { subject[:merge_request] }
subject do
- mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, **attributes)
+ mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, **arguments)
end
it_behaves_like 'permission level for merge request mutation is correctly verified'
@@ -61,6 +62,24 @@ RSpec.describe Mutations::MergeRequests::Update do
expect(mutated_merge_request).to have_attributes(attributes)
end
end
+
+ context 'when closing the MR' do
+ let(:arguments) { { state_event: ::Types::MergeRequestStateEventEnum.values['CLOSED'].value } }
+
+ it 'closes the MR' do
+ expect(mutated_merge_request).to be_closed
+ end
+ end
+
+ context 'when re-opening the MR' do
+ let(:arguments) { { state_event: ::Types::MergeRequestStateEventEnum.values['OPEN'].value } }
+
+ it 'closes the MR' do
+ merge_request.close!
+
+ expect(mutated_merge_request).to be_open
+ end
+ end
end
end
end
diff --git a/spec/graphql/mutations/security/ci_configuration/configure_sast_spec.rb b/spec/graphql/mutations/security/ci_configuration/configure_sast_spec.rb
new file mode 100644
index 00000000000..ed03a1cb906
--- /dev/null
+++ b/spec/graphql/mutations/security/ci_configuration/configure_sast_spec.rb
@@ -0,0 +1,120 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Security::CiConfiguration::ConfigureSast do
+ subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
+
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:user) { create(:user) }
+
+ let_it_be(:service_result_json) do
+ {
+ status: "success",
+ success_path: "http://127.0.0.1:3000/root/demo-historic-secrets/-/merge_requests/new?",
+ errors: nil
+ }
+ end
+
+ let_it_be(:service_error_result_json) do
+ {
+ status: "error",
+ success_path: nil,
+ errors: %w(error1 error2)
+ }
+ end
+
+ let(:context) do
+ GraphQL::Query::Context.new(
+ query: OpenStruct.new(schema: nil),
+ values: { current_user: user },
+ object: nil
+ )
+ end
+
+ specify { expect(described_class).to require_graphql_authorizations(:push_code) }
+
+ describe '#resolve' do
+ subject { mutation.resolve(project_path: project.full_path, configuration: {}) }
+
+ let(:result) { subject }
+
+ it 'raises an error if the resource is not accessible to the user' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+
+ context 'when user does not have enough permissions' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when user is a maintainer of a different project' do
+ before do
+ create(:project_empty_repo).add_maintainer(user)
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when the user does not have permission to create a new branch' do
+ before_all do
+ project.add_developer(user)
+ end
+
+ let(:error_message) { 'You are not allowed to create protected branches on this project.' }
+
+ it 'returns an array of errors' do
+ allow_next_instance_of(::Files::MultiService) do |multi_service|
+ allow(multi_service).to receive(:execute).and_raise(Gitlab::Git::PreReceiveError.new("GitLab: #{error_message}"))
+ end
+
+ expect(result).to match(
+ status: :error,
+ success_path: nil,
+ errors: match_array([error_message])
+ )
+ end
+ end
+
+ context 'when the user can create a merge request' do
+ before_all do
+ project.add_developer(user)
+ end
+
+ context 'when service successfully generates a path to create a new merge request' do
+ it 'returns a success path' do
+ allow_next_instance_of(::Security::CiConfiguration::SastCreateService) do |service|
+ allow(service).to receive(:execute).and_return(service_result_json)
+ end
+
+ expect(result).to match(
+ status: 'success',
+ success_path: service_result_json[:success_path],
+ errors: []
+ )
+ end
+ end
+
+ context 'when service can not generate any path to create a new merge request' do
+ it 'returns an array of errors' do
+ allow_next_instance_of(::Security::CiConfiguration::SastCreateService) do |service|
+ allow(service).to receive(:execute).and_return(service_error_result_json)
+ end
+
+ expect(result).to match(
+ status: 'error',
+ success_path: be_nil,
+ errors: match_array(service_error_result_json[:errors])
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/base_resolver_spec.rb b/spec/graphql/resolvers/base_resolver_spec.rb
index 8a24b69eb6f..8d2ae238bfe 100644
--- a/spec/graphql/resolvers/base_resolver_spec.rb
+++ b/spec/graphql/resolvers/base_resolver_spec.rb
@@ -277,8 +277,8 @@ RSpec.describe Resolvers::BaseResolver do
describe '#offset_pagination' do
let(:instance) { resolver_instance(resolver) }
- it 'is sugar for OffsetActiveRecordRelationConnection.new' do
- expect(instance.offset_pagination(User.none)).to be_a(::Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection)
+ it 'is sugar for OffsetPaginatedRelation.new' do
+ expect(instance.offset_pagination(User.none)).to be_a(::Gitlab::Graphql::Pagination::OffsetPaginatedRelation)
end
end
end
diff --git a/spec/graphql/resolvers/board_list_issues_resolver_spec.rb b/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
index e7c56a526f4..5eda840854a 100644
--- a/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
@@ -23,19 +23,19 @@ RSpec.describe Resolvers::BoardListIssuesResolver do
it 'returns the issues in the correct order' do
# by relative_position and then ID
- issues = resolve_board_list_issues.items
+ issues = resolve_board_list_issues
expect(issues.map(&:id)).to eq [issue3.id, issue1.id, issue2.id]
end
it 'finds only issues matching filters' do
- result = resolve_board_list_issues(args: { filters: { label_name: [label.title], not: { label_name: [label2.title] } } }).items
+ result = resolve_board_list_issues(args: { filters: { label_name: [label.title], not: { label_name: [label2.title] } } })
expect(result).to match_array([issue1, issue3])
end
it 'finds only issues matching search param' do
- result = resolve_board_list_issues(args: { filters: { search: issue1.title } }).items
+ result = resolve_board_list_issues(args: { filters: { search: issue1.title } })
expect(result).to match_array([issue1])
end
diff --git a/spec/graphql/resolvers/board_lists_resolver_spec.rb b/spec/graphql/resolvers/board_lists_resolver_spec.rb
index 71ebec4dc7e..fdcebd30bb3 100644
--- a/spec/graphql/resolvers/board_lists_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_lists_resolver_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe Resolvers::BoardListsResolver do
end
it 'does not create the backlog list' do
- lists = resolve_board_lists.items
+ lists = resolve_board_lists
expect(lists.count).to eq 1
expect(lists[0].list_type).to eq 'closed'
@@ -38,7 +38,7 @@ RSpec.describe Resolvers::BoardListsResolver do
let!(:backlog_list) { create(:backlog_list, board: board) }
it 'returns a list of board lists' do
- lists = resolve_board_lists.items
+ lists = resolve_board_lists
expect(lists.count).to eq 3
expect(lists.map(&:list_type)).to eq %w(backlog label closed)
@@ -50,7 +50,7 @@ RSpec.describe Resolvers::BoardListsResolver do
end
it 'returns the complete list of board lists for this user' do
- lists = resolve_board_lists.items
+ lists = resolve_board_lists
expect(lists.count).to eq 3
end
@@ -58,7 +58,7 @@ RSpec.describe Resolvers::BoardListsResolver do
context 'when querying for a single list' do
it 'returns specified list' do
- list = resolve_board_lists(args: { id: global_id_of(label_list) }).items
+ list = resolve_board_lists(args: { id: global_id_of(label_list) })
expect(list).to eq [label_list]
end
@@ -69,13 +69,13 @@ RSpec.describe Resolvers::BoardListsResolver do
external_label = create(:group_label, group: group)
external_list = create(:list, board: external_board, label: external_label)
- list = resolve_board_lists(args: { id: global_id_of(external_list) }).items
+ list = resolve_board_lists(args: { id: global_id_of(external_list) })
expect(list).to eq List.none
end
it 'raises an argument error if list ID is not valid' do
- expect { resolve_board_lists(args: { id: 'test' }).items }
+ expect { resolve_board_lists(args: { id: 'test' }) }
.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
end
end
diff --git a/spec/graphql/resolvers/ci/config_resolver_spec.rb b/spec/graphql/resolvers/ci/config_resolver_spec.rb
index ca7ae73fef8..73e9fab9f99 100644
--- a/spec/graphql/resolvers/ci/config_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/config_resolver_spec.rb
@@ -36,7 +36,8 @@ RSpec.describe Resolvers::Ci::ConfigResolver do
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_includes.yml'))
end
- it 'lints the ci config file' do
+ it 'lints the ci config file and returns the merged yaml file' do
+ expect(response[:merged_yaml]).to eq(content)
expect(response[:status]).to eq(:valid)
expect(response[:errors]).to be_empty
end
diff --git a/spec/graphql/resolvers/container_repositories_resolver_spec.rb b/spec/graphql/resolvers/container_repositories_resolver_spec.rb
index b888d79626e..a17d2a7b0d5 100644
--- a/spec/graphql/resolvers/container_repositories_resolver_spec.rb
+++ b/spec/graphql/resolvers/container_repositories_resolver_spec.rb
@@ -27,6 +27,34 @@ RSpec.describe Resolvers::ContainerRepositoriesResolver do
it { is_expected.to contain_exactly(named_container_repository) }
end
+
+ context 'with a sort argument' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:sort_repository) do
+ create(:container_repository, name: 'bar', project: project, created_at: 1.day.ago)
+ end
+
+ let_it_be(:sort_repository2) do
+ create(:container_repository, name: 'foo', project: project, created_at: 1.hour.ago, updated_at: 1.hour.ago)
+ end
+
+ [:created_desc, :updated_asc, :name_desc].each do |order|
+ context "#{order}" do
+ let(:args) { { sort: order } }
+
+ it { is_expected.to eq([sort_repository2, sort_repository]) }
+ end
+ end
+
+ [:created_asc, :updated_desc, :name_asc].each do |order|
+ context "#{order}" do
+ let(:args) { { sort: order } }
+
+ it { is_expected.to eq([sort_repository, sort_repository2]) }
+ end
+ end
+ end
end
context 'with authorized user' do
diff --git a/spec/graphql/resolvers/group_labels_resolver_spec.rb b/spec/graphql/resolvers/group_labels_resolver_spec.rb
new file mode 100644
index 00000000000..ed94f12502a
--- /dev/null
+++ b/spec/graphql/resolvers/group_labels_resolver_spec.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::GroupLabelsResolver do
+ include GraphqlHelpers
+
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:group, reload: true) { create(:group, :private) }
+ let_it_be(:subgroup, reload: true) { create(:group, :private, parent: group) }
+ let_it_be(:sub_subgroup, reload: true) { create(:group, :private, parent: subgroup) }
+ let_it_be(:project, reload: true) { create(:project, :private, group: sub_subgroup) }
+ let_it_be(:label1) { create(:label, project: project, name: 'project feature') }
+ let_it_be(:label2) { create(:label, project: project, name: 'new project feature') }
+ let_it_be(:group_label1) { create(:group_label, group: group, name: 'group feature') }
+ let_it_be(:group_label2) { create(:group_label, group: group, name: 'new group feature') }
+ let_it_be(:subgroup_label1) { create(:group_label, group: subgroup, name: 'subgroup feature') }
+ let_it_be(:subgroup_label2) { create(:group_label, group: subgroup, name: 'new subgroup feature') }
+ let_it_be(:sub_subgroup_label1) { create(:group_label, group: sub_subgroup, name: 'sub_subgroup feature') }
+ let_it_be(:sub_subgroup_label2) { create(:group_label, group: sub_subgroup, name: 'new sub_subgroup feature') }
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::LabelType.connection_type)
+ end
+
+ describe '#resolve' do
+ context 'with unauthorized user' do
+ it 'raises error' do
+ expect { resolve_labels(subgroup) }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'with authorized user' do
+ it 'does not raise error' do
+ group.add_guest(current_user)
+
+ expect { resolve_labels(subgroup) }.not_to raise_error
+ end
+ end
+
+ context 'without parent' do
+ it 'returns no labels' do
+ expect(resolve_labels(nil)).to eq(Label.none)
+ end
+ end
+
+ context 'at group level' do
+ before_all do
+ group.add_developer(current_user)
+ end
+
+ # because :include_ancestor_groups, :include_descendant_groups, :only_group_labels default to false
+ # the `nil` value would be equivalent to passing in `false` so just check for `nil` option
+ where(:include_ancestor_groups, :include_descendant_groups, :only_group_labels, :search_term, :test) do
+ nil | nil | nil | nil | -> { expect(subject).to contain_exactly(subgroup_label1, subgroup_label2) }
+ nil | nil | true | nil | -> { expect(subject).to contain_exactly(subgroup_label1, subgroup_label2) }
+ nil | true | nil | nil | -> { expect(subject).to contain_exactly(subgroup_label1, subgroup_label2, sub_subgroup_label1, sub_subgroup_label2, label1, label2) }
+ nil | true | true | nil | -> { expect(subject).to contain_exactly(subgroup_label1, subgroup_label2, sub_subgroup_label1, sub_subgroup_label2) }
+ true | nil | nil | nil | -> { expect(subject).to contain_exactly(group_label1, group_label2, subgroup_label1, subgroup_label2) }
+ true | nil | true | nil | -> { expect(subject).to contain_exactly(group_label1, group_label2, subgroup_label1, subgroup_label2) }
+ true | true | nil | nil | -> { expect(subject).to contain_exactly(group_label1, group_label2, subgroup_label1, subgroup_label2, sub_subgroup_label1, sub_subgroup_label2, label1, label2) }
+ true | true | true | nil | -> { expect(subject).to contain_exactly(group_label1, group_label2, subgroup_label1, subgroup_label2, sub_subgroup_label1, sub_subgroup_label2) }
+
+ nil | nil | nil | 'new' | -> { expect(subject).to contain_exactly(subgroup_label2) }
+ nil | nil | true | 'new' | -> { expect(subject).to contain_exactly(subgroup_label2) }
+ nil | true | nil | 'new' | -> { expect(subject).to contain_exactly(subgroup_label2, sub_subgroup_label2, label2) }
+ nil | true | true | 'new' | -> { expect(subject).to contain_exactly(subgroup_label2, sub_subgroup_label2) }
+ true | nil | nil | 'new' | -> { expect(subject).to contain_exactly(group_label2, subgroup_label2) }
+ true | nil | true | 'new' | -> { expect(subject).to contain_exactly(group_label2, subgroup_label2) }
+ true | true | nil | 'new' | -> { expect(subject).to contain_exactly(group_label2, subgroup_label2, sub_subgroup_label2, label2) }
+ true | true | true | 'new' | -> { expect(subject).to contain_exactly(group_label2, subgroup_label2, sub_subgroup_label2) }
+ end
+
+ with_them do
+ let(:params) do
+ {
+ include_ancestor_groups: include_ancestor_groups,
+ include_descendant_groups: include_descendant_groups,
+ only_group_labels: only_group_labels,
+ search_term: search_term
+ }
+ end
+
+ subject { resolve_labels(subgroup, params) }
+
+ it { self.instance_exec(&test) }
+ end
+ end
+ end
+
+ def resolve_labels(parent, args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: parent, args: args, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index 269ee9eabf9..8980f4aa19d 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -195,11 +195,11 @@ RSpec.describe Resolvers::IssuesResolver do
let_it_be(:priority_issue4) { create(:issue, project: project) }
it 'sorts issues ascending' do
- expect(resolve_issues(sort: :priority_asc).items).to eq([priority_issue3, priority_issue1, priority_issue2, priority_issue4])
+ expect(resolve_issues(sort: :priority_asc).to_a).to eq([priority_issue3, priority_issue1, priority_issue2, priority_issue4])
end
it 'sorts issues descending' do
- expect(resolve_issues(sort: :priority_desc).items).to eq([priority_issue1, priority_issue3, priority_issue2, priority_issue4])
+ expect(resolve_issues(sort: :priority_desc).to_a).to eq([priority_issue1, priority_issue3, priority_issue2, priority_issue4])
end
end
@@ -214,11 +214,11 @@ RSpec.describe Resolvers::IssuesResolver do
let_it_be(:label_issue4) { create(:issue, project: project) }
it 'sorts issues ascending' do
- expect(resolve_issues(sort: :label_priority_asc).items).to eq([label_issue3, label_issue1, label_issue2, label_issue4])
+ expect(resolve_issues(sort: :label_priority_asc).to_a).to eq([label_issue3, label_issue1, label_issue2, label_issue4])
end
it 'sorts issues descending' do
- expect(resolve_issues(sort: :label_priority_desc).items).to eq([label_issue2, label_issue3, label_issue1, label_issue4])
+ expect(resolve_issues(sort: :label_priority_desc).to_a).to eq([label_issue2, label_issue3, label_issue1, label_issue4])
end
end
@@ -231,11 +231,11 @@ RSpec.describe Resolvers::IssuesResolver do
let_it_be(:milestone_issue3) { create(:issue, project: project, milestone: late_milestone) }
it 'sorts issues ascending' do
- expect(resolve_issues(sort: :milestone_due_asc).items).to eq([milestone_issue2, milestone_issue3, milestone_issue1])
+ expect(resolve_issues(sort: :milestone_due_asc).to_a).to eq([milestone_issue2, milestone_issue3, milestone_issue1])
end
it 'sorts issues descending' do
- expect(resolve_issues(sort: :milestone_due_desc).items).to eq([milestone_issue3, milestone_issue2, milestone_issue1])
+ expect(resolve_issues(sort: :milestone_due_desc).to_a).to eq([milestone_issue3, milestone_issue2, milestone_issue1])
end
end
diff --git a/spec/graphql/resolvers/labels_resolver_spec.rb b/spec/graphql/resolvers/labels_resolver_spec.rb
new file mode 100644
index 00000000000..3d027a6c8d5
--- /dev/null
+++ b/spec/graphql/resolvers/labels_resolver_spec.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::LabelsResolver do
+ include GraphqlHelpers
+
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:group, reload: true) { create(:group, :private) }
+ let_it_be(:subgroup, reload: true) { create(:group, :private, parent: group) }
+ let_it_be(:sub_subgroup, reload: true) { create(:group, :private, parent: subgroup) }
+ let_it_be(:project, reload: true) { create(:project, :private, group: subgroup) }
+ let_it_be(:label1) { create(:label, project: project, name: 'project feature') }
+ let_it_be(:label2) { create(:label, project: project, name: 'new project feature') }
+ let_it_be(:group_label1) { create(:group_label, group: group, name: 'group feature') }
+ let_it_be(:group_label2) { create(:group_label, group: group, name: 'new group feature') }
+ let_it_be(:subgroup_label1) { create(:group_label, group: subgroup, name: 'subgroup feature') }
+ let_it_be(:subgroup_label2) { create(:group_label, group: subgroup, name: 'new subgroup feature') }
+ let_it_be(:sub_subgroup_label1) { create(:group_label, group: sub_subgroup, name: 'sub_subgroup feature') }
+ let_it_be(:sub_subgroup_label2) { create(:group_label, group: sub_subgroup, name: 'new sub_subgroup feature') }
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::LabelType.connection_type)
+ end
+
+ describe '#resolve' do
+ context 'with unauthorized user' do
+ it 'returns no labels' do
+ expect { resolve_labels(project) }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'with authorized user' do
+ it 'returns no labels' do
+ group.add_guest(current_user)
+
+ expect { resolve_labels(project) }.not_to raise_error
+ end
+ end
+
+ context 'without parent' do
+ it 'returns no labels' do
+ expect(resolve_labels(nil)).to eq(Label.none)
+ end
+ end
+
+ context 'at project level' do
+ before_all do
+ group.add_developer(current_user)
+ end
+
+ # because :include_ancestor_groups, :include_descendant_groups, :only_group_labels default to false
+ # the `nil` value would be equivalent to passing in `false` so just check for `nil` option
+ where(:include_ancestor_groups, :include_descendant_groups, :only_group_labels, :search_term, :test) do
+ nil | nil | nil | nil | -> { expect(subject).to contain_exactly(label1, label2, subgroup_label1, subgroup_label2) }
+ nil | nil | true | nil | -> { expect(subject).to contain_exactly(label1, label2, subgroup_label1, subgroup_label2) }
+ nil | true | nil | nil | -> { expect(subject).to contain_exactly(label1, label2, subgroup_label1, subgroup_label2, sub_subgroup_label1, sub_subgroup_label2) }
+ nil | true | true | nil | -> { expect(subject).to contain_exactly(label1, label2, subgroup_label1, subgroup_label2, sub_subgroup_label1, sub_subgroup_label2) }
+ true | nil | nil | nil | -> { expect(subject).to contain_exactly(label1, label2, group_label1, group_label2, subgroup_label1, subgroup_label2) }
+ true | nil | true | nil | -> { expect(subject).to contain_exactly(label1, label2, group_label1, group_label2, subgroup_label1, subgroup_label2) }
+ true | true | nil | nil | -> { expect(subject).to contain_exactly(label1, label2, group_label1, group_label2, subgroup_label1, subgroup_label2, sub_subgroup_label1, sub_subgroup_label2) }
+ true | true | true | nil | -> { expect(subject).to contain_exactly(label1, label2, group_label1, group_label2, subgroup_label1, subgroup_label2, sub_subgroup_label1, sub_subgroup_label2) }
+
+ nil | nil | nil | 'new' | -> { expect(subject).to contain_exactly(label2, subgroup_label2) }
+ nil | nil | true | 'new' | -> { expect(subject).to contain_exactly(label2, subgroup_label2) }
+ nil | true | nil | 'new' | -> { expect(subject).to contain_exactly(label2, subgroup_label2, sub_subgroup_label2) }
+ nil | true | true | 'new' | -> { expect(subject).to contain_exactly(label2, subgroup_label2, sub_subgroup_label2) }
+ true | nil | nil | 'new' | -> { expect(subject).to contain_exactly(label2, group_label2, subgroup_label2) }
+ true | nil | true | 'new' | -> { expect(subject).to contain_exactly(label2, group_label2, subgroup_label2) }
+ true | true | nil | 'new' | -> { expect(subject).to contain_exactly(label2, group_label2, subgroup_label2, sub_subgroup_label2) }
+ true | true | true | 'new' | -> { expect(subject).to contain_exactly(label2, group_label2, subgroup_label2, sub_subgroup_label2) }
+ end
+
+ with_them do
+ let(:params) do
+ {
+ include_ancestor_groups: include_ancestor_groups,
+ include_descendant_groups: include_descendant_groups,
+ only_group_labels: only_group_labels,
+ search_term: search_term
+ }
+ end
+
+ subject { resolve_labels(project, params) }
+
+ it { self.instance_exec(&test) }
+ end
+ end
+ end
+
+ def resolve_labels(parent, args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: parent, args: args, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
index 50b9243efa5..c5c368fc88f 100644
--- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Resolvers::MergeRequestsResolver do
include GraphqlHelpers
+ include SortingHelper
let_it_be(:project) { create(:project, :repository) }
let_it_be(:milestone) { create(:milestone, project: project) }
@@ -30,6 +31,16 @@ RSpec.describe Resolvers::MergeRequestsResolver do
end
describe '#resolve' do
+ # One for the initial auth, then MRs, and the load of project and project_feature (for further auth):
+ # SELECT MAX("project_authorizations"."access_level") AS maximum_access_level,
+ # "project_authorizations"."user_id" AS project_authorizations_user_id
+ # FROM "project_authorizations"
+ # WHERE "project_authorizations"."project_id" = 2 AND "project_authorizations"."user_id" = 2
+ # GROUP BY "project_authorizations"."user_id"
+ # SELECT "merge_requests".* FROM "merge_requests" WHERE "merge_requests"."target_project_id" = 2
+ # AND "merge_requests"."iid" = 1 ORDER BY "merge_requests"."id" DESC
+ # SELECT "projects".* FROM "projects" WHERE "projects"."id" = 2
+ # SELECT "project_features".* FROM "project_features" WHERE "project_features"."project_id" = 2
let(:queries_per_project) { 3 }
context 'no arguments' do
@@ -72,15 +83,17 @@ RSpec.describe Resolvers::MergeRequestsResolver do
expect(result).to contain_exactly(merge_request_1, merge_request_2, merge_request_3)
end
- it 'can batch-resolve merge requests from different projects' do
+ it 'can batch-resolve merge requests from different projects', :request_store, :use_clean_rails_memory_store_caching do
# 2 queries for project_authorizations, and 2 for merge_requests
- result = batch_sync(max_queries: queries_per_project * 2) do
- resolve_mr(project, iids: [iid_1]) +
- resolve_mr(project, iids: [iid_2]) +
- resolve_mr(other_project, iids: [other_iid])
+ results = batch_sync(max_queries: queries_per_project * 2) do
+ a = resolve_mr(project, iids: [iid_1])
+ b = resolve_mr(project, iids: [iid_2])
+ c = resolve_mr(other_project, iids: [other_iid])
+
+ [a, b, c].flat_map(&:to_a)
end
- expect(result).to contain_exactly(merge_request_1, merge_request_2, other_merge_request)
+ expect(results).to contain_exactly(merge_request_1, merge_request_2, other_merge_request)
end
it 'resolves an unknown iid to be empty' do
@@ -134,9 +147,9 @@ RSpec.describe Resolvers::MergeRequestsResolver do
it 'takes more than one argument' do
mrs = [merge_request_3, merge_request_4]
branches = mrs.map(&:target_branch)
- result = resolve_mr(project, target_branches: branches )
+ result = resolve_mr(project, target_branches: branches)
- expect(result.compact).to match_array(mrs)
+ expect(result).to match_array(mrs)
end
end
@@ -173,7 +186,7 @@ RSpec.describe Resolvers::MergeRequestsResolver do
it 'returns merge requests merged between the given period' do
result = resolve_mr(project, merged_after: 20.days.ago, merged_before: 5.days.ago)
- expect(result).to eq([merge_request_1])
+ expect(result).to contain_exactly(merge_request_1)
end
it 'does not return anything' do
@@ -187,7 +200,7 @@ RSpec.describe Resolvers::MergeRequestsResolver do
it 'filters merge requests by milestone title' do
result = resolve_mr(project, milestone_title: milestone.title)
- expect(result).to eq([merge_request_with_milestone])
+ expect(result).to contain_exactly(merge_request_with_milestone)
end
it 'does not find anything' do
@@ -203,18 +216,29 @@ RSpec.describe Resolvers::MergeRequestsResolver do
result = resolve_mr(project, source_branches: [merge_request_4.source_branch], state: 'locked')
- expect(result.compact).to contain_exactly(merge_request_4)
+ expect(result).to contain_exactly(merge_request_4)
end
end
describe 'sorting' do
+ let(:mrs) do
+ [
+ merge_request_with_milestone, merge_request_6, merge_request_5, merge_request_4,
+ merge_request_3, merge_request_2, merge_request_1
+ ]
+ end
+
context 'when sorting by created' do
it 'sorts merge requests ascending' do
- expect(resolve_mr(project, sort: 'created_asc')).to eq [merge_request_1, merge_request_2, merge_request_3, merge_request_4, merge_request_5, merge_request_6, merge_request_with_milestone]
+ expect(resolve_mr(project, sort: 'created_asc'))
+ .to match_array(mrs)
+ .and be_sorted(:created_at, :asc)
end
it 'sorts merge requests descending' do
- expect(resolve_mr(project, sort: 'created_desc')).to eq [merge_request_with_milestone, merge_request_6, merge_request_5, merge_request_4, merge_request_3, merge_request_2, merge_request_1]
+ expect(resolve_mr(project, sort: 'created_desc'))
+ .to match_array(mrs)
+ .and be_sorted(:created_at, :desc)
end
end
@@ -225,11 +249,19 @@ RSpec.describe Resolvers::MergeRequestsResolver do
end
it 'sorts merge requests ascending' do
- expect(resolve_mr(project, sort: :merged_at_asc)).to eq [merge_request_1, merge_request_3, merge_request_with_milestone, merge_request_6, merge_request_5, merge_request_4, merge_request_2]
+ expect(resolve_mr(project, sort: :merged_at_asc))
+ .to match_array(mrs)
+ .and be_sorted(->(mr) { [merged_at(mr), -mr.id] })
end
it 'sorts merge requests descending' do
- expect(resolve_mr(project, sort: :merged_at_desc)).to eq [merge_request_3, merge_request_1, merge_request_with_milestone, merge_request_6, merge_request_5, merge_request_4, merge_request_2]
+ expect(resolve_mr(project, sort: :merged_at_desc))
+ .to match_array(mrs)
+ .and be_sorted(->(mr) { [-merged_at(mr), -mr.id] })
+ end
+
+ def merged_at(mr)
+ nils_last(mr.metrics.merged_at)
end
context 'when label filter is given and the optimized_issuable_label_filter feature flag is off' do
diff --git a/spec/graphql/resolvers/package_details_resolver_spec.rb b/spec/graphql/resolvers/package_details_resolver_spec.rb
index 825b2aed40a..1bdc069b3bb 100644
--- a/spec/graphql/resolvers/package_details_resolver_spec.rb
+++ b/spec/graphql/resolvers/package_details_resolver_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Resolvers::PackageDetailsResolver do
include GraphqlHelpers
+ include ::Gitlab::Graphql::Laziness
let_it_be_with_reload(:project) { create(:project) }
let_it_be(:user) { project.owner }
@@ -11,10 +12,10 @@ RSpec.describe Resolvers::PackageDetailsResolver do
describe '#resolve' do
let(:args) do
- { id: package.to_global_id.to_s }
+ { id: global_id_of(package) }
end
- subject { resolve(described_class, ctx: { current_user: user }, args: args).sync }
+ subject { force(resolve(described_class, ctx: { current_user: user }, args: args)) }
it { is_expected.to eq(package) }
end
diff --git a/spec/graphql/resolvers/packages_resolver_spec.rb b/spec/graphql/resolvers/packages_resolver_spec.rb
index 9aec2c7e036..bc0588daf7f 100644
--- a/spec/graphql/resolvers/packages_resolver_spec.rb
+++ b/spec/graphql/resolvers/packages_resolver_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Resolvers::PackagesResolver do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, :public) }
let_it_be(:package) { create(:package, project: project) }
describe '#resolve' do
diff --git a/spec/graphql/resolvers/release_milestones_resolver_spec.rb b/spec/graphql/resolvers/release_milestones_resolver_spec.rb
index 5f66cba859d..f05069998d0 100644
--- a/spec/graphql/resolvers/release_milestones_resolver_spec.rb
+++ b/spec/graphql/resolvers/release_milestones_resolver_spec.rb
@@ -6,18 +6,19 @@ RSpec.describe Resolvers::ReleaseMilestonesResolver do
include GraphqlHelpers
let_it_be(:release) { create(:release, :with_milestones, milestones_count: 2) }
+ let_it_be(:current_user) { create(:user, developer_projects: [release.project]) }
let(:resolved) do
- resolve(described_class, obj: release)
+ resolve(described_class, obj: release, ctx: { current_user: current_user })
end
describe '#resolve' do
- it "returns an OffsetActiveRecordRelationConnection" do
- expect(resolved).to be_a(::Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection)
+ it "uses offset-pagination" do
+ expect(resolved).to be_a(::Gitlab::Graphql::Pagination::OffsetPaginatedRelation)
end
it "includes the release's milestones in the returned OffsetActiveRecordRelationConnection" do
- expect(resolved.items).to eq(release.milestones.order_by_dates_and_title)
+ expect(resolved.to_a).to eq(release.milestones.order_by_dates_and_title)
end
end
end
diff --git a/spec/graphql/resolvers/release_resolver_spec.rb b/spec/graphql/resolvers/release_resolver_spec.rb
index 04765fc68e9..782c9604f15 100644
--- a/spec/graphql/resolvers/release_resolver_spec.rb
+++ b/spec/graphql/resolvers/release_resolver_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe Resolvers::ReleaseResolver do
let(:args) { {} }
it 'raises an error' do
- expect { resolve_release }.to raise_error(ArgumentError, "missing keyword: :tag_name")
+ expect { resolve_release }.to raise_error(ArgumentError)
end
end
end
diff --git a/spec/graphql/resolvers/terraform/states_resolver_spec.rb b/spec/graphql/resolvers/terraform/states_resolver_spec.rb
index 64b515528cd..91d48cd782b 100644
--- a/spec/graphql/resolvers/terraform/states_resolver_spec.rb
+++ b/spec/graphql/resolvers/terraform/states_resolver_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Resolvers::Terraform::StatesResolver do
include GraphqlHelpers
- it { expect(described_class.type).to eq(Types::Terraform::StateType) }
+ it { expect(described_class).to have_nullable_graphql_type(Types::Terraform::StateType.connection_type) }
it { expect(described_class.null).to be_truthy }
describe '#resolve' do
@@ -31,3 +31,21 @@ RSpec.describe Resolvers::Terraform::StatesResolver do
end
end
end
+
+RSpec.describe Resolvers::Terraform::StatesResolver.single do
+ it { expect(described_class).to be < Resolvers::Terraform::StatesResolver }
+
+ describe 'arguments' do
+ subject { described_class.arguments[argument] }
+
+ describe 'name' do
+ let(:argument) { 'name' }
+
+ it do
+ expect(subject).to be_present
+ expect(subject.type.to_s).to eq('String!')
+ expect(subject.description).to be_present
+ end
+ end
+ end
+end
diff --git a/spec/graphql/types/ci/pipeline_type_spec.rb b/spec/graphql/types/ci/pipeline_type_spec.rb
index d435e337ad7..2a1e030480d 100644
--- a/spec/graphql/types/ci/pipeline_type_spec.rb
+++ b/spec/graphql/types/ci/pipeline_type_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Types::Ci::PipelineType do
id iid sha before_sha status detailed_status config_source duration
coverage created_at updated_at started_at finished_at committed_at
stages user retryable cancelable jobs source_job downstream
- upstream path project active user_permissions
+ upstream path project active user_permissions warnings
]
if Gitlab.ee?
diff --git a/spec/graphql/types/ci_configuration/sast/analyzers_entity_input_type_spec.rb b/spec/graphql/types/ci_configuration/sast/analyzers_entity_input_type_spec.rb
new file mode 100644
index 00000000000..ac18f8d53a1
--- /dev/null
+++ b/spec/graphql/types/ci_configuration/sast/analyzers_entity_input_type_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Types::CiConfiguration::Sast::AnalyzersEntityInputType do
+ it { expect(described_class.graphql_name).to eq('SastCiConfigurationAnalyzersEntityInput') }
+
+ it { expect(described_class.arguments.keys).to match_array(%w[enabled name variables]) }
+end
diff --git a/spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb b/spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb
new file mode 100644
index 00000000000..27f6703b429
--- /dev/null
+++ b/spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['SastCiConfigurationAnalyzersEntity'] do
+ let(:fields) { %i[name label enabled description variables] }
+
+ it { expect(described_class.graphql_name).to eq('SastCiConfigurationAnalyzersEntity') }
+
+ it { expect(described_class).to have_graphql_fields(fields) }
+end
diff --git a/spec/graphql/types/ci_configuration/sast/entity_input_type_spec.rb b/spec/graphql/types/ci_configuration/sast/entity_input_type_spec.rb
new file mode 100644
index 00000000000..cefcf64164a
--- /dev/null
+++ b/spec/graphql/types/ci_configuration/sast/entity_input_type_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Types::CiConfiguration::Sast::EntityInputType do
+ it { expect(described_class.graphql_name).to eq('SastCiConfigurationEntityInput') }
+
+ it { expect(described_class.arguments.keys).to match_array(%w[field defaultValue value]) }
+end
diff --git a/spec/graphql/types/ci_configuration/sast/entity_type_spec.rb b/spec/graphql/types/ci_configuration/sast/entity_type_spec.rb
new file mode 100644
index 00000000000..762798670a5
--- /dev/null
+++ b/spec/graphql/types/ci_configuration/sast/entity_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['SastCiConfigurationEntity'] do
+ let(:fields) { %i[field label description type options default_value value size] }
+
+ it { expect(described_class.graphql_name).to eq('SastCiConfigurationEntity') }
+
+ it { expect(described_class).to have_graphql_fields(fields) }
+end
diff --git a/spec/graphql/types/ci_configuration/sast/input_type_spec.rb b/spec/graphql/types/ci_configuration/sast/input_type_spec.rb
new file mode 100644
index 00000000000..9f9d1dea98f
--- /dev/null
+++ b/spec/graphql/types/ci_configuration/sast/input_type_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Types::CiConfiguration::Sast::InputType do
+ it { expect(described_class.graphql_name).to eq('SastCiConfigurationInput') }
+
+ it { expect(described_class.arguments.keys).to match_array(%w[global pipeline analyzers]) }
+end
diff --git a/spec/graphql/types/ci_configuration/sast/options_entity_spec.rb b/spec/graphql/types/ci_configuration/sast/options_entity_spec.rb
new file mode 100644
index 00000000000..c60c8b9c84a
--- /dev/null
+++ b/spec/graphql/types/ci_configuration/sast/options_entity_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['SastCiConfigurationOptionsEntity'] do
+ let(:fields) { %i[label value] }
+
+ it { expect(described_class.graphql_name).to eq('SastCiConfigurationOptionsEntity') }
+
+ it { expect(described_class).to have_graphql_fields(fields) }
+end
diff --git a/spec/graphql/types/ci_configuration/sast/type_spec.rb b/spec/graphql/types/ci_configuration/sast/type_spec.rb
new file mode 100644
index 00000000000..e7a8cd436e4
--- /dev/null
+++ b/spec/graphql/types/ci_configuration/sast/type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['SastCiConfiguration'] do
+ let(:fields) { %i[global pipeline analyzers] }
+
+ it { expect(described_class.graphql_name).to eq('SastCiConfiguration') }
+
+ it { expect(described_class).to have_graphql_fields(fields) }
+end
diff --git a/spec/graphql/types/ci_configuration/sast/ui_component_size_enum_spec.rb b/spec/graphql/types/ci_configuration/sast/ui_component_size_enum_spec.rb
new file mode 100644
index 00000000000..23184df809f
--- /dev/null
+++ b/spec/graphql/types/ci_configuration/sast/ui_component_size_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::CiConfiguration::Sast::UiComponentSizeEnum do
+ specify { expect(described_class.graphql_name).to eq('SastUiComponentSize') }
+
+ it 'exposes all sizes of ui components' do
+ expect(described_class.values.keys).to include(*%w[SMALL MEDIUM LARGE])
+ end
+end
diff --git a/spec/graphql/types/container_repository_sort_enum_spec.rb b/spec/graphql/types/container_repository_sort_enum_spec.rb
new file mode 100644
index 00000000000..eb936c6d3a1
--- /dev/null
+++ b/spec/graphql/types/container_repository_sort_enum_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['ContainerRepositorySort'] do
+ specify { expect(described_class.graphql_name).to eq('ContainerRepositorySort') }
+
+ it_behaves_like 'common sort values'
+
+ it 'exposes all the existing issue sort values' do
+ expect(described_class.values.keys).to include(
+ *%w[NAME_ASC NAME_DESC]
+ )
+ end
+end
diff --git a/spec/graphql/types/event_type_spec.rb b/spec/graphql/types/event_type_spec.rb
new file mode 100644
index 00000000000..10c3b5e18ca
--- /dev/null
+++ b/spec/graphql/types/event_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::EventType do
+ specify { expect(described_class.graphql_name).to eq('Event') }
+
+ specify { expect(described_class).to require_graphql_authorizations(:read_event) }
+
+ specify { expect(described_class).to have_graphql_fields(:id, :author, :action, :created_at, :updated_at) }
+end
diff --git a/spec/graphql/types/eventable_type_spec.rb b/spec/graphql/types/eventable_type_spec.rb
new file mode 100644
index 00000000000..c1c7bf6d65a
--- /dev/null
+++ b/spec/graphql/types/eventable_type_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::EventableType do
+ it 'exposes events field' do
+ expect(described_class).to have_graphql_fields(:events)
+ end
+end
diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb
index de19e8b602a..bba702ba3e9 100644
--- a/spec/graphql/types/group_type_spec.rb
+++ b/spec/graphql/types/group_type_spec.rb
@@ -38,5 +38,7 @@ RSpec.describe GitlabSchema.types['Group'] do
it { is_expected.to have_graphql_resolver(Resolvers::GroupMembersResolver) }
end
- it_behaves_like 'a GraphQL type with labels'
+ it_behaves_like 'a GraphQL type with labels' do
+ let(:labels_resolver_arguments) { [:search_term, :includeAncestorGroups, :includeDescendantGroups, :onlyGroupLabels] }
+ end
end
diff --git a/spec/graphql/types/merge_request_state_event_enum_spec.rb b/spec/graphql/types/merge_request_state_event_enum_spec.rb
new file mode 100644
index 00000000000..94214b29755
--- /dev/null
+++ b/spec/graphql/types/merge_request_state_event_enum_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['MergeRequestNewState'] do
+ it 'has the appropriate values' do
+ expect(described_class.values).to contain_exactly(
+ ['OPEN', have_attributes(value: 'reopen')],
+ ['CLOSED', have_attributes(value: 'close')]
+ )
+ end
+end
diff --git a/spec/graphql/types/packages/composer/details_type_spec.rb b/spec/graphql/types/packages/composer/details_type_spec.rb
deleted file mode 100644
index 2e4cb965ded..00000000000
--- a/spec/graphql/types/packages/composer/details_type_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe GitlabSchema.types['PackageComposerDetails'] do
- it { expect(described_class.graphql_name).to eq('PackageComposerDetails') }
-
- it 'includes all the package fields' do
- expected_fields = %w[
- id name version created_at updated_at package_type tags project pipelines versions
- ]
-
- expect(described_class).to include_graphql_fields(*expected_fields)
- end
-
- it 'includes composer specific files' do
- expected_fields = %w[
- composer_metadatum
- ]
-
- expect(described_class).to include_graphql_fields(*expected_fields)
- end
-end
diff --git a/spec/graphql/types/packages/composer/metadatum_type_spec.rb b/spec/graphql/types/packages/composer/metadatum_type_spec.rb
index 0f47d8f1812..a950c10a41d 100644
--- a/spec/graphql/types/packages/composer/metadatum_type_spec.rb
+++ b/spec/graphql/types/packages/composer/metadatum_type_spec.rb
@@ -2,9 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['PackageComposerMetadatumType'] do
- it { expect(described_class.graphql_name).to eq('PackageComposerMetadatumType') }
-
+RSpec.describe GitlabSchema.types['ComposerMetadata'] do
it 'includes composer metadatum fields' do
expected_fields = %w[
target_sha composer_json
diff --git a/spec/graphql/types/packages/package_type_enum_spec.rb b/spec/graphql/types/packages/package_type_enum_spec.rb
index 407d5786f65..ccd91485e4b 100644
--- a/spec/graphql/types/packages/package_type_enum_spec.rb
+++ b/spec/graphql/types/packages/package_type_enum_spec.rb
@@ -4,6 +4,6 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['PackageTypeEnum'] do
it 'exposes all package types' do
- expect(described_class.values.keys).to contain_exactly(*%w[MAVEN NPM CONAN NUGET PYPI COMPOSER GENERIC GOLANG DEBIAN])
+ expect(described_class.values.keys).to contain_exactly(*%w[MAVEN NPM CONAN NUGET PYPI COMPOSER GENERIC GOLANG DEBIAN RUBYGEMS])
end
end
diff --git a/spec/graphql/types/packages/package_type_spec.rb b/spec/graphql/types/packages/package_type_spec.rb
index 7003a4d4d07..43289a019b3 100644
--- a/spec/graphql/types/packages/package_type_spec.rb
+++ b/spec/graphql/types/packages/package_type_spec.rb
@@ -3,11 +3,12 @@
require 'spec_helper'
RSpec.describe GitlabSchema.types['Package'] do
- it { expect(described_class.graphql_name).to eq('Package') }
-
it 'includes all the package fields' do
expected_fields = %w[
- id name version created_at updated_at package_type tags project pipelines versions
+ id name version package_type
+ created_at updated_at
+ project
+ tags pipelines versions
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/packages/package_without_versions_type_spec.rb b/spec/graphql/types/packages/package_without_versions_type_spec.rb
new file mode 100644
index 00000000000..faa79e588d5
--- /dev/null
+++ b/spec/graphql/types/packages/package_without_versions_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['PackageWithoutVersions'] do
+ it 'includes all the package fields' do
+ expected_fields = %w[
+ id name version created_at updated_at package_type tags project pipelines
+ ]
+
+ expect(described_class).to include_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 9d0d7a3918a..9579ef8b99b 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -31,12 +31,171 @@ RSpec.describe GitlabSchema.types['Project'] do
container_expiration_policy service_desk_enabled service_desk_address
issue_status_counts terraform_states alert_management_integrations
container_repositories container_repositories_count
- pipeline_analytics squash_read_only
+ pipeline_analytics squash_read_only sast_ci_configuration
]
expect(described_class).to include_graphql_fields(*expected_fields)
end
+ describe 'sast_ci_configuration' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ before do
+ stub_licensed_features(security_dashboard: true)
+ project.add_developer(user)
+ allow(project.repository).to receive(:blob_data_at).and_return(gitlab_ci_yml_content)
+ end
+
+ include_context 'read ci configuration for sast enabled project'
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ sastCiConfiguration {
+ global {
+ nodes {
+ type
+ options {
+ nodes {
+ label
+ value
+ }
+ }
+ field
+ label
+ defaultValue
+ value
+ size
+ }
+ }
+ pipeline {
+ nodes {
+ type
+ options {
+ nodes {
+ label
+ value
+ }
+ }
+ field
+ label
+ defaultValue
+ value
+ size
+ }
+ }
+ analyzers {
+ nodes {
+ name
+ label
+ enabled
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
+
+ it "returns the project's sast configuration for global variables" do
+ secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes').first
+ expect(secure_analyzers_prefix['type']).to eq('string')
+ expect(secure_analyzers_prefix['field']).to eq('SECURE_ANALYZERS_PREFIX')
+ expect(secure_analyzers_prefix['label']).to eq('Image prefix')
+ expect(secure_analyzers_prefix['defaultValue']).to eq('registry.gitlab.com/gitlab-org/security-products/analyzers')
+ expect(secure_analyzers_prefix['value']).to eq('registry.gitlab.com/gitlab-org/security-products/analyzers')
+ expect(secure_analyzers_prefix['size']).to eq('LARGE')
+ expect(secure_analyzers_prefix['options']).to be_nil
+ end
+
+ it "returns the project's sast configuration for pipeline variables" do
+ pipeline_stage = subject.dig('data', 'project', 'sastCiConfiguration', 'pipeline', 'nodes').first
+ expect(pipeline_stage['type']).to eq('string')
+ expect(pipeline_stage['field']).to eq('stage')
+ expect(pipeline_stage['label']).to eq('Stage')
+ expect(pipeline_stage['defaultValue']).to eq('test')
+ expect(pipeline_stage['value']).to eq('test')
+ expect(pipeline_stage['size']).to eq('MEDIUM')
+ end
+
+ it "returns the project's sast configuration for analyzer variables" do
+ analyzer = subject.dig('data', 'project', 'sastCiConfiguration', 'analyzers', 'nodes').first
+ expect(analyzer['name']).to eq('brakeman')
+ expect(analyzer['label']).to eq('Brakeman')
+ expect(analyzer['enabled']).to eq(true)
+ end
+
+ context "with guest user" do
+ before do
+ project.add_guest(user)
+ end
+
+ context 'when project is private' do
+ let(:project) { create(:project, :private, :repository) }
+
+ it "returns no configuration" do
+ secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration')
+ expect(secure_analyzers_prefix).to be_nil
+ end
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :public, :repository) }
+
+ context 'when repository is accessible by everyone' do
+ it "returns the project's sast configuration for global variables" do
+ secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes').first
+
+ expect(secure_analyzers_prefix['type']).to eq('string')
+ expect(secure_analyzers_prefix['field']).to eq('SECURE_ANALYZERS_PREFIX')
+ end
+ end
+ end
+ end
+
+ context "with non-member user" do
+ before do
+ project.team.truncate
+ end
+
+ context 'when project is private' do
+ let(:project) { create(:project, :private, :repository) }
+
+ it "returns no configuration" do
+ secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration')
+ expect(secure_analyzers_prefix).to be_nil
+ end
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :public, :repository) }
+
+ context 'when repository is accessible by everyone' do
+ it "returns the project's sast configuration for global variables" do
+ secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes').first
+ expect(secure_analyzers_prefix['type']).to eq('string')
+ expect(secure_analyzers_prefix['field']).to eq('SECURE_ANALYZERS_PREFIX')
+ end
+ end
+
+ context 'when repository is accessible only by team members' do
+ it "returns no configuration" do
+ project.project_feature.update!(merge_requests_access_level: ProjectFeature::DISABLED,
+ builds_access_level: ProjectFeature::DISABLED,
+ repository_access_level: ProjectFeature::PRIVATE)
+
+ secure_analyzers_prefix = subject.dig('data', 'project', 'sastCiConfiguration')
+ expect(secure_analyzers_prefix).to be_nil
+ end
+ end
+ end
+ end
+ end
+
describe 'issue field' do
subject { described_class.fields['issue'] }
@@ -159,6 +318,13 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_type(Types::ContainerExpirationPolicyType) }
end
+ describe 'terraform state field' do
+ subject { described_class.fields['terraformState'] }
+
+ it { is_expected.to have_graphql_type(Types::Terraform::StateType) }
+ it { is_expected.to have_graphql_resolver(Resolvers::Terraform::StatesResolver.single) }
+ end
+
describe 'terraform states field' do
subject { described_class.fields['terraformStates'] }
@@ -166,7 +332,9 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_resolver(Resolvers::Terraform::StatesResolver) }
end
- it_behaves_like 'a GraphQL type with labels'
+ it_behaves_like 'a GraphQL type with labels' do
+ let(:labels_resolver_arguments) { [:search_term, :includeAncestorGroups] }
+ end
describe 'jira_imports' do
subject { resolve_field(:jira_imports, project) }
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index 3e716865e56..fea0a3bd37e 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -95,9 +95,9 @@ RSpec.describe GitlabSchema.types['Query'] do
it { is_expected.to have_graphql_type(Types::ContainerRepositoryDetailsType) }
end
- describe 'package_composer_details field' do
- subject { described_class.fields['packageComposerDetails'] }
+ describe 'package field' do
+ subject { described_class.fields['package'] }
- it { is_expected.to have_graphql_type(Types::Packages::Composer::DetailsType) }
+ it { is_expected.to have_graphql_type(Types::Packages::PackageType) }
end
end
diff --git a/spec/graphql/types/user_type_spec.rb b/spec/graphql/types/user_type_spec.rb
index 0eff33bb25b..5b3662383d8 100644
--- a/spec/graphql/types/user_type_spec.rb
+++ b/spec/graphql/types/user_type_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe GitlabSchema.types['User'] do
it 'has the expected fields' do
expected_fields = %w[
id
+ bot
user_permissions
snippets
name