summaryrefslogtreecommitdiff
path: root/spec/requests/api/graphql
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-02-18 09:45:46 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-02-18 09:45:46 +0000
commita7b3560714b4d9cc4ab32dffcd1f74a284b93580 (patch)
tree7452bd5c3545c2fa67a28aa013835fb4fa071baf /spec/requests/api/graphql
parentee9173579ae56a3dbfe5afe9f9410c65bb327ca7 (diff)
downloadgitlab-ce-a7b3560714b4d9cc4ab32dffcd1f74a284b93580.tar.gz
Add latest changes from gitlab-org/gitlab@14-8-stable-eev14.8.0-rc42
Diffstat (limited to 'spec/requests/api/graphql')
-rw-r--r--spec/requests/api/graphql/ci/ci_cd_setting_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/config_spec.rb7
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb103
-rw-r--r--spec/requests/api/graphql/container_repository/container_repository_details_spec.rb2
-rw-r--r--spec/requests/api/graphql/gitlab_schema_spec.rb4
-rw-r--r--spec/requests/api/graphql/group/recent_issue_boards_query_spec.rb14
-rw-r--r--spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/create_spec.rb17
-rw-r--r--spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/user_preferences/update_spec.rb49
-rw-r--r--spec/requests/api/graphql/mutations/work_items/create_spec.rb21
-rw-r--r--spec/requests/api/graphql/mutations/work_items/delete_spec.rb49
-rw-r--r--spec/requests/api/graphql/mutations/work_items/update_spec.rb84
-rw-r--r--spec/requests/api/graphql/packages/package_spec.rb17
-rw-r--r--spec/requests/api/graphql/project/container_expiration_policy_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/container_repositories_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/grafana_integration_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue/designs/designs_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue/designs/notes_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/merge_requests_spec.rb37
-rw-r--r--spec/requests/api/graphql/project/project_members_spec.rb96
-rw-r--r--spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb14
-rw-r--r--spec/requests/api/graphql/project/repository/blobs_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/repository_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/tree/tree_spec.rb2
33 files changed, 503 insertions, 49 deletions
diff --git a/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb b/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb
index 578a71a7272..c19defa37e8 100644
--- a/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb
+++ b/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe 'Getting Ci Cd Setting' do
include GraphqlHelpers
let_it_be_with_reload(:project) { create(:project, :repository) }
- let_it_be(:current_user) { project.owner }
+ let_it_be(:current_user) { project.first_owner }
let(:fields) do
<<~QUERY
diff --git a/spec/requests/api/graphql/ci/config_spec.rb b/spec/requests/api/graphql/ci/config_spec.rb
index 755585f8e0e..62b15a8396c 100644
--- a/spec/requests/api/graphql/ci/config_spec.rb
+++ b/spec/requests/api/graphql/ci/config_spec.rb
@@ -225,7 +225,7 @@ RSpec.describe 'Query.ciConfig' do
context 'when using deprecated keywords' do
let_it_be(:content) do
YAML.dump(
- rspec: { script: 'ls' },
+ rspec: { script: 'ls', type: 'test' },
types: ['test']
)
end
@@ -233,7 +233,10 @@ RSpec.describe 'Query.ciConfig' do
it 'returns a warning' do
post_graphql_query
- expect(graphql_data['ciConfig']['warnings']).to include('root `types` is deprecated in 9.0 and will be removed in 15.0.')
+ expect(graphql_data['ciConfig']['warnings']).to include(
+ 'root `types` is deprecated in 9.0 and will be removed in 15.0.',
+ 'jobs:rspec `type` is deprecated in 9.0 and will be removed in 15.0.'
+ )
end
end
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 8c919b48849..fa16b9e1ddd 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -25,6 +25,8 @@ RSpec.describe 'Query.runner(id)' do
access_level: 0, tag_list: %w[tag1 tag2], run_untagged: true, executor_type: :shell)
end
+ let_it_be(:active_project_runner) { create(:ci_runner, :project) }
+
def get_runner(id)
case id
when :active_instance_runner
@@ -33,6 +35,8 @@ RSpec.describe 'Query.runner(id)' do
inactive_instance_runner
when :active_group_runner
active_group_runner
+ when :active_project_runner
+ active_project_runner
end
end
@@ -55,7 +59,7 @@ RSpec.describe 'Query.runner(id)' do
runner = get_runner(runner_id)
expect(runner_data).to match a_hash_including(
- 'id' => "gid://gitlab/Ci::Runner/#{runner.id}",
+ 'id' => runner.to_global_id.to_s,
'description' => runner.description,
'createdAt' => runner.created_at&.iso8601,
'contactedAt' => runner.contacted_at&.iso8601,
@@ -64,6 +68,7 @@ RSpec.describe 'Query.runner(id)' do
'revision' => runner.revision,
'locked' => false,
'active' => runner.active,
+ 'paused' => !runner.active,
'status' => runner.status('14.5').to_s.upcase,
'maximumTimeout' => runner.maximum_timeout,
'accessLevel' => runner.access_level.to_s.upcase,
@@ -72,6 +77,7 @@ RSpec.describe 'Query.runner(id)' do
'runnerType' => runner.instance_type? ? 'INSTANCE_TYPE' : 'PROJECT_TYPE',
'executorName' => runner.executor_type&.dasherize,
'jobCount' => 0,
+ 'jobs' => a_hash_including("count" => 0, "nodes" => [], "pageInfo" => anything),
'projectCount' => nil,
'adminUrl' => "http://localhost/admin/runners/#{runner.id}",
'userPermissions' => {
@@ -103,7 +109,7 @@ RSpec.describe 'Query.runner(id)' do
runner = get_runner(runner_id)
expect(runner_data).to match a_hash_including(
- 'id' => "gid://gitlab/Ci::Runner/#{runner.id}",
+ 'id' => runner.to_global_id.to_s,
'adminUrl' => nil
)
expect(runner_data['tagList']).to match_array runner.tag_list
@@ -179,7 +185,7 @@ RSpec.describe 'Query.runner(id)' do
runner_data = graphql_data_at(:runner)
expect(runner_data).to match a_hash_including(
- 'id' => "gid://gitlab/Ci::Runner/#{project_runner.id}",
+ 'id' => project_runner.to_global_id.to_s,
'locked' => is_locked
)
end
@@ -216,13 +222,36 @@ RSpec.describe 'Query.runner(id)' do
a_hash_including(
'webUrl' => "http://localhost/groups/#{group.full_path}/-/runners/#{active_group_runner.id}",
'node' => {
- 'id' => "gid://gitlab/Ci::Runner/#{active_group_runner.id}"
+ 'id' => active_group_runner.to_global_id.to_s
}
)
]
end
end
+ describe 'for group runner request' do
+ let(:query) do
+ %(
+ query {
+ runner(id: "#{active_group_runner.to_global_id}") {
+ groups {
+ nodes {
+ id
+ }
+ }
+ }
+ }
+ )
+ end
+
+ it 'retrieves groups field with expected value' do
+ post_graphql(query, current_user: user)
+
+ runner_data = graphql_data_at(:runner, :groups)
+ expect(runner_data).to eq 'nodes' => [{ 'id' => group.to_global_id.to_s }]
+ end
+ end
+
describe 'for runner with status' do
let_it_be(:stale_runner) { create(:ci_runner, description: 'Stale runner 1', created_at: 3.months.ago) }
let_it_be(:never_contacted_instance_runner) { create(:ci_runner, description: 'Missing runner 1', created_at: 1.month.ago, contacted_at: nil) }
@@ -279,21 +308,51 @@ RSpec.describe 'Query.runner(id)' do
let!(:job) { create(:ci_build, runner: project_runner1) }
- context 'requesting project and job counts' do
+ context 'requesting projects and counts for projects and jobs' do
+ let(:jobs_fragment) do
+ %(
+ jobs {
+ count
+ nodes {
+ id
+ status
+ }
+ }
+ )
+ end
+
let(:query) do
%(
query {
projectRunner1: runner(id: "#{project_runner1.to_global_id}") {
projectCount
jobCount
+ #{jobs_fragment}
+ projects {
+ nodes {
+ id
+ }
+ }
}
projectRunner2: runner(id: "#{project_runner2.to_global_id}") {
projectCount
jobCount
+ #{jobs_fragment}
+ projects {
+ nodes {
+ id
+ }
+ }
}
activeInstanceRunner: runner(id: "#{active_instance_runner.to_global_id}") {
projectCount
jobCount
+ #{jobs_fragment}
+ projects {
+ nodes {
+ id
+ }
+ }
}
}
)
@@ -312,13 +371,29 @@ RSpec.describe 'Query.runner(id)' do
expect(runner1_data).to match a_hash_including(
'jobCount' => 1,
- 'projectCount' => 2)
+ 'jobs' => a_hash_including(
+ "count" => 1,
+ "nodes" => [{ "id" => job.to_global_id.to_s, "status" => job.status.upcase }]
+ ),
+ 'projectCount' => 2,
+ 'projects' => {
+ 'nodes' => [
+ { 'id' => project1.to_global_id.to_s },
+ { 'id' => project2.to_global_id.to_s }
+ ]
+ })
expect(runner2_data).to match a_hash_including(
'jobCount' => 0,
- 'projectCount' => 0)
+ 'jobs' => nil, # returning jobs not allowed for more than 1 runner (see RunnerJobsResolver)
+ 'projectCount' => 0,
+ 'projects' => {
+ 'nodes' => []
+ })
expect(runner3_data).to match a_hash_including(
'jobCount' => 0,
- 'projectCount' => nil)
+ 'jobs' => nil, # returning jobs not allowed for more than 1 runner (see RunnerJobsResolver)
+ 'projectCount' => nil,
+ 'projects' => nil)
end
end
end
@@ -326,7 +401,17 @@ RSpec.describe 'Query.runner(id)' do
describe 'by regular user' do
let(:user) { create(:user) }
- it_behaves_like 'retrieval by unauthorized user', :active_instance_runner
+ context 'on instance runner' do
+ it_behaves_like 'retrieval by unauthorized user', :active_instance_runner
+ end
+
+ context 'on group runner' do
+ it_behaves_like 'retrieval by unauthorized user', :active_group_runner
+ end
+
+ context 'on project runner' do
+ it_behaves_like 'retrieval by unauthorized user', :active_project_runner
+ end
end
describe 'by non-admin user' do
diff --git a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
index 802ab847b3d..35a70a180a2 100644
--- a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
+++ b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'container repository details' do
)
end
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
let(:variables) { {} }
let(:tags) { %w[latest tag1 tag2 tag3 tag4 tag5] }
let(:container_repository_global_id) { container_repository.to_global_id.to_s }
diff --git a/spec/requests/api/graphql/gitlab_schema_spec.rb b/spec/requests/api/graphql/gitlab_schema_spec.rb
index 8bbeae97f57..e80f5e0e0ff 100644
--- a/spec/requests/api/graphql/gitlab_schema_spec.rb
+++ b/spec/requests/api/graphql/gitlab_schema_spec.rb
@@ -166,7 +166,7 @@ RSpec.describe 'GitlabSchema configurations' do
end
context 'authentication' do
- let(:current_user) { project.owner }
+ let(:current_user) { project.first_owner }
it 'authenticates all queries' do
subject
@@ -216,7 +216,7 @@ RSpec.describe 'GitlabSchema configurations' do
context "global id's" do
it 'uses GlobalID to expose ids' do
post_graphql(graphql_query_for('project', { 'fullPath' => project.full_path }, %w(id)),
- current_user: project.owner)
+ current_user: project.first_owner)
parsed_id = GlobalID.parse(graphql_data['project']['id'])
diff --git a/spec/requests/api/graphql/group/recent_issue_boards_query_spec.rb b/spec/requests/api/graphql/group/recent_issue_boards_query_spec.rb
new file mode 100644
index 00000000000..4914beec870
--- /dev/null
+++ b/spec/requests/api/graphql/group/recent_issue_boards_query_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting group recent issue boards' do
+ include GraphqlHelpers
+
+ it_behaves_like 'querying a GraphQL type recent boards' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:parent) { create(:group, :public) }
+ let_it_be(:board) { create(:board, resource_parent: parent, name: 'test group board') }
+ let(:board_type) { 'group' }
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb b/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
index 05f6804a208..30e7f196542 100644
--- a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe 'CiCdSettingsUpdate' do
end
context 'when authorized' do
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
it 'updates ci cd settings' do
post_graphql_mutation(mutation, current_user: user)
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
index b53a7ddde32..5269c60b50a 100644
--- a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe 'CiJobTokenScopeAddProject' do
end
context 'when authorized' do
- let_it_be(:current_user) { project.owner }
+ let_it_be(:current_user) { project.first_owner }
before do
target_project.add_developer(current_user)
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
index f1f42b00ada..b62291d1ebd 100644
--- a/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe 'CiJobTokenScopeRemoveProject' do
end
context 'when authorized' do
- let_it_be(:current_user) { project.owner }
+ let_it_be(:current_user) { project.first_owner }
before do
target_project.add_guest(current_user)
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb
index 08959d354e2..37656ab4eea 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'PipelineDestroy' do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
let_it_be(:pipeline) { create(:ci_pipeline, :success, project: project, user: user) }
let(:mutation) do
diff --git a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
index 322706be119..12368e7e9c5 100644
--- a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
@@ -71,7 +71,7 @@ RSpec.describe 'RunnersRegistrationTokenReset' do
end
include_context 'when authorized', 'project' do
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
def get_token
project.reload.runners_token
diff --git a/spec/requests/api/graphql/mutations/issues/create_spec.rb b/spec/requests/api/graphql/mutations/issues/create_spec.rb
index 6baed352b37..3d81b456c9c 100644
--- a/spec/requests/api/graphql/mutations/issues/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/create_spec.rb
@@ -52,5 +52,22 @@ RSpec.describe 'Create an issue' do
it_behaves_like 'has spam protection' do
let(:mutation_class) { ::Mutations::Issues::Create }
end
+
+ context 'when position params are provided' do
+ let(:existing_issue) { create(:issue, project: project, relative_position: 50) }
+
+ before do
+ input.merge!(
+ move_after_id: existing_issue.to_global_id.to_s
+ )
+ end
+
+ it 'sets the correct position' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['issue']['relativePosition']).to be < existing_issue.relative_position
+ end
+ end
end
end
diff --git a/spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb b/spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb
index 929609d4160..0c034f38dc8 100644
--- a/spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb
+++ b/spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'ConfigureSastIac' do
let(:mutation_response) { graphql_mutation_response(:configureSastIac) }
context 'when authorized' do
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
it 'creates a branch with sast iac configured' do
post_graphql_mutation(mutation, current_user: user)
diff --git a/spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb b/spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb
index 23a154b71a0..8fa6e44b208 100644
--- a/spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb
+++ b/spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'ConfigureSecretDetection' do
let(:mutation_response) { graphql_mutation_response(:configureSecretDetection) }
context 'when authorized' do
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
it 'creates a branch with secret detection configured' do
post_graphql_mutation(mutation, current_user: user)
diff --git a/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb b/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb
new file mode 100644
index 00000000000..e1c7fd9d60d
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::UserPreferences::Update do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+
+ let(:sort_value) { 'TITLE_ASC' }
+
+ let(:input) do
+ {
+ 'issuesSort' => sort_value
+ }
+ end
+
+ let(:mutation) { graphql_mutation(:userPreferencesUpdate, input) }
+ let(:mutation_response) { graphql_mutation_response(:userPreferencesUpdate) }
+
+ context 'when user has no existing preference' do
+ it 'creates the user preference record' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['userPreferences']['issuesSort']).to eq(sort_value)
+
+ expect(current_user.user_preference.persisted?).to eq(true)
+ expect(current_user.user_preference.issues_sort).to eq(Types::IssueSortEnum.values[sort_value].value.to_s)
+ end
+ end
+
+ context 'when user has existing preference' do
+ before do
+ current_user.create_user_preference!(issues_sort: Types::IssueSortEnum.values['TITLE_DESC'].value)
+ end
+
+ it 'updates the existing value' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ current_user.user_preference.reload
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['userPreferences']['issuesSort']).to eq(sort_value)
+
+ expect(current_user.user_preference.issues_sort).to eq(Types::IssueSortEnum.values[sort_value].value.to_s)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/work_items/create_spec.rb b/spec/requests/api/graphql/mutations/work_items/create_spec.rb
index e7a0c7753fb..6abdaa2c850 100644
--- a/spec/requests/api/graphql/mutations/work_items/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/create_spec.rb
@@ -47,6 +47,18 @@ RSpec.describe 'Create a work item' do
)
end
+ context 'when input is invalid' do
+ let(:input) { { 'title' => '', 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_global_id.to_s } }
+
+ it 'does not create and returns validation errors' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to not_change(WorkItem, :count)
+
+ expect(graphql_mutation_response(:work_item_create)['errors']).to contain_exactly("Title can't be blank")
+ end
+ end
+
it_behaves_like 'has spam protection' do
let(:mutation_class) { ::Mutations::WorkItems::Create }
end
@@ -56,8 +68,13 @@ RSpec.describe 'Create a work item' do
stub_feature_flags(work_items: false)
end
- it_behaves_like 'a mutation that returns top-level errors',
- errors: ["Field 'workItemCreate' doesn't exist on type 'Mutation'", "Variable $workItemCreateInput is declared by anonymous mutation but not used"]
+ it 'does not create the work item and returns an error' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to not_change(WorkItem, :count)
+
+ expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
+ end
end
end
end
diff --git a/spec/requests/api/graphql/mutations/work_items/delete_spec.rb b/spec/requests/api/graphql/mutations/work_items/delete_spec.rb
new file mode 100644
index 00000000000..14c8b757a57
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/work_items/delete_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Delete a work item' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } }
+
+ let(:current_user) { developer }
+ let(:mutation) { graphql_mutation(:workItemDelete, { 'id' => work_item.to_global_id.to_s }) }
+ let(:mutation_response) { graphql_mutation_response(:work_item_delete) }
+
+ context 'when the user is not allowed to delete a work item' do
+ let(:work_item) { create(:work_item, project: project) }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user has permissions to delete a work item' do
+ let_it_be(:authored_work_item, refind: true) { create(:work_item, project: project, author: developer, assignees: [developer]) }
+
+ let(:work_item) { authored_work_item }
+
+ it 'deletes the work item' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change(WorkItem, :count).by(-1)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['project']).to include('id' => work_item.project.to_global_id.to_s)
+ end
+
+ context 'when the work_items feature flag is disabled' do
+ before do
+ stub_feature_flags(work_items: false)
+ end
+
+ it 'does not delete the work item' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to not_change(WorkItem, :count)
+
+ expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/work_items/update_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_spec.rb
new file mode 100644
index 00000000000..71b03103115
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/work_items/update_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Update a work item' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } }
+ let_it_be(:work_item, refind: true) { create(:work_item, project: project) }
+
+ let(:work_item_event) { 'CLOSE' }
+ let(:input) { { 'stateEvent' => work_item_event, 'title' => 'updated title' } }
+
+ let(:mutation) { graphql_mutation(:workItemUpdate, input.merge('id' => work_item.to_global_id.to_s)) }
+
+ let(:mutation_response) { graphql_mutation_response(:work_item_update) }
+
+ context 'the user is not allowed to update a work item' do
+ let(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user has permissions to update a work item' do
+ let(:current_user) { developer }
+
+ context 'when the work item is open' do
+ it 'closes and updates the work item' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ work_item.reload
+ end.to change(work_item, :state).from('opened').to('closed').and(
+ change(work_item, :title).from(work_item.title).to('updated title')
+ )
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['workItem']).to include(
+ 'state' => 'CLOSED',
+ 'title' => 'updated title'
+ )
+ end
+ end
+
+ context 'when the work item is closed' do
+ let(:work_item_event) { 'REOPEN' }
+
+ before do
+ work_item.close!
+ end
+
+ it 'reopens the work item' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ work_item.reload
+ end.to change(work_item, :state).from('closed').to('opened')
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['workItem']).to include(
+ 'state' => 'OPEN'
+ )
+ end
+ end
+
+ it_behaves_like 'has spam protection' do
+ let(:mutation_class) { ::Mutations::WorkItems::Update }
+ end
+
+ context 'when the work_items feature flag is disabled' do
+ before do
+ stub_feature_flags(work_items: false)
+ end
+
+ it 'does not update the work item and returns and error' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ work_item.reload
+ end.to not_change(work_item, :title)
+
+ expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/packages/package_spec.rb b/spec/requests/api/graphql/packages/package_spec.rb
index 2ff3bc7cc47..365efc514d4 100644
--- a/spec/requests/api/graphql/packages/package_spec.rb
+++ b/spec/requests/api/graphql/packages/package_spec.rb
@@ -102,18 +102,6 @@ RSpec.describe 'package details' do
expect(package_file_ids).to contain_exactly(package_file.to_global_id.to_s)
end
-
- context 'with packages_installable_package_files disabled' do
- before do
- stub_feature_flags(packages_installable_package_files: false)
- end
-
- it 'returns them' do
- subject
-
- expect(package_file_ids).to contain_exactly(package_file_pending_destruction.to_global_id.to_s, package_file.to_global_id.to_s)
- end
- end
end
context 'with a batched query' do
@@ -145,8 +133,9 @@ RSpec.describe 'package details' do
let(:pipeline_gids) { pipelines.sort_by(&:id).map(&:to_gid).map(&:to_s).reverse }
before do
- composer_package.pipelines = pipelines
- composer_package.save!
+ pipelines.each do |pipeline|
+ create(:package_build_info, package: composer_package, pipeline: pipeline)
+ end
end
def run_query(args)
diff --git a/spec/requests/api/graphql/project/container_expiration_policy_spec.rb b/spec/requests/api/graphql/project/container_expiration_policy_spec.rb
index dc16847a669..e3ea9e46353 100644
--- a/spec/requests/api/graphql/project/container_expiration_policy_spec.rb
+++ b/spec/requests/api/graphql/project/container_expiration_policy_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe 'getting a repository in a project' do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
- let_it_be(:current_user) { project.owner }
+ let_it_be(:current_user) { project.first_owner }
let_it_be(:container_expiration_policy) { project.container_expiration_policy }
let(:fields) do
diff --git a/spec/requests/api/graphql/project/container_repositories_spec.rb b/spec/requests/api/graphql/project/container_repositories_spec.rb
index 692143b2215..bbab6012f3f 100644
--- a/spec/requests/api/graphql/project/container_repositories_spec.rb
+++ b/spec/requests/api/graphql/project/container_repositories_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe 'getting container repositories in a project' do
)
end
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
let(:variables) { {} }
let(:container_repositories_response) { graphql_data.dig('project', 'containerRepositories', 'edges') }
let(:container_repositories_count_response) { graphql_data.dig('project', 'containerRepositoriesCount') }
diff --git a/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb b/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
index 40a3281d3b7..2b85704f479 100644
--- a/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
+++ b/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'getting a detailed sentry error' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:project_setting) { create(:project_error_tracking_setting, project: project) }
- let_it_be(:current_user) { project.owner }
+ let_it_be(:current_user) { project.first_owner }
let_it_be(:sentry_detailed_error) { build(:error_tracking_sentry_detailed_error) }
let(:sentry_gid) { sentry_detailed_error.to_global_id.to_s }
diff --git a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
index a540386a9de..3ca0e35882a 100644
--- a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
+++ b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'sentry errors requests' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:project_setting) { create(:project_error_tracking_setting, project: project) }
- let_it_be(:current_user) { project.owner }
+ let_it_be(:current_user) { project.first_owner }
let(:query) do
graphql_query_for(
diff --git a/spec/requests/api/graphql/project/grafana_integration_spec.rb b/spec/requests/api/graphql/project/grafana_integration_spec.rb
index 9b24698f40c..e7534945e7a 100644
--- a/spec/requests/api/graphql/project/grafana_integration_spec.rb
+++ b/spec/requests/api/graphql/project/grafana_integration_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe 'Getting Grafana Integration' do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
- let_it_be(:current_user) { project.owner }
+ let_it_be(:current_user) { project.first_owner }
let_it_be(:grafana_integration) { create(:grafana_integration, project: project) }
let(:fields) do
diff --git a/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb b/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb
index 9d98498ca8a..46fd65db1c5 100644
--- a/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb
+++ b/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'Getting versions related to an issue' do
create(:design_version, issue: issue)
end
- let_it_be(:owner) { issue.project.owner }
+ let_it_be(:owner) { issue.project.first_owner }
def version_query(params = version_params)
query_graphql_field(:versions, params, version_query_fields)
diff --git a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
index def41efddde..f0205319983 100644
--- a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
+++ b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Getting designs related to an issue' do
include DesignManagementTestHelpers
let_it_be(:design) { create(:design, :with_smaller_image_versions, versions_count: 1) }
- let_it_be(:current_user) { design.project.owner }
+ let_it_be(:current_user) { design.project.first_owner }
let(:design_query) do
<<~NODE
diff --git a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
index 7148750b6cb..de2ace95757 100644
--- a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
+++ b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'Getting designs related to an issue' do
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:design) { create(:design, :with_file, versions_count: 1, issue: issue) }
- let_it_be(:current_user) { project.owner }
+ let_it_be(:current_user) { project.first_owner }
let_it_be(:note) { create(:diff_note_on_design, noteable: design, project: project) }
before do
diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb
index b0bedd99fce..303748bc70e 100644
--- a/spec/requests/api/graphql/project/merge_requests_spec.rb
+++ b/spec/requests/api/graphql/project/merge_requests_spec.rb
@@ -29,6 +29,10 @@ RSpec.describe 'getting merge request listings nested in a project' do
create(:merge_request, :unique_branches, source_project: project)
end
+ let(:all_merge_requests) do
+ [merge_request_a, merge_request_b, merge_request_c, merge_request_d, merge_request_e]
+ end
+
let(:results) { graphql_data.dig('project', 'mergeRequests', 'nodes') }
let(:search_params) { nil }
@@ -180,6 +184,39 @@ RSpec.describe 'getting merge request listings nested in a project' do
it_behaves_like 'when searching with parameters'
end
+ context 'when searching by update time' do
+ let(:start_time) { 10.days.ago }
+ let(:cutoff) { start_time + 36.hours }
+
+ before do
+ all_merge_requests.each_with_index do |mr, i|
+ mr.updated_at = start_time + i.days
+ mr.save!(touch: false)
+ end
+ end
+
+ context 'when searching by updated_after' do
+ let(:search_params) { { updated_after: cutoff } }
+ let(:mrs) { all_merge_requests[2..] }
+
+ it_behaves_like 'when searching with parameters'
+ end
+
+ context 'when searching by updated_before' do
+ let(:search_params) { { updated_before: cutoff } }
+ let(:mrs) { all_merge_requests[0..1] }
+
+ it_behaves_like 'when searching with parameters'
+ end
+
+ context 'when searching by updated_before and updated_after' do
+ let(:search_params) { { updated_after: cutoff, updated_before: cutoff + 2.days } }
+ let(:mrs) { all_merge_requests[2..3] }
+
+ it_behaves_like 'when searching with parameters'
+ end
+ end
+
context 'when searching by combination' do
let(:search_params) { { state: :closed, labels: [label.title] } }
let(:mrs) { [merge_request_c] }
diff --git a/spec/requests/api/graphql/project/project_members_spec.rb b/spec/requests/api/graphql/project/project_members_spec.rb
index 466464f600c..315d44884ff 100644
--- a/spec/requests/api/graphql/project/project_members_spec.rb
+++ b/spec/requests/api/graphql/project/project_members_spec.rb
@@ -110,6 +110,102 @@ RSpec.describe 'getting project members information' do
end
end
+ context 'merge request interactions' do
+ let(:project_path) { var('ID!').with(parent_project.full_path) }
+ let(:mr_a) do
+ var('MergeRequestID!')
+ .with(global_id_of(create(:merge_request, source_project: parent_project, source_branch: 'branch-1')))
+ end
+
+ let(:mr_b) do
+ var('MergeRequestID!')
+ .with(global_id_of(create(:merge_request, source_project: parent_project, source_branch: 'branch-2')))
+ end
+
+ let(:interaction_query) do
+ <<~HEREDOC
+ edges {
+ node {
+ user {
+ id
+ }
+ mrA: #{query_graphql_field(:merge_request_interaction, { id: mr_a }, 'canMerge')}
+ }
+ }
+ HEREDOC
+ end
+
+ let(:interaction_b_query) do
+ <<~HEREDOC
+ edges {
+ node {
+ user {
+ id
+ }
+ mrA: #{query_graphql_field(:merge_request_interaction, { id: mr_a }, 'canMerge')}
+ mrB: #{query_graphql_field(:merge_request_interaction, { id: mr_b }, 'canMerge')}
+ }
+ }
+ HEREDOC
+ end
+
+ it 'avoids N+1 queries, when requesting multiple MRs' do
+ control_query = with_signature(
+ [project_path, mr_a],
+ graphql_query_for(:project, { full_path: project_path },
+ query_graphql_field(:project_members, nil, interaction_query))
+ )
+ query_two = with_signature(
+ [project_path, mr_a, mr_b],
+ graphql_query_for(:project, { full_path: project_path },
+ query_graphql_field(:project_members, nil, interaction_b_query))
+ )
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ post_graphql(control_query, current_user: user, variables: [project_path, mr_a])
+ end
+
+ # two project members, neither of whom can merge
+ expect(can_merge(:mrA)).to eq [false, false]
+
+ expect do
+ post_graphql(query_two, current_user: user, variables: [project_path, mr_a, mr_b])
+
+ expect(can_merge(:mrA)).to eq [false, false]
+ expect(can_merge(:mrB)).to eq [false, false]
+ end.not_to exceed_query_limit(control_count)
+ end
+
+ it 'avoids N+1 queries, when more users are involved' do
+ new_user = create(:user)
+
+ query = with_signature(
+ [project_path, mr_a],
+ graphql_query_for(:project, { full_path: project_path },
+ query_graphql_field(:project_members, nil, interaction_query))
+ )
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ post_graphql(query, current_user: user, variables: [project_path, mr_a])
+ end
+
+ # two project members, neither of whom can merge
+ expect(can_merge(:mrA)).to eq [false, false]
+
+ parent_project.add_guest(new_user)
+
+ expect do
+ post_graphql(query, current_user: user, variables: [project_path, mr_a])
+
+ expect(can_merge(:mrA)).to eq [false, false, false]
+ end.not_to exceed_query_limit(control_count)
+ end
+
+ def can_merge(name)
+ graphql_data_at(:project, :project_members, :edges, :node, name, :can_merge)
+ end
+ end
+
context 'when unauthenticated' do
it 'returns members' do
fetch_members(current_user: nil, project: parent_project)
diff --git a/spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb b/spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb
new file mode 100644
index 00000000000..b3daf86c4af
--- /dev/null
+++ b/spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting project recent issue boards' do
+ include GraphqlHelpers
+
+ it_behaves_like 'querying a GraphQL type recent boards' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:parent) { create(:project, :public, namespace: user.namespace) }
+ let_it_be(:board) { create(:board, resource_parent: parent, name: 'test project board') }
+ let(:board_type) { 'project' }
+ end
+end
diff --git a/spec/requests/api/graphql/project/repository/blobs_spec.rb b/spec/requests/api/graphql/project/repository/blobs_spec.rb
index 12f6fbd793e..ba87f1100f2 100644
--- a/spec/requests/api/graphql/project/repository/blobs_spec.rb
+++ b/spec/requests/api/graphql/project/repository/blobs_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe 'getting blobs in a project repository' do
include GraphqlHelpers
let(:project) { create(:project, :repository) }
- let(:current_user) { project.owner }
+ let(:current_user) { project.first_owner }
let(:paths) { ["CONTRIBUTING.md", "README.md"] }
let(:ref) { project.default_branch }
let(:fields) do
diff --git a/spec/requests/api/graphql/project/repository_spec.rb b/spec/requests/api/graphql/project/repository_spec.rb
index 8810f2fa3d5..b00f64c3db6 100644
--- a/spec/requests/api/graphql/project/repository_spec.rb
+++ b/spec/requests/api/graphql/project/repository_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe 'getting a repository in a project' do
include GraphqlHelpers
let(:project) { create(:project, :repository) }
- let(:current_user) { project.owner }
+ let(:current_user) { project.first_owner }
let(:fields) do
<<~QUERY
#{all_graphql_fields_for('repository'.classify)}
diff --git a/spec/requests/api/graphql/project/tree/tree_spec.rb b/spec/requests/api/graphql/project/tree/tree_spec.rb
index f4cd316da96..25e878a5b1a 100644
--- a/spec/requests/api/graphql/project/tree/tree_spec.rb
+++ b/spec/requests/api/graphql/project/tree/tree_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe 'getting a tree in a project' do
include GraphqlHelpers
let(:project) { create(:project, :repository) }
- let(:current_user) { project.owner }
+ let(:current_user) { project.first_owner }
let(:path) { "" }
let(:ref) { "master" }
let(:fields) do