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/requests/api/graphql/project')
-rw-r--r--spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb109
-rw-r--r--spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb109
-rw-r--r--spec/requests/api/graphql/project/branch_rules/branch_protection_spec.rb60
-rw-r--r--spec/requests/api/graphql/project/branch_rules_spec.rb122
-rw-r--r--spec/requests/api/graphql/project/deployment_spec.rb51
-rw-r--r--spec/requests/api/graphql/project/environments_spec.rb133
-rw-r--r--spec/requests/api/graphql/project/issue/design_collection/version_spec.rb10
-rw-r--r--spec/requests/api/graphql/project/issues_spec.rb26
-rw-r--r--spec/requests/api/graphql/project/job_spec.rb54
-rw-r--r--spec/requests/api/graphql/project/merge_request_spec.rb20
-rw-r--r--spec/requests/api/graphql/project/pipeline_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/terraform/state_spec.rb16
-rw-r--r--spec/requests/api/graphql/project/terraform/states_spec.rb18
-rw-r--r--spec/requests/api/graphql/project/work_items_spec.rb63
14 files changed, 742 insertions, 51 deletions
diff --git a/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb b/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
new file mode 100644
index 00000000000..cb5006ec8e4
--- /dev/null
+++ b/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting merge access levels for a branch protection' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+
+ let(:merge_access_level_data) { merge_access_levels_data[0] }
+
+ let(:merge_access_levels_data) do
+ graphql_data_at('project',
+ 'branchRules',
+ 'nodes',
+ 0,
+ 'branchProtection',
+ 'mergeAccessLevels',
+ 'nodes')
+ end
+
+ let(:project) { protected_branch.project }
+
+ let(:merge_access_levels_count) { protected_branch.merge_access_levels.size }
+
+ let(:variables) { { path: project.full_path } }
+
+ let(:fields) { all_graphql_fields_for('MergeAccessLevel') }
+
+ let(:query) do
+ <<~GQL
+ query($path: ID!) {
+ project(fullPath: $path) {
+ branchRules(first: 1) {
+ nodes {
+ branchProtection {
+ mergeAccessLevels {
+ nodes {
+ #{fields}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ context 'when the user does not have read_protected_branch abilities' do
+ let_it_be(:protected_branch) { create(:protected_branch) }
+
+ before do
+ project.add_guest(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it { expect(merge_access_levels_data).not_to be_present }
+ end
+
+ shared_examples 'merge access request' do
+ let(:merge_access) { protected_branch.merge_access_levels.first }
+
+ before do
+ project.add_maintainer(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns all merge access levels' do
+ expect(merge_access_levels_data.size).to eq(merge_access_levels_count)
+ end
+
+ it 'includes access_level' do
+ expect(merge_access_level_data['accessLevel'])
+ .to eq(merge_access.access_level)
+ end
+
+ it 'includes access_level_description' do
+ expect(merge_access_level_data['accessLevelDescription'])
+ .to eq(merge_access.humanize)
+ end
+ end
+
+ context 'when the user does have read_protected_branch abilities' do
+ let(:merge_access) { protected_branch.merge_access_levels.first }
+
+ context 'when no one has access' do
+ let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_merge) }
+
+ it_behaves_like 'merge access request'
+ end
+
+ context 'when developers have access' do
+ let_it_be(:protected_branch) { create(:protected_branch, :developers_can_merge) }
+
+ it_behaves_like 'merge access request'
+ end
+
+ context 'when maintainers have access' do
+ let_it_be(:protected_branch) { create(:protected_branch, :maintainers_can_merge) }
+
+ it_behaves_like 'merge access request'
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb b/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb
new file mode 100644
index 00000000000..59f9c7d61cb
--- /dev/null
+++ b/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting push access levels for a branch protection' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+
+ let(:push_access_level_data) { push_access_levels_data[0] }
+
+ let(:push_access_levels_data) do
+ graphql_data_at('project',
+ 'branchRules',
+ 'nodes',
+ 0,
+ 'branchProtection',
+ 'pushAccessLevels',
+ 'nodes')
+ end
+
+ let(:project) { protected_branch.project }
+
+ let(:push_access_levels_count) { protected_branch.push_access_levels.size }
+
+ let(:variables) { { path: project.full_path } }
+
+ let(:fields) { all_graphql_fields_for('PushAccessLevel'.classify) }
+
+ let(:query) do
+ <<~GQL
+ query($path: ID!) {
+ project(fullPath: $path) {
+ branchRules(first: 1) {
+ nodes {
+ branchProtection {
+ pushAccessLevels {
+ nodes {
+ #{fields}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ context 'when the user does not have read_protected_branch abilities' do
+ let_it_be(:protected_branch) { create(:protected_branch) }
+
+ before do
+ project.add_guest(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it { expect(push_access_levels_data).not_to be_present }
+ end
+
+ shared_examples 'push access request' do
+ let(:push_access) { protected_branch.push_access_levels.first }
+
+ before do
+ project.add_maintainer(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns all push access levels' do
+ expect(push_access_levels_data.size).to eq(push_access_levels_count)
+ end
+
+ it 'includes access_level' do
+ expect(push_access_level_data['accessLevel'])
+ .to eq(push_access.access_level)
+ end
+
+ it 'includes access_level_description' do
+ expect(push_access_level_data['accessLevelDescription'])
+ .to eq(push_access.humanize)
+ end
+ end
+
+ context 'when the user does have read_protected_branch abilities' do
+ let(:push_access) { protected_branch.push_access_levels.first }
+
+ context 'when no one has access' do
+ let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_push) }
+
+ it_behaves_like 'push access request'
+ end
+
+ context 'when developers have access' do
+ let_it_be(:protected_branch) { create(:protected_branch, :developers_can_push) }
+
+ it_behaves_like 'push access request'
+ end
+
+ context 'when maintainers have access' do
+ let_it_be(:protected_branch) { create(:protected_branch, :maintainers_can_push) }
+
+ it_behaves_like 'push access request'
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/branch_rules/branch_protection_spec.rb b/spec/requests/api/graphql/project/branch_rules/branch_protection_spec.rb
new file mode 100644
index 00000000000..8a3f546ef95
--- /dev/null
+++ b/spec/requests/api/graphql/project/branch_rules/branch_protection_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting branch protection for a branch rule' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:branch_rule) { create(:protected_branch) }
+ let_it_be(:project) { branch_rule.project }
+
+ let(:branch_protection_data) do
+ graphql_data_at('project', 'branchRules', 'nodes', 0, 'branchProtection')
+ end
+
+ let(:variables) { { path: project.full_path } }
+
+ let(:fields) { all_graphql_fields_for('BranchProtection') }
+
+ let(:query) do
+ <<~GQL
+ query($path: ID!) {
+ project(fullPath: $path) {
+ branchRules(first: 1) {
+ nodes {
+ branchProtection {
+ #{fields}
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ context 'when the user does not have read_protected_branch abilities' do
+ before do
+ project.add_guest(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it { expect(branch_protection_data).not_to be_present }
+ end
+
+ context 'when the user does have read_protected_branch abilities' do
+ before do
+ project.add_maintainer(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'includes allow_force_push' do
+ expect(branch_protection_data['allowForcePush']).to be_in([true, false])
+ expect(branch_protection_data['allowForcePush']).to eq(branch_rule.allow_force_push)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/branch_rules_spec.rb b/spec/requests/api/graphql/project/branch_rules_spec.rb
new file mode 100644
index 00000000000..70fb37941e2
--- /dev/null
+++ b/spec/requests/api/graphql/project/branch_rules_spec.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting list of branch rules for a project' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :repository, :public) }
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:branch_name_a) { 'branch_name_a' }
+ let_it_be(:branch_name_b) { 'wildcard-*' }
+ 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)
+ end
+
+ let_it_be(:branch_rule_b) do
+ create(:protected_branch, project: project, name: branch_name_b)
+ end
+
+ let(:branch_rules_data) { graphql_data_at('project', 'branchRules', 'edges') }
+ let(:variables) { { path: project.full_path } }
+
+ let(:fields) do
+ <<~QUERY
+ pageInfo {
+ hasNextPage
+ hasPreviousPage
+ }
+ edges {
+ cursor
+ node {
+ #{all_graphql_fields_for('branch_rules'.classify)}
+ }
+ }
+ QUERY
+ end
+
+ let(:query) do
+ <<~GQL
+ query($path: ID!, $n: Int, $cursor: String) {
+ project(fullPath: $path) {
+ branchRules(first: $n, after: $cursor) { #{fields} }
+ }
+ }
+ GQL
+ end
+
+ context 'when the user does not have read_protected_branch abilities' do
+ before do
+ project.add_guest(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it { expect(branch_rules_data).to be_empty }
+ end
+
+ context 'when the user does have read_protected_branch abilities' do
+ before do
+ project.add_maintainer(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'includes a name' do
+ expect(branch_rules_data.dig(0, 'node', 'name')).to be_present
+ end
+
+ it 'includes created_at and updated_at' do
+ expect(branch_rules_data.dig(0, 'node', 'createdAt')).to be_present
+ expect(branch_rules_data.dig(1, 'node', 'updatedAt')).to be_present
+ end
+
+ context 'when limiting the number of results' do
+ let(:branch_rule_limit) { 1 }
+ let(:variables) { { path: project.full_path, n: branch_rule_limit } }
+ let(:next_variables) do
+ { path: project.full_path, n: branch_rule_limit, cursor: last_cursor }
+ end
+
+ it_behaves_like 'a working graphql query' do
+ it 'only returns N branch_rules' do
+ expect(branch_rules_data.size).to eq(branch_rule_limit)
+ expect(has_next_page).to be_truthy
+ expect(has_prev_page).to be_falsey
+ post_graphql(query, current_user: current_user, variables: next_variables)
+ expect(branch_rules_data.size).to eq(branch_rule_limit)
+ expect(has_next_page).to be_falsey
+ expect(has_prev_page).to be_truthy
+ end
+ end
+
+ context 'when no limit is provided' do
+ let(:branch_rule_limit) { nil }
+
+ it 'returns all branch_rules' do
+ expect(branch_rules_data.size).to eq(branch_rules.size)
+ end
+ end
+ end
+ end
+
+ def pagination_info
+ graphql_data_at('project', 'branchRules', 'pageInfo')
+ end
+
+ def has_next_page
+ pagination_info['hasNextPage']
+ end
+
+ def has_prev_page
+ pagination_info['hasPreviousPage']
+ end
+
+ def last_cursor
+ branch_rules_data.last['cursor']
+ end
+end
diff --git a/spec/requests/api/graphql/project/deployment_spec.rb b/spec/requests/api/graphql/project/deployment_spec.rb
new file mode 100644
index 00000000000..e5ef7bcafbf
--- /dev/null
+++ b/spec/requests/api/graphql/project/deployment_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Project Deployment query' do
+ let_it_be(:project) { create(:project, :private, :repository) }
+ let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
+ let_it_be(:guest) { create(:user).tap { |u| project.add_guest(u) } }
+ let_it_be(:environment) { create(:environment, project: project) }
+ let_it_be(:deployment) { create(:deployment, environment: environment, project: project) }
+
+ subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
+
+ let(:user) { developer }
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ deployment(iid: #{deployment.iid}) {
+ id
+ iid
+ ref
+ tag
+ sha
+ createdAt
+ updatedAt
+ finishedAt
+ status
+ }
+ }
+ }
+ )
+ end
+
+ it 'returns the deployment of the project' do
+ deployment_data = subject.dig('data', 'project', 'deployment')
+
+ expect(deployment_data['iid']).to eq(deployment.iid.to_s)
+ end
+
+ context 'when user is guest' do
+ let(:user) { guest }
+
+ it 'returns nothing' do
+ deployment_data = subject.dig('data', 'project', 'deployment')
+
+ expect(deployment_data).to be_nil
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/environments_spec.rb b/spec/requests/api/graphql/project/environments_spec.rb
new file mode 100644
index 00000000000..e5b6aebbf2c
--- /dev/null
+++ b/spec/requests/api/graphql/project/environments_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Project Environments query' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :private, :repository) }
+ let_it_be_with_refind(:production) { create(:environment, :production, project: project) }
+ let_it_be_with_refind(:staging) { create(:environment, :staging, project: project) }
+ let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
+
+ subject { post_graphql(query, current_user: user) }
+
+ let(:user) { developer }
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ environment(name: "#{production.name}") {
+ slug
+ createdAt
+ updatedAt
+ autoStopAt
+ autoDeleteAt
+ tier
+ environmentType
+ }
+ }
+ }
+ )
+ end
+
+ it 'returns the specified fields of the environment', :aggregate_failures do
+ production.update!(auto_stop_at: 1.day.ago, auto_delete_at: 2.days.ago, environment_type: 'review')
+
+ subject
+
+ environment_data = graphql_data.dig('project', 'environment')
+ expect(environment_data['slug']).to eq(production.slug)
+ expect(environment_data['createdAt']).to eq(production.created_at.iso8601)
+ expect(environment_data['updatedAt']).to eq(production.updated_at.iso8601)
+ expect(environment_data['autoStopAt']).to eq(production.auto_stop_at.iso8601)
+ expect(environment_data['autoDeleteAt']).to eq(production.auto_delete_at.iso8601)
+ expect(environment_data['tier']).to eq(production.tier.upcase)
+ expect(environment_data['environmentType']).to eq(production.environment_type)
+ end
+
+ describe 'last deployments of environments' do
+ ::Deployment.statuses.each do |status, _|
+ let_it_be(:"production_#{status}_deployment") do
+ create(:deployment, status.to_sym, environment: production, project: project)
+ end
+
+ let_it_be(:"staging_#{status}_deployment") do
+ create(:deployment, status.to_sym, environment: staging, project: project)
+ end
+ end
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ environments {
+ nodes {
+ name
+ lastSuccessDeployment: lastDeployment(status: SUCCESS) {
+ iid
+ }
+ lastRunningDeployment: lastDeployment(status: RUNNING) {
+ iid
+ }
+ lastBlockedDeployment: lastDeployment(status: BLOCKED) {
+ iid
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ it 'returns all last deployments of the environment' do
+ subject
+
+ environments_data = graphql_data_at(:project, :environments, :nodes)
+
+ environments_data.each do |environment_data|
+ name = environment_data['name']
+ success_deployment = public_send(:"#{name}_success_deployment")
+ running_deployment = public_send(:"#{name}_running_deployment")
+ blocked_deployment = public_send(:"#{name}_blocked_deployment")
+
+ expect(environment_data['lastSuccessDeployment']['iid']).to eq(success_deployment.iid.to_s)
+ expect(environment_data['lastRunningDeployment']['iid']).to eq(running_deployment.iid.to_s)
+ expect(environment_data['lastBlockedDeployment']['iid']).to eq(blocked_deployment.iid.to_s)
+ end
+ end
+
+ it 'executes the same number of queries in single environment and multiple environments' do
+ single_environment_query =
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ environment(name: "#{production.name}") {
+ name
+ lastSuccessDeployment: lastDeployment(status: SUCCESS) {
+ iid
+ }
+ lastRunningDeployment: lastDeployment(status: RUNNING) {
+ iid
+ }
+ lastBlockedDeployment: lastDeployment(status: BLOCKED) {
+ iid
+ }
+ }
+ }
+ }
+ )
+
+ baseline = ActiveRecord::QueryRecorder.new do
+ run_with_clean_state(single_environment_query, context: { current_user: user })
+ end
+
+ multi = ActiveRecord::QueryRecorder.new do
+ run_with_clean_state(query, context: { current_user: user })
+ end
+
+ expect(multi).not_to exceed_query_limit(baseline)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb b/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb
index 8cda61f0628..0444ce43c22 100644
--- a/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb
+++ b/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb
@@ -11,14 +11,14 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
let_it_be(:developer) { create(:user) }
let_it_be(:stranger) { create(:user) }
let_it_be(:old_version) do
- create(:design_version, issue: issue,
- created_designs: create_list(:design, 3, issue: issue))
+ create(:design_version, issue: issue, created_designs: create_list(:design, 3, issue: issue))
end
let_it_be(:version) do
- create(:design_version, issue: issue,
- modified_designs: old_version.designs,
- created_designs: create_list(:design, 2, issue: issue))
+ create(:design_version,
+ issue: issue,
+ modified_designs: old_version.designs,
+ created_designs: create_list(:design, 2, issue: issue))
end
let(:current_user) { developer }
diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb
index 596e023a027..28282860416 100644
--- a/spec/requests/api/graphql/project/issues_spec.rb
+++ b/spec/requests/api/graphql/project/issues_spec.rb
@@ -27,14 +27,6 @@ RSpec.describe 'getting an issue list for a project' do
QUERY
end
- let(:query) do
- graphql_query_for(
- 'project',
- { 'fullPath' => project.full_path },
- query_graphql_field('issues', issue_filter_params, fields)
- )
- end
-
it_behaves_like 'a working graphql query' do
before do
post_graphql(query, current_user: current_user)
@@ -89,6 +81,14 @@ RSpec.describe 'getting an issue list for a project' do
end
end
+ context 'when filtering by search' do
+ it_behaves_like 'query with a search term' do
+ let(:issuable_data) { issues_data }
+ let(:user) { current_user }
+ let_it_be(:issuable) { create(:issue, project: project, description: 'bar') }
+ end
+ end
+
context 'when limiting the number of results' do
let(:query) do
<<~GQL
@@ -301,7 +301,7 @@ RSpec.describe 'getting an issue list for a project' do
let_it_be(:relative_issue5) { create(:issue, project: sort_project, relative_position: 500) }
context 'when ascending' do
- it_behaves_like 'sorted paginated query' do
+ it_behaves_like 'sorted paginated query', is_reversible: true do
let(:sort_param) { :RELATIVE_POSITION_ASC }
let(:first_param) { 2 }
let(:all_records) do
@@ -679,4 +679,12 @@ RSpec.describe 'getting an issue list for a project' do
def issues_ids
graphql_dig_at(issues_data, :node, :id)
end
+
+ def query(params = issue_filter_params)
+ graphql_query_for(
+ 'project',
+ { 'fullPath' => project.full_path },
+ query_graphql_field('issues', params, fields)
+ )
+ end
end
diff --git a/spec/requests/api/graphql/project/job_spec.rb b/spec/requests/api/graphql/project/job_spec.rb
new file mode 100644
index 00000000000..6edd4cf753f
--- /dev/null
+++ b/spec/requests/api/graphql/project/job_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Query.project.job' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ let(:job) { create(:ci_build, project: project, name: 'GQL test job') }
+
+ let(:query) do
+ <<~QUERY
+ {
+ project(fullPath: "#{project.full_path}") {
+ job(id: "#{job.to_global_id}") {
+ name
+ }
+ }
+ }
+ QUERY
+ end
+
+ context 'when the user can read jobs on the project' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns the job that matches the given ID' do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data.dig('project', 'job', 'name')).to eq('GQL test job')
+ end
+
+ context 'when no job matches the given ID' do
+ let(:job) { create(:ci_build, project: create(:project), name: 'Job from another project') }
+
+ it 'returns null' do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data.dig('project', 'job')).to be_nil
+ end
+ end
+ end
+
+ context 'when the user cannot read jobs on the project' do
+ it 'returns null' do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data.dig('project', 'job')).to be_nil
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb
index d2f34080be3..6a59df81405 100644
--- a/spec/requests/api/graphql/project/merge_request_spec.rb
+++ b/spec/requests/api/graphql/project/merge_request_spec.rb
@@ -365,7 +365,7 @@ RSpec.describe 'getting merge request information nested in a project' do
expect(interaction_data).to contain_exactly a_hash_including(
'canMerge' => false,
'canUpdate' => can_update,
- 'reviewState' => attention_requested,
+ 'reviewState' => unreviewed,
'reviewed' => false,
'approved' => false
)
@@ -398,8 +398,8 @@ RSpec.describe 'getting merge request information nested in a project' do
describe 'scalability' do
let_it_be(:other_users) { create_list(:user, 3) }
- let(:attention_requested) do
- { 'reviewState' => 'ATTENTION_REQUESTED' }
+ let(:unreviewed) do
+ { 'reviewState' => 'UNREVIEWED' }
end
let(:reviewed) do
@@ -425,15 +425,15 @@ RSpec.describe 'getting merge request information nested in a project' do
other_users.each do |user|
assign_user(user)
- merge_request.merge_request_reviewers.find_or_create_by!(reviewer: user, state: :attention_requested)
+ merge_request.merge_request_reviewers.find_or_create_by!(reviewer: user)
end
expect { post_graphql(query) }.not_to exceed_query_limit(baseline)
expect(interaction_data).to contain_exactly(
- include(attention_requested),
- include(attention_requested),
- include(attention_requested),
+ include(unreviewed),
+ include(unreviewed),
+ include(unreviewed),
include(reviewed)
)
end
@@ -462,17 +462,17 @@ RSpec.describe 'getting merge request information nested in a project' do
it_behaves_like 'when requesting information about MR interactions' do
let(:field) { :reviewers }
- let(:attention_requested) { 'ATTENTION_REQUESTED' }
+ let(:unreviewed) { 'UNREVIEWED' }
let(:can_update) { false }
def assign_user(user)
- merge_request.merge_request_reviewers.create!(reviewer: user, state: :attention_requested)
+ merge_request.merge_request_reviewers.create!(reviewer: user)
end
end
it_behaves_like 'when requesting information about MR interactions' do
let(:field) { :assignees }
- let(:attention_requested) { nil }
+ let(:unreviewed) { nil }
let(:can_update) { true } # assignees can update MRs
def assign_user(user)
diff --git a/spec/requests/api/graphql/project/pipeline_spec.rb b/spec/requests/api/graphql/project/pipeline_spec.rb
index 08c6a2d9927..41915d3cdee 100644
--- a/spec/requests/api/graphql/project/pipeline_spec.rb
+++ b/spec/requests/api/graphql/project/pipeline_spec.rb
@@ -111,7 +111,7 @@ RSpec.describe 'getting pipeline information nested in a project' do
name: build_job.name,
pipeline: pipeline,
stage_idx: 0,
- stage: build_job.stage)
+ stage: build_job.stage_name)
end
let(:fields) do
diff --git a/spec/requests/api/graphql/project/terraform/state_spec.rb b/spec/requests/api/graphql/project/terraform/state_spec.rb
index 8f2d2cffef2..5e207ec0963 100644
--- a/spec/requests/api/graphql/project/terraform/state_spec.rb
+++ b/spec/requests/api/graphql/project/terraform/state_spec.rb
@@ -60,17 +60,17 @@ RSpec.describe 'query a single terraform state' do
expect(data).to match a_graphql_entity_for(
terraform_state,
:name,
- 'lockedAt' => terraform_state.locked_at.iso8601,
- 'createdAt' => terraform_state.created_at.iso8601,
- 'updatedAt' => terraform_state.updated_at.iso8601,
- 'lockedByUser' => a_graphql_entity_for(terraform_state.locked_by_user),
+ 'lockedAt' => terraform_state.locked_at.iso8601,
+ 'createdAt' => terraform_state.created_at.iso8601,
+ 'updatedAt' => terraform_state.updated_at.iso8601,
+ 'lockedByUser' => a_graphql_entity_for(terraform_state.locked_by_user),
'latestVersion' => a_graphql_entity_for(
latest_version,
- 'serial' => eq(latest_version.version),
- 'createdAt' => eq(latest_version.created_at.iso8601),
- 'updatedAt' => eq(latest_version.updated_at.iso8601),
+ 'serial' => eq(latest_version.version),
+ 'createdAt' => eq(latest_version.created_at.iso8601),
+ 'updatedAt' => eq(latest_version.updated_at.iso8601),
'createdByUser' => a_graphql_entity_for(latest_version.created_by_user),
- 'job' => { 'name' => eq(latest_version.build.name) }
+ 'job' => { 'name' => eq(latest_version.build.name) }
)
)
end
diff --git a/spec/requests/api/graphql/project/terraform/states_spec.rb b/spec/requests/api/graphql/project/terraform/states_spec.rb
index a7ec6f69776..cc3660bcc6b 100644
--- a/spec/requests/api/graphql/project/terraform/states_spec.rb
+++ b/spec/requests/api/graphql/project/terraform/states_spec.rb
@@ -64,18 +64,18 @@ RSpec.describe 'query terraform states' do
expect(data['nodes']).to contain_exactly a_graphql_entity_for(
terraform_state, :name,
- 'lockedAt' => terraform_state.locked_at.iso8601,
- 'createdAt' => terraform_state.created_at.iso8601,
- 'updatedAt' => terraform_state.updated_at.iso8601,
- 'lockedByUser' => a_graphql_entity_for(terraform_state.locked_by_user),
+ 'lockedAt' => terraform_state.locked_at.iso8601,
+ 'createdAt' => terraform_state.created_at.iso8601,
+ 'updatedAt' => terraform_state.updated_at.iso8601,
+ 'lockedByUser' => a_graphql_entity_for(terraform_state.locked_by_user),
'latestVersion' => a_graphql_entity_for(
latest_version,
- 'serial' => eq(latest_version.version),
- 'downloadPath' => eq(download_path),
- 'createdAt' => eq(latest_version.created_at.iso8601),
- 'updatedAt' => eq(latest_version.updated_at.iso8601),
+ 'serial' => eq(latest_version.version),
+ 'downloadPath' => eq(download_path),
+ 'createdAt' => eq(latest_version.created_at.iso8601),
+ 'updatedAt' => eq(latest_version.updated_at.iso8601),
'createdByUser' => a_graphql_entity_for(latest_version.created_by_user),
- 'job' => { 'name' => eq(latest_version.build.name) }
+ 'job' => { 'name' => eq(latest_version.build.name) }
)
)
end
diff --git a/spec/requests/api/graphql/project/work_items_spec.rb b/spec/requests/api/graphql/project/work_items_spec.rb
index 6ef28392b8b..69f8d1cac74 100644
--- a/spec/requests/api/graphql/project/work_items_spec.rb
+++ b/spec/requests/api/graphql/project/work_items_spec.rb
@@ -10,7 +10,10 @@ RSpec.describe 'getting an work item list for a project' do
let_it_be(:current_user) { create(:user) }
let_it_be(:item1) { create(:work_item, project: project, discussion_locked: true, title: 'item1') }
- let_it_be(:item2) { create(:work_item, project: project, title: 'item2') }
+ let_it_be(:item2) do
+ create(:work_item, project: project, title: 'item2', last_edited_by: current_user, last_edited_at: 1.day.ago)
+ end
+
let_it_be(:confidential_item) { create(:work_item, confidential: true, project: project, title: 'item3') }
let_it_be(:other_item) { create(:work_item) }
@@ -27,14 +30,6 @@ RSpec.describe 'getting an work item list for a project' do
QUERY
end
- let(:query) do
- graphql_query_for(
- 'project',
- { 'fullPath' => project.full_path },
- query_graphql_field('workItems', item_filter_params, fields)
- )
- end
-
it_behaves_like 'a working graphql query' do
before do
post_graphql(query, current_user: current_user)
@@ -83,6 +78,48 @@ RSpec.describe 'getting an work item list for a project' do
end
end
+ context 'when fetching description edit information' do
+ let(:fields) do
+ <<~GRAPHQL
+ nodes {
+ widgets {
+ type
+ ... on WorkItemWidgetDescription {
+ edited
+ lastEditedAt
+ lastEditedBy {
+ webPath
+ username
+ }
+ }
+ }
+ }
+ GRAPHQL
+ end
+
+ it 'avoids N+1 queries' do
+ post_graphql(query, current_user: current_user) # warm-up
+
+ control = ActiveRecord::QueryRecorder.new do
+ post_graphql(query, current_user: current_user)
+ end
+ expect_graphql_errors_to_be_empty
+
+ create_list(:work_item, 3, :last_edited_by_user, last_edited_at: 1.week.ago, project: project)
+
+ expect_graphql_errors_to_be_empty
+ expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control)
+ end
+ end
+
+ context 'when filtering by search' do
+ it_behaves_like 'query with a search term' do
+ let(:issuable_data) { items_data }
+ let(:user) { current_user }
+ let_it_be(:issuable) { create(:work_item, project: project, description: 'bar') }
+ end
+ end
+
describe 'sorting and pagination' do
let(:data_path) { [:project, :work_items] }
@@ -118,4 +155,12 @@ RSpec.describe 'getting an work item list for a project' do
def item_ids
graphql_dig_at(items_data, :node, :id)
end
+
+ def query(params = item_filter_params)
+ graphql_query_for(
+ 'project',
+ { 'fullPath' => project.full_path },
+ query_graphql_field('workItems', params, fields)
+ )
+ end
end