diff options
Diffstat (limited to 'spec/requests/api/graphql')
30 files changed, 474 insertions, 110 deletions
diff --git a/spec/requests/api/graphql/ci/config_spec.rb b/spec/requests/api/graphql/ci/config_spec.rb index 8154f132430..5f43a0806f3 100644 --- a/spec/requests/api/graphql/ci/config_spec.rb +++ b/spec/requests/api/graphql/ci/config_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' RSpec.describe 'Query.ciConfig', feature_category: :continuous_integration do include GraphqlHelpers include StubRequests + include RepoHelpers subject(:post_graphql_query) { post_graphql(query, current_user: user) } @@ -245,17 +246,22 @@ RSpec.describe 'Query.ciConfig', feature_category: :continuous_integration do ) end - before do - allow_next_instance_of(Repository) do |repository| - allow(repository).to receive(:blob_data_at).with(an_instance_of(String), 'other_file.yml') do - YAML.dump( - build: { - script: 'build' - } - ) - end + let(:project_files) do + { + 'other_file.yml' => <<~YAML + build: + script: build + YAML + } + end + + around do |example| + create_and_delete_files(project, project_files) do + example.run end + end + before do post_graphql_query end @@ -370,25 +376,33 @@ RSpec.describe 'Query.ciConfig', feature_category: :continuous_integration do ) end - before do - allow_next_instance_of(Repository) do |repository| - allow(repository).to receive(:blob_data_at).with(an_instance_of(String), 'other_file.yml') do - YAML.dump( - build: { - script: 'build' - } - ) - end + let(:project_files) do + { + 'other_file.yml' => <<~YAML + build: + script: build + YAML + } + end - allow(repository).to receive(:blob_data_at).with(an_instance_of(String), 'other_project_file.yml') do - YAML.dump( - other_project_test: { - script: 'other_project_test' - } - ) + let(:other_project_files) do + { + 'other_project_file.yml' => <<~YAML + other_project_test: + script: other_project_test + YAML + } + end + + around do |example| + create_and_delete_files(project, project_files) do + create_and_delete_files(other_project, other_project_files) do + example.run end end + end + before do stub_full_request('https://gitlab.com/gitlab-org/gitlab/raw/1234/.hello.yml').to_return(body: remote_file_content) post_graphql_query diff --git a/spec/requests/api/graphql/ci/jobs_spec.rb b/spec/requests/api/graphql/ci/jobs_spec.rb index 7a1dc614dcf..131cdb77107 100644 --- a/spec/requests/api/graphql/ci/jobs_spec.rb +++ b/spec/requests/api/graphql/ci/jobs_spec.rb @@ -88,10 +88,10 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati build_stage = create(:ci_stage, position: 2, name: 'build', project: project, pipeline: pipeline) test_stage = create(:ci_stage, position: 3, name: 'test', project: project, pipeline: pipeline) - create(:ci_build, pipeline: pipeline, name: 'docker 1 2', scheduling_type: :stage, stage: build_stage, stage_idx: build_stage.position) - create(:ci_build, pipeline: pipeline, name: 'docker 2 2', stage: build_stage, stage_idx: build_stage.position, scheduling_type: :dag) - create(:ci_build, pipeline: pipeline, name: 'rspec 1 2', scheduling_type: :stage, stage: test_stage, stage_idx: test_stage.position) - test_job = create(:ci_build, pipeline: pipeline, name: 'rspec 2 2', scheduling_type: :dag, stage: test_stage, stage_idx: test_stage.position) + create(:ci_build, pipeline: pipeline, name: 'docker 1 2', scheduling_type: :stage, ci_stage: build_stage, stage_idx: build_stage.position) + create(:ci_build, pipeline: pipeline, name: 'docker 2 2', ci_stage: build_stage, stage_idx: build_stage.position, scheduling_type: :dag) + create(:ci_build, pipeline: pipeline, name: 'rspec 1 2', scheduling_type: :stage, ci_stage: test_stage, stage_idx: test_stage.position) + test_job = create(:ci_build, pipeline: pipeline, name: 'rspec 2 2', scheduling_type: :dag, ci_stage: test_stage, stage_idx: test_stage.position) create(:ci_build_need, build: test_job, name: 'my test job') end diff --git a/spec/requests/api/graphql/group/merge_requests_spec.rb b/spec/requests/api/graphql/group/merge_requests_spec.rb index 6976685ecc0..adaee3031a9 100644 --- a/spec/requests/api/graphql/group/merge_requests_spec.rb +++ b/spec/requests/api/graphql/group/merge_requests_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' # Based on ee/spec/requests/api/epics_spec.rb # Should follow closely in order to ensure all situations are covered -RSpec.describe 'Query.group.mergeRequests', feature_category: :code_review do +RSpec.describe 'Query.group.mergeRequests', feature_category: :code_review_workflow do include GraphqlHelpers let_it_be(:group) { create(:group) } diff --git a/spec/requests/api/graphql/group_query_spec.rb b/spec/requests/api/graphql/group_query_spec.rb index bc288c0a98b..ce5816999a6 100644 --- a/spec/requests/api/graphql/group_query_spec.rb +++ b/spec/requests/api/graphql/group_query_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' # Based on spec/requests/api/groups_spec.rb # Should follow closely in order to ensure all situations are covered -RSpec.describe 'getting group information', feature_category: :subgroups do +RSpec.describe 'getting group information', :with_license, feature_category: :subgroups do include GraphqlHelpers include UploadHelpers diff --git a/spec/requests/api/graphql/issues_spec.rb b/spec/requests/api/graphql/issues_spec.rb index ba6f8ec2cab..e67c92d6c33 100644 --- a/spec/requests/api/graphql/issues_spec.rb +++ b/spec/requests/api/graphql/issues_spec.rb @@ -2,11 +2,13 @@ require 'spec_helper' +# rubocop:disable RSpec/MultipleMemoizedHelpers RSpec.describe 'getting an issue list at root level', feature_category: :team_planning do include GraphqlHelpers let_it_be(:developer) { create(:user) } let_it_be(:reporter) { create(:user) } + let_it_be(:current_user) { developer } let_it_be(:group1) { create(:group).tap { |group| group.add_developer(developer) } } let_it_be(:group2) { create(:group).tap { |group| group.add_developer(developer) } } let_it_be(:project_a) { create(:project, :repository, :public, group: group1) } @@ -82,9 +84,11 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl end let_it_be(:issues, reload: true) { [issue_a, issue_b, issue_c, issue_d, issue_e] } + # we need to always provide at least one filter to the query so it doesn't fail + let_it_be(:base_params) { { iids: issues.map { |issue| issue.iid.to_s } } } let(:issue_filter_params) { {} } - let(:current_user) { developer } + let(:all_query_params) { base_params.merge(**issue_filter_params) } let(:fields) do <<~QUERY nodes { id } @@ -95,6 +99,16 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl group2.add_reporter(reporter) end + shared_examples 'query that requires at least one filter' do + it 'requires at least one filter to be provided to the query' do + post_graphql(query, current_user: developer) + + expect(graphql_errors).to contain_exactly( + hash_including('message' => _('You must provide at least one filter argument for this query')) + ) + end + end + context 'when the root_level_issues_query feature flag is disabled' do before do stub_feature_flags(root_level_issues_query: false) @@ -107,20 +121,31 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl end end + context 'when no filters are provided' do + let(:all_query_params) { {} } + + it_behaves_like 'query that requires at least one filter' + end + + context 'when only non filter arguments are provided' do + let(:all_query_params) { { sort: :SEVERITY_ASC } } + + it_behaves_like 'query that requires at least one filter' + end + # All new specs should be added to the shared example if the change also # affects the `issues` query at the root level of the API. # Shared example also used in spec/requests/api/graphql/project/issues_spec.rb it_behaves_like 'graphql issue list request spec' do let_it_be(:external_user) { create(:user) } + let_it_be(:another_user) { reporter } let(:public_projects) { [project_a, project_c] } - let(:another_user) { reporter } let(:issue_nodes_path) { %w[issues nodes] } # filters let(:expected_negated_assignee_issues) { [issue_b, issue_c, issue_d, issue_e] } - let(:expected_unioned_assignee_issues) { [issue_a, issue_c] } let(:voted_issues) { [issue_a, issue_c] } let(:no_award_issues) { [issue_b, issue_d, issue_e] } let(:locked_discussion_issues) { [issue_b, issue_d] } @@ -148,9 +173,6 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl let(:same_project_issue2) { issue_e } before_all do - issue_a.assignee_ids = developer.id - issue_c.assignee_ids = reporter.id - create(:award_emoji, :upvote, user: developer, awardable: issue_a) create(:award_emoji, :upvote, user: developer, awardable: issue_c) end @@ -158,7 +180,7 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl def pagination_query(params) graphql_query_for( :issues, - params, + base_params.merge(**params.to_h), "#{page_info} nodes { id }" ) end @@ -177,6 +199,32 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl end end + context 'with rate limiting' do + it_behaves_like 'rate limited endpoint', rate_limit_key: :search_rate_limit, graphql: true do + let_it_be(:current_user) { developer } + + let(:error_message) do + 'This endpoint has been requested with the search argument too many times. Try again later.' + end + + def request + post_graphql(query({ search: 'test' }), current_user: developer) + end + end + + it_behaves_like 'rate limited endpoint', rate_limit_key: :search_rate_limit_unauthenticated, graphql: true do + let_it_be(:current_user) { nil } + + let(:error_message) do + 'This endpoint has been requested with the search argument too many times. Try again later.' + end + + def request + post_graphql(query({ search: 'test' })) + end + end + end + def execute_query post_query end @@ -185,7 +233,7 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl post_graphql(query, current_user: request_user) end - def query(params = issue_filter_params) + def query(params = all_query_params) graphql_query_for( :issues, params, @@ -193,3 +241,4 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl ) end end +# rubocop:enable RSpec/MultipleMemoizedHelpers diff --git a/spec/requests/api/graphql/merge_request/merge_request_spec.rb b/spec/requests/api/graphql/merge_request/merge_request_spec.rb index 213697bacc1..02ea7bac920 100644 --- a/spec/requests/api/graphql/merge_request/merge_request_spec.rb +++ b/spec/requests/api/graphql/merge_request/merge_request_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Query.merge_request(id)', feature_category: :code_review do +RSpec.describe 'Query.merge_request(id)', feature_category: :code_review_workflow do include GraphqlHelpers let_it_be(:project) { create(:project, :empty_repo) } diff --git a/spec/requests/api/graphql/mutations/achievements/create_spec.rb b/spec/requests/api/graphql/mutations/achievements/create_spec.rb new file mode 100644 index 00000000000..1713f050540 --- /dev/null +++ b/spec/requests/api/graphql/mutations/achievements/create_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Achievements::Create, feature_category: :users do + include GraphqlHelpers + include WorkhorseHelpers + + let_it_be(:developer) { create(:user) } + let_it_be(:maintainer) { create(:user) } + let_it_be(:group) { create(:group) } + + let(:mutation) { graphql_mutation(:achievements_create, params) } + let(:name) { 'Name' } + let(:description) { 'Description' } + let(:revokeable) { false } + let(:avatar) { fixture_file_upload("spec/fixtures/dk.png") } + let(:params) do + { + namespace_id: group.to_global_id, + name: name, + avatar: avatar, + description: description, + revokeable: revokeable + } + end + + subject { post_graphql_mutation_with_uploads(mutation, current_user: current_user) } + + def mutation_response + graphql_mutation_response(:achievements_create) + end + + before_all do + group.add_developer(developer) + group.add_maintainer(maintainer) + end + + context 'when the user does not have permission' do + let(:current_user) { developer } + let(:avatar) {} + + it_behaves_like 'a mutation that returns a top-level access error' + + it 'does not create an achievement' do + expect { subject }.not_to change { Achievements::Achievement.count } + end + end + + context 'when the user has permission' do + let(:current_user) { maintainer } + + context 'when the params are invalid' do + let(:name) {} + + it 'returns the validation error' do + subject + + expect(graphql_errors.to_s).to include('provided invalid value for name (Expected value to not be null)') + end + end + + it 'creates an achievement' do + expect { subject }.to change { Achievements::Achievement.count }.by(1) + end + + it 'returns the new achievement' do + subject + + expect(graphql_data_at(:achievements_create, :achievement)).to match a_hash_including( + 'name' => name, + 'namespace' => a_hash_including('id' => group.to_global_id.to_s), + 'description' => description, + 'revokeable' => revokeable + ) + end + end +end diff --git a/spec/requests/api/graphql/mutations/ci/job_play_spec.rb b/spec/requests/api/graphql/mutations/ci/job_play_spec.rb index 014a5e0f1c7..9ba80e51dee 100644 --- a/spec/requests/api/graphql/mutations/ci/job_play_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/job_play_spec.rb @@ -8,17 +8,25 @@ RSpec.describe 'JobPlay', feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) } - let_it_be(:job) { create(:ci_build, pipeline: pipeline, name: 'build') } + let_it_be(:job) { create(:ci_build, :playable, pipeline: pipeline, name: 'build') } - let(:mutation) do - variables = { + let(:variables) do + { id: job.to_global_id.to_s } + end + + let(:mutation) do graphql_mutation(:job_play, variables, <<-QL errors job { id + manualVariables { + nodes { + key + } + } } QL ) @@ -43,4 +51,29 @@ RSpec.describe 'JobPlay', feature_category: :continuous_integration do expect(response).to have_gitlab_http_status(:success) expect(mutation_response['job']['id']).to eq(job_id) end + + context 'when given variables' do + let(:variables) do + { + id: job.to_global_id.to_s, + variables: [ + { key: 'MANUAL_VAR_1', value: 'test var' }, + { key: 'MANUAL_VAR_2', value: 'test var 2' } + ] + } + end + + it 'provides those variables to the job', :aggregated_errors do + expect_next_instance_of(Ci::PlayBuildService) do |instance| + expect(instance).to receive(:execute).with(an_instance_of(Ci::Build), variables[:variables]).and_call_original + end + + post_graphql_mutation(mutation, current_user: user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['job']['manualVariables']['nodes'].pluck('key')).to contain_exactly( + 'MANUAL_VAR_1', 'MANUAL_VAR_2' + ) + end + end end diff --git a/spec/requests/api/graphql/mutations/groups/update_spec.rb b/spec/requests/api/graphql/mutations/groups/update_spec.rb index ea3d42a4463..a9acc593229 100644 --- a/spec/requests/api/graphql/mutations/groups/update_spec.rb +++ b/spec/requests/api/graphql/mutations/groups/update_spec.rb @@ -11,7 +11,7 @@ RSpec.describe 'GroupUpdate', feature_category: :subgroups do let(:variables) do { full_path: group.full_path, - shared_runners_setting: 'DISABLED_WITH_OVERRIDE' + shared_runners_setting: 'DISABLED_AND_OVERRIDABLE' } end @@ -52,6 +52,23 @@ RSpec.describe 'GroupUpdate', feature_category: :subgroups do expect(group.reload.shared_runners_setting).to eq(variables[:shared_runners_setting].downcase) end + context 'when using DISABLED_WITH_OVERRIDE (deprecated)' do + let(:variables) do + { + full_path: group.full_path, + shared_runners_setting: 'DISABLED_WITH_OVERRIDE' + } + end + + it 'updates shared runners settings with disabled_and_overridable' do + post_graphql_mutation(mutation, current_user: user) + + expect(response).to have_gitlab_http_status(:success) + expect(graphql_errors).to be_nil + expect(group.reload.shared_runners_setting).to eq('disabled_and_overridable') + end + end + context 'when bad arguments are provided' do let(:variables) { { full_path: '', shared_runners_setting: 'INVALID' } } diff --git a/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb b/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb new file mode 100644 index 00000000000..ad70129a7bc --- /dev/null +++ b/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'GroupMemberBulkUpdate', feature_category: :subgroups do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:user1) { create(:user) } + let_it_be(:user2) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:group_member1) { create(:group_member, group: group, user: user1) } + let_it_be(:group_member2) { create(:group_member, group: group, user: user2) } + let_it_be(:mutation_name) { :group_member_bulk_update } + + let(:input) do + { + 'group_id' => group.to_global_id.to_s, + 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s], + 'access_level' => 'GUEST' + } + end + + let(:extra_params) { { expires_at: 10.days.from_now } } + let(:input_params) { input.merge(extra_params) } + let(:mutation) { graphql_mutation(mutation_name, input_params) } + let(:mutation_response) { graphql_mutation_response(mutation_name) } + + context 'when user is not logged-in' do + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'when user is not an owner' do + before do + group.add_maintainer(current_user) + end + + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'when user is an owner' do + before do + group.add_owner(current_user) + end + + shared_examples 'updates the user access role' do + specify do + post_graphql_mutation(mutation, current_user: current_user) + + new_access_levels = mutation_response['groupMembers'].map { |member| member['accessLevel']['integerValue'] } + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['errors']).to be_empty + expect(new_access_levels).to all(be Gitlab::Access::GUEST) + end + end + + it_behaves_like 'updates the user access role' + + context 'when inherited members are passed' do + let_it_be(:subgroup) { create(:group, parent: group) } + let_it_be(:subgroup_member) { create(:group_member, group: subgroup) } + + let(:input) do + { + 'group_id' => group.to_global_id.to_s, + 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s, subgroup_member.user.to_global_id.to_s], + 'access_level' => 'GUEST' + } + end + + it 'does not update the members' do + post_graphql_mutation(mutation, current_user: current_user) + + error = Mutations::Members::Groups::BulkUpdate::INVALID_MEMBERS_ERROR + expect(json_response['errors'].first['message']).to include(error) + end + end + + context 'when members count is more than the allowed limit' do + let(:max_members_update_limit) { 1 } + + before do + stub_const('Mutations::Members::Groups::BulkUpdate::MAX_MEMBERS_UPDATE_LIMIT', max_members_update_limit) + end + + it 'does not update the members' do + post_graphql_mutation(mutation, current_user: current_user) + + error = Mutations::Members::Groups::BulkUpdate::MAX_MEMBERS_UPDATE_ERROR + expect(json_response['errors'].first['message']).to include(error) + end + end + + context 'when the update service raises access denied error' do + before do + allow_next_instance_of(Members::UpdateService) do |instance| + allow(instance).to receive(:execute).and_raise(Gitlab::Access::AccessDeniedError) + end + end + + it 'does not update the members' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(mutation_response['groupMembers']).to be_nil + expect(mutation_response['errors']) + .to contain_exactly("Unable to update members, please check user permissions.") + end + end + + context 'when the update service returns an error message' do + before do + allow_next_instance_of(Members::UpdateService) do |instance| + error_result = { + message: 'Expires at cannot be a date in the past', + status: :error, + members: [group_member1] + } + allow(instance).to receive(:execute).and_return(error_result) + end + end + + it 'will pass through the error' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(mutation_response['groupMembers'].first['id']).to eq(group_member1.to_global_id.to_s) + expect(mutation_response['errors']).to contain_exactly('Expires at cannot be a date in the past') + end + end + end +end diff --git a/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb index c954fd50cc4..59f41c5e878 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Creation of a new merge request', feature_category: :code_review do +RSpec.describe 'Creation of a new merge request', feature_category: :code_review_workflow do include GraphqlHelpers let_it_be(:current_user) { create(:user) } diff --git a/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb index c41161eff2b..7a1b3982111 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Setting assignees of a merge request', feature_category: :code_review do +RSpec.describe 'Setting assignees of a merge request', feature_category: :code_review_workflow do include GraphqlHelpers let(:current_user) { create(:user) } diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb index 364d13291db..b5f2042c42a 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Setting assignees of a merge request', :assume_throttled, feature_category: :code_review do +RSpec.describe 'Setting assignees of a merge request', :assume_throttled, feature_category: :code_review_workflow do include GraphqlHelpers let_it_be(:project) { create(:project, :repository) } diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb index b48a94fbeb9..0c2e2975350 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Setting Draft status of a merge request', feature_category: :code_review do +RSpec.describe 'Setting Draft status of a merge request', feature_category: :code_review_workflow do include GraphqlHelpers let(:current_user) { create(:user) } diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb index d88982c508c..73a38adf723 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Setting locked status of a merge request', feature_category: :code_review do +RSpec.describe 'Setting locked status of a merge request', feature_category: :code_review_workflow do include GraphqlHelpers let(:current_user) { create(:user) } diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb index a0f0e45d1fc..3907ebad9ce 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Setting milestone of a merge request', feature_category: :code_review do +RSpec.describe 'Setting milestone of a merge request', feature_category: :code_review_workflow do include GraphqlHelpers let(:current_user) { create(:user) } diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb index a5be2a95c8b..fd87112be33 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Setting reviewers of a merge request', :assume_throttled, feature_category: :code_review do +RSpec.describe 'Setting reviewers of a merge request', :assume_throttled, feature_category: :code_review_workflow do include GraphqlHelpers let_it_be(:project) { create(:project, :repository) } diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb index daf1f529847..0e77b048646 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Setting subscribed status of a merge request', feature_category: :code_review do +RSpec.describe 'Setting subscribed status of a merge request', feature_category: :code_review_workflow do include GraphqlHelpers it_behaves_like 'a subscribable resource api' do diff --git a/spec/requests/api/graphql/mutations/work_items/update_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_spec.rb index 14cb18d04b8..b33a394d023 100644 --- a/spec/requests/api/graphql/mutations/work_items/update_spec.rb +++ b/spec/requests/api/graphql/mutations/work_items/update_spec.rb @@ -489,10 +489,10 @@ RSpec.describe 'Update a work item', feature_category: :team_planning do expect(response).to have_gitlab_http_status(:success) expect(widgets_response).to include( { - 'children' => { 'edges' => [ + 'children' => { 'edges' => match_array([ { 'node' => { 'id' => valid_child2.to_global_id.to_s } }, { 'node' => { 'id' => valid_child1.to_global_id.to_s } } - ] }, + ]) }, 'parent' => nil, 'type' => 'HIERARCHY' } diff --git a/spec/requests/api/graphql/project/branch_rules_spec.rb b/spec/requests/api/graphql/project/branch_rules_spec.rb index 7f6a66e2377..2ca37a49149 100644 --- a/spec/requests/api/graphql/project/branch_rules_spec.rb +++ b/spec/requests/api/graphql/project/branch_rules_spec.rb @@ -69,12 +69,6 @@ RSpec.describe 'getting list of branch rules for a project', feature_category: : before do create(:protected_branch, project: project) - allow_next_instance_of(Resolvers::ProjectResolver) do |resolver| - allow(resolver).to receive(:resolve) - .with(full_path: project.full_path) - .and_return(project) - end - allow(project.repository).to receive(:branch_names).and_call_original end it 'avoids N+1 queries', :use_sql_query_cache, :aggregate_failures do @@ -93,7 +87,6 @@ RSpec.describe 'getting list of branch rules for a project', feature_category: : end.not_to exceed_all_query_limit(control) expect_n_matching_branches_count_fields(3) - expect(project.repository).to have_received(:branch_names).at_least(2).times end def expect_n_matching_branches_count_fields(count) @@ -110,16 +103,16 @@ RSpec.describe 'getting list of branch rules for a project', feature_category: : let_it_be(:branch_name_b) { 'diff-*' } let_it_be(:branch_rules) { [branch_rule_a, branch_rule_b] } let_it_be(:branch_rule_a) do - create(:protected_branch, project: project, name: branch_name_a, id: 9999) + create(:protected_branch, project: project, name: branch_name_a) end let_it_be(:branch_rule_b) do - create(:protected_branch, project: project, name: branch_name_b, id: 10000) + create(:protected_branch, project: project, name: branch_name_b) end - # branchRules are returned in reverse order, newest first, sorted by primary_key. - let(:branch_rule_b_data) { branch_rules_data.dig(0, 'node') } + # branchRules are returned in alphabetical order let(:branch_rule_a_data) { branch_rules_data.dig(1, 'node') } + let(:branch_rule_b_data) { branch_rules_data.dig(0, 'node') } before do post_graphql(query, current_user: current_user, variables: variables) @@ -128,22 +121,28 @@ RSpec.describe 'getting list of branch rules for a project', feature_category: : it_behaves_like 'a working graphql query' it 'includes all fields', :use_sql_query_cache, :aggregate_failures do - expect(branch_rule_a_data['name']).to eq(branch_name_a) - expect(branch_rule_a_data['isDefault']).to be(true).or be(false) - expect(branch_rule_a_data['branchProtection']).to be_present - expect(branch_rule_a_data['matchingBranchesCount']).to eq(1) - expect(branch_rule_a_data['createdAt']).to be_present - expect(branch_rule_a_data['updatedAt']).to be_present + expect(branch_rule_a_data).to include( + 'name' => branch_name_a, + 'isDefault' => be_boolean, + 'isProtected' => true, + 'matchingBranchesCount' => 1, + 'branchProtection' => be_kind_of(Hash), + 'createdAt' => be_kind_of(String), + 'updatedAt' => be_kind_of(String) + ) wildcard_count = TestEnv::BRANCH_SHA.keys.count do |branch_name| branch_name.starts_with?('diff-') end - expect(branch_rule_b_data['name']).to eq(branch_name_b) - expect(branch_rule_b_data['isDefault']).to be(true).or be(false) - expect(branch_rule_b_data['branchProtection']).to be_present - expect(branch_rule_b_data['matchingBranchesCount']).to eq(wildcard_count) - expect(branch_rule_b_data['createdAt']).to be_present - expect(branch_rule_b_data['updatedAt']).to be_present + expect(branch_rule_b_data).to include( + 'name' => branch_name_b, + 'isDefault' => be_boolean, + 'isProtected' => true, + 'matchingBranchesCount' => wildcard_count, + 'branchProtection' => be_kind_of(Hash), + 'createdAt' => be_kind_of(String), + 'updatedAt' => be_kind_of(String) + ) end context 'when limiting the number of results' do diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb index ec5e3c6f0de..cc41795f770 100644 --- a/spec/requests/api/graphql/project/issues_spec.rb +++ b/spec/requests/api/graphql/project/issues_spec.rb @@ -91,7 +91,6 @@ RSpec.describe 'getting an issue list for a project', feature_category: :team_pl # filters let(:expected_negated_assignee_issues) { [issue_b, issue_c, issue_d, issue_e] } - let(:expected_unioned_assignee_issues) { [issue_a, issue_b] } let(:voted_issues) { [issue_a] } let(:no_award_issues) { [issue_b, issue_c, issue_d, issue_e] } let(:locked_discussion_issues) { [issue_a] } @@ -119,9 +118,6 @@ RSpec.describe 'getting an issue list for a project', feature_category: :team_pl let(:same_project_issue2) { issue_b } before_all do - issue_a.assignee_ids = current_user.id - issue_b.assignee_ids = another_user.id - create(:award_emoji, :upvote, user: current_user, awardable: issue_a) end diff --git a/spec/requests/api/graphql/project/jobs_spec.rb b/spec/requests/api/graphql/project/jobs_spec.rb index d05d4a2f4b6..aea6cad9e62 100644 --- a/spec/requests/api/graphql/project/jobs_spec.rb +++ b/spec/requests/api/graphql/project/jobs_spec.rb @@ -33,10 +33,10 @@ RSpec.describe 'Query.project.jobs', feature_category: :continuous_integration d it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do build_stage = create(:ci_stage, position: 1, name: 'build', project: project, pipeline: pipeline) test_stage = create(:ci_stage, position: 2, name: 'test', project: project, pipeline: pipeline) - create(:ci_build, pipeline: pipeline, stage_idx: build_stage.position, name: 'docker 1 2', stage: build_stage) - create(:ci_build, pipeline: pipeline, stage_idx: build_stage.position, name: 'docker 2 2', stage: build_stage) - create(:ci_build, pipeline: pipeline, stage_idx: test_stage.position, name: 'rspec 1 2', stage: test_stage) - test_job = create(:ci_build, pipeline: pipeline, stage_idx: test_stage.position, name: 'rspec 2 2', stage: test_stage) + create(:ci_build, pipeline: pipeline, name: 'docker 1 2', ci_stage: build_stage) + create(:ci_build, pipeline: pipeline, name: 'docker 2 2', ci_stage: build_stage) + create(:ci_build, pipeline: pipeline, name: 'rspec 1 2', ci_stage: test_stage) + test_job = create(:ci_build, pipeline: pipeline, name: 'rspec 2 2', ci_stage: test_stage) create(:ci_build_need, build: test_job, name: 'docker 1 2') post_graphql(query, current_user: user) @@ -45,8 +45,8 @@ RSpec.describe 'Query.project.jobs', feature_category: :continuous_integration d post_graphql(query, current_user: user) end - create(:ci_build, name: 'test-a', stage: test_stage, stage_idx: test_stage.position, pipeline: pipeline) - test_b_job = create(:ci_build, name: 'test-b', stage: test_stage, stage_idx: test_stage.position, pipeline: pipeline) + create(:ci_build, name: 'test-a', ci_stage: test_stage, pipeline: pipeline) + test_b_job = create(:ci_build, name: 'test-b', ci_stage: test_stage, pipeline: pipeline) create(:ci_build_need, build: test_b_job, name: 'docker 2 2') expect do diff --git a/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb b/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb index 36e148468bc..4884e04ab23 100644 --- a/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb +++ b/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'getting notes for a merge request', feature_category: :code_review do +RSpec.describe 'getting notes for a merge request', feature_category: :code_review_workflow do include GraphqlHelpers let_it_be(:noteable) { create(:merge_request) } diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb index b7aafdf305a..6aa96cfc070 100644 --- a/spec/requests/api/graphql/project/merge_request_spec.rb +++ b/spec/requests/api/graphql/project/merge_request_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'getting merge request information nested in a project', feature_category: :code_review do +RSpec.describe 'getting merge request information nested in a project', feature_category: :code_review_workflow do include GraphqlHelpers let_it_be(:project) { create(:project, :repository, :public) } diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb index b3b4c8fe0d5..8407faa967e 100644 --- a/spec/requests/api/graphql/project/merge_requests_spec.rb +++ b/spec/requests/api/graphql/project/merge_requests_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'getting merge request listings nested in a project', feature_category: :code_review do +RSpec.describe 'getting merge request listings nested in a project', feature_category: :code_review_workflow do include GraphqlHelpers let_it_be(:group) { create(:group) } diff --git a/spec/requests/api/graphql/project/pipeline_spec.rb b/spec/requests/api/graphql/project/pipeline_spec.rb index 0eeb382510e..abfdf07c288 100644 --- a/spec/requests/api/graphql/project/pipeline_spec.rb +++ b/spec/requests/api/graphql/project/pipeline_spec.rb @@ -348,10 +348,10 @@ RSpec.describe 'getting pipeline information nested in a project', feature_categ it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do build_stage = create(:ci_stage, position: 1, name: 'build', project: project, pipeline: pipeline) test_stage = create(:ci_stage, position: 2, name: 'test', project: project, pipeline: pipeline) - create(:ci_build, pipeline: pipeline, stage_idx: build_stage.position, name: 'docker 1 2', stage: build_stage) - create(:ci_build, pipeline: pipeline, stage_idx: build_stage.position, name: 'docker 2 2', stage: build_stage) - create(:ci_build, pipeline: pipeline, stage_idx: test_stage.position, name: 'rspec 1 2', stage: test_stage) - test_job = create(:ci_build, pipeline: pipeline, stage_idx: test_stage.position, name: 'rspec 2 2', stage: test_stage) + create(:ci_build, pipeline: pipeline, name: 'docker 1 2', ci_stage: build_stage) + create(:ci_build, pipeline: pipeline, name: 'docker 2 2', ci_stage: build_stage) + create(:ci_build, pipeline: pipeline, name: 'rspec 1 2', ci_stage: test_stage) + test_job = create(:ci_build, pipeline: pipeline, name: 'rspec 2 2', ci_stage: test_stage) create(:ci_build_need, build: test_job, name: 'docker 1 2') post_graphql(query, current_user: current_user) @@ -360,8 +360,8 @@ RSpec.describe 'getting pipeline information nested in a project', feature_categ post_graphql(query, current_user: current_user) end - create(:ci_build, name: 'test-a', stage: test_stage, stage_idx: test_stage.position, pipeline: pipeline) - test_b_job = create(:ci_build, name: 'test-b', stage: test_stage, stage_idx: test_stage.position, pipeline: pipeline) + create(:ci_build, name: 'test-a', ci_stage: test_stage, pipeline: pipeline) + test_b_job = create(:ci_build, name: 'test-b', ci_stage: test_stage, pipeline: pipeline) create(:ci_build_need, build: test_b_job, name: 'docker 2 2') expect do @@ -409,7 +409,8 @@ RSpec.describe 'getting pipeline information nested in a project', feature_categ it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do # create extra statuses - create(:generic_commit_status, :pending, name: 'generic-build-a', pipeline: pipeline, stage_idx: 0, stage: 'build') + external_stage = create(:ci_stage, position: 10, name: 'external', project: project, pipeline: pipeline) + create(:generic_commit_status, :pending, name: 'generic-build-a', pipeline: pipeline, ci_stage: external_stage) create(:ci_bridge, :failed, name: 'deploy-a', pipeline: pipeline, stage_idx: 2, stage: 'deploy') # warm up @@ -419,7 +420,7 @@ RSpec.describe 'getting pipeline information nested in a project', feature_categ post_graphql(query, current_user: current_user) end - create(:generic_commit_status, :pending, name: 'generic-build-b', pipeline: pipeline, stage_idx: 0, stage: 'build') + create(:generic_commit_status, :pending, name: 'generic-build-b', pipeline: pipeline, ci_stage: external_stage) create(:ci_build, :failed, name: 'test-a', pipeline: pipeline, stage_idx: 1, stage: 'test') create(:ci_build, :running, name: 'test-b', pipeline: pipeline, stage_idx: 1, stage: 'test') create(:ci_build, :pending, name: 'deploy-b', pipeline: pipeline, stage_idx: 2, stage: 'deploy') diff --git a/spec/requests/api/graphql/project/runners_spec.rb b/spec/requests/api/graphql/project/runners_spec.rb index 7304de7bec6..bee7ce2e372 100644 --- a/spec/requests/api/graphql/project/runners_spec.rb +++ b/spec/requests/api/graphql/project/runners_spec.rb @@ -53,16 +53,4 @@ RSpec.describe 'Project.runners', feature_category: :runner do expect(graphql_data_at(:project, :runners, :nodes)).to be_empty end end - - context 'when on_demand_scans_runner_tags feature flag is disabled' do - before do - stub_feature_flags(on_demand_scans_runner_tags: false) - end - - it 'returns no runners' do - post_graphql(query, current_user: user) - - expect(graphql_data_at(:project, :runners, :nodes)).to be_empty - end - end end diff --git a/spec/requests/api/graphql/project/work_items_spec.rb b/spec/requests/api/graphql/project/work_items_spec.rb index a59da706a8a..de35c943749 100644 --- a/spec/requests/api/graphql/project/work_items_spec.rb +++ b/spec/requests/api/graphql/project/work_items_spec.rb @@ -263,7 +263,7 @@ RSpec.describe 'getting a work item list for a project', feature_category: :team GRAPHQL end - before do + before_all do create_notes(item1, "some note1") create_notes(item2, "some note2") end diff --git a/spec/requests/api/graphql/user_spec.rb b/spec/requests/api/graphql/user_spec.rb index 2e1e4971767..3e82d783a18 100644 --- a/spec/requests/api/graphql/user_spec.rb +++ b/spec/requests/api/graphql/user_spec.rb @@ -58,4 +58,45 @@ RSpec.describe 'User', feature_category: :users do ) end end + + describe 'email fields' do + before_all do + current_user.commit_email = current_user.emails.first.email + current_user.save! + end + + let_it_be(:query) do + graphql_query_for( + :user, + { username: current_user.username }, + 'emails { nodes { email } } commitEmail namespaceCommitEmails { nodes { id } }' + ) + end + + let_it_be(:email_1) { create(:email, user: current_user) } + let_it_be(:email_2) { create(:email, user: current_user) } + let_it_be(:namespace_commit_email_1) { create(:namespace_commit_email, email: email_1) } + let_it_be(:namespace_commit_email_2) { create(:namespace_commit_email, email: email_2) } + + context 'with permission' do + it 'returns the relevant email details' do + post_graphql(query, current_user: current_user) + + expect(graphql_data['user']['emails']['nodes'].pluck('email')).to match_array( + current_user.emails.map(&:email)) + expect(graphql_data['user']['namespaceCommitEmails']['nodes']).not_to be_empty + expect(graphql_data['user']['commitEmail']).to eq(current_user.commit_email) + end + end + + context 'without permission' do + it 'does not return email details' do + post_graphql(query, current_user: create(:user)) + + expect(graphql_data['user']['emails']['nodes']).to be_empty + expect(graphql_data['user']['namespaceCommitEmails']['nodes']).to be_empty + expect(graphql_data['user']['commitEmail']).to be_nil + end + end + end end diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb index df7dbaea420..6b5d437df83 100644 --- a/spec/requests/api/graphql/work_item_spec.rb +++ b/spec/requests/api/graphql/work_item_spec.rb @@ -193,6 +193,24 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do ) end end + + context 'when ordered by default by created_at' do + let_it_be(:newest_child) { create(:work_item, :task, project: project, created_at: 5.minutes.from_now) } + let_it_be(:oldest_child) { create(:work_item, :task, project: project, created_at: 5.minutes.ago) } + let_it_be(:newest_link) { create(:parent_link, work_item_parent: work_item, work_item: newest_child) } + let_it_be(:oldest_link) { create(:parent_link, work_item_parent: work_item, work_item: oldest_child) } + + let(:hierarchy_widget) { work_item_data['widgets'].find { |widget| widget['type'] == 'HIERARCHY' } } + let(:hierarchy_children) { hierarchy_widget['children']['nodes'] } + + it 'places the oldest child item to the beginning of the children list' do + expect(hierarchy_children.first['id']).to eq(oldest_child.to_gid.to_s) + end + + it 'places the newest child item to the end of the children list' do + expect(hierarchy_children.last['id']).to eq(newest_child.to_gid.to_s) + end + end end describe 'assignees widget' do |