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:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-20 16:49:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-20 16:49:51 +0300
commit71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e (patch)
tree6a2d93ef3fb2d353bb7739e4b57e6541f51cdd71 /spec/graphql
parenta7253423e3403b8c08f8a161e5937e1488f5f407 (diff)
Add latest changes from gitlab-org/gitlab@15-9-stable-eev15.9.0-rc42
Diffstat (limited to 'spec/graphql')
-rw-r--r--spec/graphql/mutations/achievements/create_spec.rb2
-rw-r--r--spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb40
-rw-r--r--spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb37
-rw-r--r--spec/graphql/mutations/ci/pipeline_schedule/variable_input_type_spec.rb9
-rw-r--r--spec/graphql/mutations/issues/update_spec.rb41
-rw-r--r--spec/graphql/mutations/merge_requests/update_spec.rb103
-rw-r--r--spec/graphql/mutations/saved_replies/create_spec.rb2
-rw-r--r--spec/graphql/mutations/saved_replies/update_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb8
-rw-r--r--spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/variables_resolver_spec.rb70
-rw-r--r--spec/graphql/resolvers/data_transfer_resolver_spec.rb31
-rw-r--r--spec/graphql/resolvers/group_releases_resolver_spec.rb47
-rw-r--r--spec/graphql/resolvers/groups_resolver_spec.rb127
-rw-r--r--spec/graphql/resolvers/nested_groups_resolver_spec.rb133
-rw-r--r--spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/releases_resolver_spec.rb64
-rw-r--r--spec/graphql/resolvers/saved_reply_resolver_spec.rb40
-rw-r--r--spec/graphql/resolvers/users/participants_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/work_items_resolver_spec.rb4
-rw-r--r--spec/graphql/types/achievements/achievement_type_spec.rb3
-rw-r--r--spec/graphql/types/ci/job_token_scope_type_spec.rb84
-rw-r--r--spec/graphql/types/ci/job_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/pipeline_schedule_variable_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/pipeline_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/runner_architecture_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/runner_platform_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/runner_setup_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/runner_type_spec.rb3
-rw-r--r--spec/graphql/types/ci/runner_upgrade_status_enum_spec.rb3
-rw-r--r--spec/graphql/types/ci/runner_web_url_edge_spec.rb2
-rw-r--r--spec/graphql/types/ci/variable_sort_enum_spec.rb12
-rw-r--r--spec/graphql/types/commit_signatures/verification_status_enum_spec.rb2
-rw-r--r--spec/graphql/types/group_type_spec.rb9
-rw-r--r--spec/graphql/types/issue_type_spec.rb26
-rw-r--r--spec/graphql/types/notes/deleted_note_type_spec.rb15
-rw-r--r--spec/graphql/types/packages/package_details_type_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/merge_request_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/work_item_spec.rb2
-rw-r--r--spec/graphql/types/project_type_spec.rb64
-rw-r--r--spec/graphql/types/query_type_spec.rb42
-rw-r--r--spec/graphql/types/user_type_spec.rb3
-rw-r--r--spec/graphql/types/users/email_type_spec.rb2
-rw-r--r--spec/graphql/types/users/namespace_commit_email_type_spec.rb2
-rw-r--r--spec/graphql/types/work_item_type_spec.rb1
45 files changed, 783 insertions, 276 deletions
diff --git a/spec/graphql/mutations/achievements/create_spec.rb b/spec/graphql/mutations/achievements/create_spec.rb
index 4bad6164314..12b8ff67549 100644
--- a/spec/graphql/mutations/achievements/create_spec.rb
+++ b/spec/graphql/mutations/achievements/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::Achievements::Create, feature_category: :users do
+RSpec.describe Mutations::Achievements::Create, feature_category: :user_profile do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb b/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb
index 727db7e2361..44147987ebb 100644
--- a/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb
+++ b/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Mutations::Ci::JobTokenScope::AddProject do
+RSpec.describe Mutations::Ci::JobTokenScope::AddProject, feature_category: :continuous_integration do
let(:mutation) do
described_class.new(object: nil, context: { current_user: current_user }, field: nil)
end
@@ -14,9 +14,10 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddProject do
let_it_be(:target_project) { create(:project) }
let(:target_project_path) { target_project.full_path }
+ let(:mutation_args) { { project_path: project.full_path, target_project_path: target_project_path } }
subject do
- mutation.resolve(project_path: project.full_path, target_project_path: target_project_path)
+ mutation.resolve(**mutation_args)
end
context 'when user is not logged in' do
@@ -42,18 +43,45 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddProject do
target_project.add_guest(current_user)
end
- it 'adds target project to the job token scope' do
+ it 'adds target project to the outbound job token scope by default' do
expect do
expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty)
- end.to change { Ci::JobToken::ProjectScopeLink.count }.by(1)
+ end.to change { Ci::JobToken::ProjectScopeLink.outbound.count }.by(1)
+ end
+
+ context 'when mutation uses the direction argument' do
+ let(:mutation_args) { super().merge!(direction: direction) }
+
+ context 'when targeting the outbound allowlist' do
+ let(:direction) { :outbound }
+
+ it 'adds the target project' do
+ expect do
+ expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty)
+ end.to change { Ci::JobToken::ProjectScopeLink.outbound.count }.by(1)
+ end
+ end
+
+ context 'when targeting the inbound allowlist' do
+ let(:direction) { :inbound }
+
+ it 'adds the target project' do
+ expect do
+ expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty)
+ end.to change { Ci::JobToken::ProjectScopeLink.inbound.count }.by(1)
+ end
+ end
end
context 'when the service returns an error' do
let(:service) { double(:service) }
it 'returns an error response' do
- expect(::Ci::JobTokenScope::AddProjectService).to receive(:new).with(project, current_user).and_return(service)
- expect(service).to receive(:execute).with(target_project).and_return(ServiceResponse.error(message: 'The error message'))
+ expect(::Ci::JobTokenScope::AddProjectService).to receive(:new).with(
+ project,
+ current_user
+ ).and_return(service)
+ expect(service).to receive(:execute).with(target_project, direction: :outbound).and_return(ServiceResponse.error(message: 'The error message'))
expect(subject.fetch(:ci_job_token_scope)).to be_nil
expect(subject.fetch(:errors)).to include("The error message")
diff --git a/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb b/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
index d399e73f394..5385b6ca1cf 100644
--- a/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
+++ b/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Mutations::Ci::JobTokenScope::RemoveProject do
+RSpec.describe Mutations::Ci::JobTokenScope::RemoveProject, feature_category: :continuous_integration do
let(:mutation) do
described_class.new(object: nil, context: { current_user: current_user }, field: nil)
end
@@ -17,6 +17,7 @@ RSpec.describe Mutations::Ci::JobTokenScope::RemoveProject do
end
let(:target_project_path) { target_project.full_path }
+ let(:links_relation) { Ci::JobToken::ProjectScopeLink.with_source(project).with_target(target_project) }
subject do
mutation.resolve(project_path: project.full_path, target_project_path: target_project_path)
@@ -45,18 +46,40 @@ RSpec.describe Mutations::Ci::JobTokenScope::RemoveProject do
target_project.add_guest(current_user)
end
- it 'removes target project from the job token scope' do
- expect do
- expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty)
- end.to change { Ci::JobToken::ProjectScopeLink.count }.by(-1)
+ let(:service) { instance_double('Ci::JobTokenScope::RemoveProjectService') }
+
+ context 'with no direction specified' do
+ it 'defaults to asking the RemoveProjectService to remove the outbound link' do
+ expect(::Ci::JobTokenScope::RemoveProjectService)
+ .to receive(:new).with(project, current_user).and_return(service)
+ expect(service).to receive(:execute).with(target_project, :outbound)
+ .and_return(instance_double('ServiceResponse', "success?": true))
+
+ subject
+ end
+ end
+
+ context 'with direction specified' do
+ subject do
+ mutation.resolve(project_path: project.full_path, target_project_path: target_project_path, direction: 'inbound')
+ end
+
+ it 'executes project removal for the correct direction' do
+ expect(::Ci::JobTokenScope::RemoveProjectService)
+ .to receive(:new).with(project, current_user).and_return(service)
+ expect(service).to receive(:execute).with(target_project, 'inbound')
+ .and_return(instance_double('ServiceResponse', "success?": true))
+
+ subject
+ end
end
context 'when the service returns an error' do
- let(:service) { double(:service) }
+ let(:service) { instance_double('Ci::JobTokenScope::RemoveProjectService') }
it 'returns an error response' do
expect(::Ci::JobTokenScope::RemoveProjectService).to receive(:new).with(project, current_user).and_return(service)
- expect(service).to receive(:execute).with(target_project).and_return(ServiceResponse.error(message: 'The error message'))
+ expect(service).to receive(:execute).with(target_project, :outbound).and_return(ServiceResponse.error(message: 'The error message'))
expect(subject.fetch(:ci_job_token_scope)).to be_nil
expect(subject.fetch(:errors)).to include("The error message")
diff --git a/spec/graphql/mutations/ci/pipeline_schedule/variable_input_type_spec.rb b/spec/graphql/mutations/ci/pipeline_schedule/variable_input_type_spec.rb
new file mode 100644
index 00000000000..564bc95b352
--- /dev/null
+++ b/spec/graphql/mutations/ci/pipeline_schedule/variable_input_type_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Ci::PipelineSchedule::VariableInputType, feature_category: :continuous_integration do
+ specify { expect(described_class.graphql_name).to eq('PipelineScheduleVariableInput') }
+
+ it { expect(described_class.arguments.keys).to match_array(%w[key value variableType]) }
+end
diff --git a/spec/graphql/mutations/issues/update_spec.rb b/spec/graphql/mutations/issues/update_spec.rb
index bb57ad4c404..324f225f209 100644
--- a/spec/graphql/mutations/issues/update_spec.rb
+++ b/spec/graphql/mutations/issues/update_spec.rb
@@ -46,10 +46,12 @@ RSpec.describe Mutations::Issues::Update do
project.add_developer(user)
end
- it 'updates issue with correct values' do
- subject
+ context 'when all attributes except timeEstimate are provided' do
+ it 'updates issue with correct values' do
+ subject
- expect(issue.reload).to have_attributes(expected_attributes)
+ expect(issue.reload).to have_attributes(expected_attributes)
+ end
end
context 'when iid does not exist' do
@@ -162,6 +164,39 @@ RSpec.describe Mutations::Issues::Update do
expect { subject }.to change { issue.reload.issue_type }.from('issue').to('incident')
end
end
+
+ context 'when timeEstimate attribute is provided' do
+ let_it_be_with_refind(:issue) { create(:issue, project: project, time_estimate: 3600) }
+
+ let(:time_estimate) { '0' }
+ let(:expected_attributes) { { time_estimate: time_estimate } }
+
+ context 'when timeEstimate is invalid' do
+ let(:time_estimate) { '1e' }
+
+ it 'raises an argument error and changes are not applied' do
+ expect { mutation.ready?(time_estimate: time_estimate) }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'timeEstimate must be formatted correctly, for example `1h 30m`')
+ expect { subject }.not_to change { issue.reload.time_estimate }
+ end
+ end
+
+ context 'when timeEstimate is 0' do
+ let(:time_estimate) { '0' }
+
+ it 'resets the time estimate' do
+ expect { subject }.to change { issue.reload.time_estimate }.from(3600).to(0)
+ end
+ end
+
+ context 'when timeEstimate is a valid human readable time' do
+ let(:time_estimate) { '1h 30m' }
+
+ it 'updates the time estimate' do
+ expect { subject }.to change { issue.reload.time_estimate }.from(3600).to(5400)
+ end
+ end
+ end
end
end
end
diff --git a/spec/graphql/mutations/merge_requests/update_spec.rb b/spec/graphql/mutations/merge_requests/update_spec.rb
index 206abaf34ce..8a10f6cadd0 100644
--- a/spec/graphql/mutations/merge_requests/update_spec.rb
+++ b/spec/graphql/mutations/merge_requests/update_spec.rb
@@ -26,10 +26,56 @@ RSpec.describe Mutations::MergeRequests::Update do
merge_request.project.add_developer(user)
end
- it 'applies all attributes' do
- expect(mutated_merge_request).to eq(merge_request)
- expect(mutated_merge_request).to have_attributes(attributes)
- expect(subject[:errors]).to be_empty
+ context 'when all attributes except timeEstimate are provided' do
+ before do
+ merge_request.update!(time_estimate: 3600)
+ end
+
+ it 'applies all attributes' do
+ expect(mutated_merge_request).to eq(merge_request)
+ expect(mutated_merge_request).to have_attributes(attributes)
+ expect(mutated_merge_request.time_estimate).to eq(3600)
+ expect(subject[:errors]).to be_empty
+ end
+ end
+
+ context 'when timeEstimate attribute is provided' do
+ let(:time_estimate) { '0' }
+ let(:attributes) { { time_estimate: time_estimate } }
+
+ before do
+ merge_request.update!(time_estimate: 3600)
+ end
+
+ context 'when timeEstimate is invalid' do
+ let(:time_estimate) { '1e' }
+
+ it 'changes are not applied' do
+ expect { mutation.ready?(time_estimate: time_estimate) }
+ .to raise_error(
+ Gitlab::Graphql::Errors::ArgumentError,
+ 'timeEstimate must be formatted correctly, for example `1h 30m`')
+ expect(mutated_merge_request.time_estimate).to eq(3600)
+ end
+ end
+
+ context 'when timeEstimate is 0' do
+ let(:time_estimate) { '0' }
+
+ it 'resets the time estimate' do
+ expect(mutated_merge_request.time_estimate).to eq(0)
+ expect(subject[:errors]).to be_empty
+ end
+ end
+
+ context 'when timeEstimate is a valid human readable time' do
+ let(:time_estimate) { '1h 30m' }
+
+ it 'updates the time estimate' do
+ expect(mutated_merge_request.time_estimate).to eq(5400)
+ expect(subject[:errors]).to be_empty
+ end
+ end
end
context 'the merge request is invalid' do
@@ -82,4 +128,53 @@ RSpec.describe Mutations::MergeRequests::Update do
end
end
end
+
+ describe '#ready?' do
+ let(:extra_args) { {} }
+
+ let(:arguments) do
+ {
+ project_path: merge_request.project.full_path,
+ iid: merge_request.iid
+ }.merge(extra_args)
+ end
+
+ subject(:ready) { mutation.ready?(**arguments) }
+
+ context 'when required arguments are not provided' do
+ let(:arguments) { {} }
+
+ it 'raises an argument error' do
+ expect { subject }.to raise_error(ArgumentError, 'Arguments must be provided: projectPath, iid')
+ end
+ end
+
+ context 'when required arguments are provided' do
+ it 'returns true' do
+ expect(subject).to eq(true)
+ end
+ end
+
+ context 'when timeEstimate is provided' do
+ let(:extra_args) { { time_estimate: time_estimate } }
+
+ context 'when the value is invalid' do
+ let(:time_estimate) { '1e' }
+
+ it 'raises an argument error' do
+ expect { subject }.to raise_error(
+ Gitlab::Graphql::Errors::ArgumentError,
+ 'timeEstimate must be formatted correctly, for example `1h 30m`')
+ end
+ end
+
+ context 'when the value valid' do
+ let(:time_estimate) { '1d' }
+
+ it 'returns true' do
+ expect(subject).to eq(true)
+ end
+ end
+ end
+ end
end
diff --git a/spec/graphql/mutations/saved_replies/create_spec.rb b/spec/graphql/mutations/saved_replies/create_spec.rb
index 5141c537b06..9423ba2b354 100644
--- a/spec/graphql/mutations/saved_replies/create_spec.rb
+++ b/spec/graphql/mutations/saved_replies/create_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Mutations::SavedReplies::Create do
let(:mutation_arguments) { { name: '', content: '' } }
it { expect(subject[:saved_reply]).to be_nil }
- it { expect(subject[:errors]).to match_array(["Content can't be blank", "Name can't be blank", "Name can contain only lowercase letters, digits, '_' and '-'. Must start with a letter, and cannot end with '-' or '_'"]) }
+ it { expect(subject[:errors]).to match_array(["Content can't be blank", "Name can't be blank"]) }
end
context 'when service successfully creates a new saved reply' do
diff --git a/spec/graphql/mutations/saved_replies/update_spec.rb b/spec/graphql/mutations/saved_replies/update_spec.rb
index 67c2d1348f7..9b0e90b7b41 100644
--- a/spec/graphql/mutations/saved_replies/update_spec.rb
+++ b/spec/graphql/mutations/saved_replies/update_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe Mutations::SavedReplies::Update do
let(:mutation_arguments) { { name: '', content: '' } }
it { expect(subject[:saved_reply]).to be_nil }
- it { expect(subject[:errors]).to match_array(["Content can't be blank", "Name can't be blank", "Name can contain only lowercase letters, digits, '_' and '-'. Must start with a letter, and cannot end with '-' or '_'"]) }
+ it { expect(subject[:errors]).to match_array(["Content can't be blank", "Name can't be blank"]) }
end
context 'when service successfully updates the saved reply' do
diff --git a/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb b/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb
index 59ece15b745..92f4d3dd8e8 100644
--- a/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb
@@ -23,18 +23,18 @@ RSpec.describe Resolvers::Ci::JobTokenScopeResolver do
it 'returns the same project in the allow list of projects for the Ci Job Token when scope is not enabled' do
allow(project).to receive(:ci_outbound_job_token_scope_enabled?).and_return(false)
- expect(resolve_scope.all_projects).to contain_exactly(project)
+ expect(resolve_scope.outbound_projects).to contain_exactly(project)
end
it 'returns the same project in the allow list of projects for the Ci Job Token' do
- expect(resolve_scope.all_projects).to contain_exactly(project)
+ expect(resolve_scope.outbound_projects).to contain_exactly(project)
end
context 'when another projects gets added to the allow list' do
let!(:link) { create(:ci_job_token_project_scope_link, source_project: project) }
it 'returns both projects' do
- expect(resolve_scope.all_projects).to contain_exactly(project, link.target_project)
+ expect(resolve_scope.outbound_projects).to contain_exactly(project, link.target_project)
end
end
@@ -44,7 +44,7 @@ RSpec.describe Resolvers::Ci::JobTokenScopeResolver do
end
it 'resolves projects' do
- expect(resolve_scope.all_projects).to contain_exactly(project)
+ expect(resolve_scope.outbound_projects).to contain_exactly(project)
end
end
end
diff --git a/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb
index 1d1fb4a9967..da6a84cec44 100644
--- a/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Resolvers::Ci::RunnerPlatformsResolver, feature_category: :runner
expect(resolve_subject).to contain_exactly(
hash_including(name: :linux), hash_including(name: :osx),
hash_including(name: :windows), hash_including(name: :docker),
- hash_including(name: :kubernetes)
+ hash_including(name: :kubernetes), hash_including(name: :aws)
)
end
end
diff --git a/spec/graphql/resolvers/ci/variables_resolver_spec.rb b/spec/graphql/resolvers/ci/variables_resolver_spec.rb
new file mode 100644
index 00000000000..16b72e8cb7f
--- /dev/null
+++ b/spec/graphql/resolvers/ci/variables_resolver_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Ci::VariablesResolver, feature_category: :pipeline_authoring do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:args) { {} }
+ let_it_be(:obj) { nil }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project) }
+
+ let_it_be(:ci_instance_variables) do
+ [
+ create(:ci_instance_variable, key: 'a'),
+ create(:ci_instance_variable, key: 'b')
+ ]
+ end
+
+ let_it_be(:ci_group_variables) do
+ [
+ create(:ci_group_variable, group: group, key: 'a'),
+ create(:ci_group_variable, group: group, key: 'b')
+ ]
+ end
+
+ let_it_be(:ci_project_variables) do
+ [
+ create(:ci_variable, project: project, key: 'a'),
+ create(:ci_variable, project: project, key: 'b')
+ ]
+ end
+
+ subject(:resolve_variables) { resolve(described_class, obj: obj, ctx: { current_user: user }, args: args) }
+
+ context 'when parent object is nil' do
+ context 'when user is authorized', :enable_admin_mode do
+ let_it_be(:user) { create(:admin) }
+
+ it "returns the instance's variables" do
+ expect(resolve_variables.items.to_a).to match_array(ci_instance_variables)
+ end
+ end
+
+ context 'when user is not authorized' do
+ it "returns nil" do
+ expect(resolve_variables).to be_nil
+ end
+ end
+ end
+
+ context 'when parent object is a Group' do
+ let_it_be(:obj) { group }
+
+ it "returns the group's variables" do
+ expect(resolve_variables.items.to_a).to match_array(ci_group_variables)
+ end
+ end
+
+ context 'when parent object is a Project' do
+ let_it_be(:obj) { project }
+
+ it "returns the project's variables" do
+ expect(resolve_variables.items.to_a).to match_array(ci_project_variables)
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/data_transfer_resolver_spec.rb b/spec/graphql/resolvers/data_transfer_resolver_spec.rb
new file mode 100644
index 00000000000..f5a088dc1c3
--- /dev/null
+++ b/spec/graphql/resolvers/data_transfer_resolver_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::DataTransferResolver, feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ describe '.source' do
+ context 'with base DataTransferResolver' do
+ it 'raises NotImplementedError' do
+ expect { described_class.source }.to raise_error ::NotImplementedError
+ end
+ end
+
+ context 'with projects DataTransferResolver' do
+ let(:source) { described_class.project.source }
+
+ it 'outputs "Project"' do
+ expect(source).to eq 'Project'
+ end
+ end
+
+ context 'with groups DataTransferResolver' do
+ let(:source) { described_class.group.source }
+
+ it 'outputs "Group"' do
+ expect(source).to eq 'Group'
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/group_releases_resolver_spec.rb b/spec/graphql/resolvers/group_releases_resolver_spec.rb
new file mode 100644
index 00000000000..73386870030
--- /dev/null
+++ b/spec/graphql/resolvers/group_releases_resolver_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::GroupReleasesResolver, feature_category: :release_orchestration do
+ include GraphqlHelpers
+
+ let_it_be(:today) { Time.now }
+ let_it_be(:yesterday) { today - 1.day }
+ let_it_be(:tomorrow) { today + 1.day }
+
+ let_it_be(:group) { create(:group, :private) }
+ let_it_be(:project) { create(:project, :private, namespace: group) }
+ let_it_be(:release_v1) do
+ create(:release, project: project, tag: 'v1.0.0', released_at: yesterday, created_at: tomorrow)
+ end
+
+ let_it_be(:release_v2) do
+ create(:release, project: project, tag: 'v2.0.0', released_at: today, created_at: yesterday)
+ end
+
+ let_it_be(:release_v3) do
+ create(:release, project: project, tag: 'v3.0.0', released_at: tomorrow, created_at: today)
+ end
+
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:public_user) { create(:user) }
+
+ let(:args) { { sort: :released_at_desc } }
+ let(:all_releases) { [release_v1, release_v2, release_v3] }
+
+ before do
+ group.add_member(developer, :owner)
+ project.add_developer(developer)
+ end
+
+ describe '#resolve' do
+ it_behaves_like 'releases and group releases resolver'
+ end
+
+ private
+
+ def resolve_releases
+ context = { current_user: current_user }
+ resolve(described_class, obj: group, args: args, ctx: context, arg_style: :internal)
+ end
+end
diff --git a/spec/graphql/resolvers/groups_resolver_spec.rb b/spec/graphql/resolvers/groups_resolver_spec.rb
index e53ca674163..9d1ad46ed0e 100644
--- a/spec/graphql/resolvers/groups_resolver_spec.rb
+++ b/spec/graphql/resolvers/groups_resolver_spec.rb
@@ -2,131 +2,42 @@
require 'spec_helper'
-RSpec.describe Resolvers::GroupsResolver do
+RSpec.describe Resolvers::GroupsResolver, feature_category: :subgroups do
include GraphqlHelpers
describe '#resolve' do
- let_it_be(:group) { create(:group, name: 'public-group') }
- let_it_be(:private_group) { create(:group, :private, name: 'private-group') }
- let_it_be(:subgroup1) { create(:group, parent: group, name: 'Subgroup') }
- let_it_be(:subgroup2) { create(:group, parent: subgroup1, name: 'Test Subgroup 2') }
- let_it_be(:private_subgroup1) { create(:group, :private, parent: private_group, name: 'Subgroup1') }
- let_it_be(:private_subgroup2) { create(:group, :private, parent: private_subgroup1, name: 'Subgroup2') }
let_it_be(:user) { create(:user) }
+ let_it_be(:public_group) { create(:group, name: 'public-group') }
+ let_it_be(:private_group) { create(:group, :private, name: 'private-group') }
- before_all do
- private_group.add_developer(user)
- end
+ let(:params) { {} }
- shared_examples 'access to all public descendant groups' do
- it 'returns all public descendant groups of the parent group ordered by ASC name' do
- is_expected.to eq([subgroup1, subgroup2])
- end
- end
+ subject { resolve(described_class, args: params, ctx: { current_user: user }) }
- shared_examples 'access to all public subgroups' do
- it 'returns all public subgroups of the parent group' do
- is_expected.to contain_exactly(subgroup1)
- end
+ it 'includes public groups' do
+ expect(subject).to contain_exactly(public_group)
end
- shared_examples 'returning empty results' do
- it 'returns empty results' do
- is_expected.to be_empty
- end
+ it 'includes accessible private groups' do
+ private_group.add_developer(user)
+ expect(subject).to contain_exactly(public_group, private_group)
end
- context 'when parent group is public' do
- subject { resolve(described_class, obj: group, args: params, ctx: { current_user: current_user }) }
-
- context 'when `include_parent_descendants` is false' do
- let(:params) { { include_parent_descendants: false } }
-
- context 'when user is not logged in' do
- let(:current_user) { nil }
-
- it_behaves_like 'access to all public subgroups'
- end
+ describe 'ordering' do
+ let_it_be(:other_group) { create(:group, name: 'other-group') }
- context 'when user is logged in' do
- let(:current_user) { user }
-
- it_behaves_like 'access to all public subgroups'
- end
- end
-
- context 'when `include_parent_descendants` is true' do
- let(:params) { { include_parent_descendants: true } }
-
- context 'when user is not logged in' do
- let(:current_user) { nil }
-
- it_behaves_like 'access to all public descendant groups'
- end
-
- context 'when user is logged in' do
- let(:current_user) { user }
-
- it_behaves_like 'access to all public descendant groups'
-
- context 'with owned argument set as true' do
- before do
- subgroup1.add_owner(current_user)
- params[:owned] = true
- end
-
- it 'returns only descendant groups owned by the user' do
- is_expected.to contain_exactly(subgroup1)
- end
- end
-
- context 'with search argument' do
- it 'returns only descendant groups with matching name or path' do
- params[:search] = 'Test'
- is_expected.to contain_exactly(subgroup2)
- end
- end
- end
+ it 'orders by name ascending' do
+ expect(subject.map(&:name)).to eq(%w[other-group public-group])
end
end
- context 'when parent group is private' do
- subject { resolve(described_class, obj: private_group, args: params, ctx: { current_user: current_user }) }
-
- context 'when `include_parent_descendants` is true' do
- let(:params) { { include_parent_descendants: true } }
-
- context 'when user is not logged in' do
- let(:current_user) { nil }
-
- it_behaves_like 'returning empty results'
- end
-
- context 'when user is logged in' do
- let(:current_user) { user }
-
- it 'returns all private descendant groups' do
- is_expected.to contain_exactly(private_subgroup1, private_subgroup2)
- end
- end
- end
-
- context 'when `include_parent_descendants` is false' do
- let(:params) { { include_parent_descendants: false } }
-
- context 'when user is not logged in' do
- let(:current_user) { nil }
-
- it_behaves_like 'returning empty results'
- end
+ context 'with `search` argument' do
+ let_it_be(:other_group) { create(:group, name: 'other-group') }
- context 'when user is logged in' do
- let(:current_user) { user }
+ let(:params) { { search: 'oth' } }
- it 'returns private subgroups' do
- is_expected.to contain_exactly(private_subgroup1)
- end
- end
+ it 'filters groups by name' do
+ expect(subject).to contain_exactly(other_group)
end
end
end
diff --git a/spec/graphql/resolvers/nested_groups_resolver_spec.rb b/spec/graphql/resolvers/nested_groups_resolver_spec.rb
new file mode 100644
index 00000000000..e58edc3fd4b
--- /dev/null
+++ b/spec/graphql/resolvers/nested_groups_resolver_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::NestedGroupsResolver, feature_category: :subgroups do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:group) { create(:group, name: 'public-group') }
+ let_it_be(:private_group) { create(:group, :private, name: 'private-group') }
+ let_it_be(:subgroup1) { create(:group, parent: group, name: 'Subgroup') }
+ let_it_be(:subgroup2) { create(:group, parent: subgroup1, name: 'Test Subgroup 2') }
+ let_it_be(:private_subgroup1) { create(:group, :private, parent: private_group, name: 'Subgroup1') }
+ let_it_be(:private_subgroup2) { create(:group, :private, parent: private_subgroup1, name: 'Subgroup2') }
+ let_it_be(:user) { create(:user) }
+
+ before_all do
+ private_group.add_developer(user)
+ end
+
+ shared_examples 'access to all public descendant groups' do
+ it 'returns all public descendant groups of the parent group ordered by ASC name' do
+ is_expected.to eq([subgroup1, subgroup2])
+ end
+ end
+
+ shared_examples 'access to all public subgroups' do
+ it 'returns all public subgroups of the parent group' do
+ is_expected.to contain_exactly(subgroup1)
+ end
+ end
+
+ shared_examples 'returning empty results' do
+ it 'returns empty results' do
+ is_expected.to be_empty
+ end
+ end
+
+ context 'when parent group is public' do
+ subject { resolve(described_class, obj: group, args: params, ctx: { current_user: current_user }) }
+
+ context 'when `include_parent_descendants` is false' do
+ let(:params) { { include_parent_descendants: false } }
+
+ context 'when user is not logged in' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'access to all public subgroups'
+ end
+
+ context 'when user is logged in' do
+ let(:current_user) { user }
+
+ it_behaves_like 'access to all public subgroups'
+ end
+ end
+
+ context 'when `include_parent_descendants` is true' do
+ let(:params) { { include_parent_descendants: true } }
+
+ context 'when user is not logged in' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'access to all public descendant groups'
+ end
+
+ context 'when user is logged in' do
+ let(:current_user) { user }
+
+ it_behaves_like 'access to all public descendant groups'
+
+ context 'with owned argument set as true' do
+ before do
+ subgroup1.add_owner(current_user)
+ params[:owned] = true
+ end
+
+ it 'returns only descendant groups owned by the user' do
+ is_expected.to contain_exactly(subgroup1)
+ end
+ end
+
+ context 'with search argument' do
+ it 'returns only descendant groups with matching name or path' do
+ params[:search] = 'Test'
+ is_expected.to contain_exactly(subgroup2)
+ end
+ end
+ end
+ end
+ end
+
+ context 'when parent group is private' do
+ subject { resolve(described_class, obj: private_group, args: params, ctx: { current_user: current_user }) }
+
+ context 'when `include_parent_descendants` is true' do
+ let(:params) { { include_parent_descendants: true } }
+
+ context 'when user is not logged in' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'returning empty results'
+ end
+
+ context 'when user is logged in' do
+ let(:current_user) { user }
+
+ it 'returns all private descendant groups' do
+ is_expected.to contain_exactly(private_subgroup1, private_subgroup2)
+ end
+ end
+ end
+
+ context 'when `include_parent_descendants` is false' do
+ let(:params) { { include_parent_descendants: false } }
+
+ context 'when user is not logged in' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'returning empty results'
+ end
+
+ context 'when user is logged in' do
+ let(:current_user) { user }
+
+ it 'returns private subgroups' do
+ is_expected.to contain_exactly(private_subgroup1)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
index b95bab41e3e..6af2f56cef4 100644
--- a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Resolvers::Projects::JiraProjectsResolver do
+RSpec.describe Resolvers::Projects::JiraProjectsResolver, feature_category: :integrations do
include GraphqlHelpers
specify do
diff --git a/spec/graphql/resolvers/releases_resolver_spec.rb b/spec/graphql/resolvers/releases_resolver_spec.rb
index 6ba9a6c33a1..58f6257c946 100644
--- a/spec/graphql/resolvers/releases_resolver_spec.rb
+++ b/spec/graphql/resolvers/releases_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Resolvers::ReleasesResolver do
+RSpec.describe Resolvers::ReleasesResolver, feature_category: :release_orchestration do
include GraphqlHelpers
let_it_be(:today) { Time.now }
@@ -24,60 +24,28 @@ RSpec.describe Resolvers::ReleasesResolver do
end
describe '#resolve' do
- context 'when the user does not have access to the project' do
- let(:current_user) { public_user }
+ it_behaves_like 'releases and group releases resolver'
- it 'returns an empty array' do
- expect(resolve_releases).to be_empty
- end
- end
-
- context "when the user has full access to the project's releases" do
+ describe 'when order_by is created_at' do
let(:current_user) { developer }
- it 'returns all releases associated to the project' do
- expect(resolve_releases).to match_array(all_releases)
- end
-
- describe 'sorting behavior' do
- context 'with sort: :released_at_desc' do
- let(:args) { { sort: :released_at_desc } }
-
- it 'returns the releases ordered by released_at in descending order' do
- expect(resolve_releases.to_a)
- .to match_array(all_releases)
- .and be_sorted(:released_at, :desc)
- end
- end
-
- context 'with sort: :released_at_asc' do
- let(:args) { { sort: :released_at_asc } }
-
- it 'returns the releases ordered by released_at in ascending order' do
- expect(resolve_releases.to_a)
- .to match_array(all_releases)
- .and be_sorted(:released_at, :asc)
- end
- end
-
- context 'with sort: :created_desc' do
- let(:args) { { sort: :created_desc } }
+ context 'with sort: desc' do
+ let(:args) { { sort: :created_desc } }
- it 'returns the releases ordered by created_at in descending order' do
- expect(resolve_releases.to_a)
- .to match_array(all_releases)
- .and be_sorted(:created_at, :desc)
- end
+ it 'returns the releases ordered by created_at in descending order' do
+ expect(resolve_releases.to_a)
+ .to match_array(all_releases)
+ .and be_sorted(:created_at, :desc)
end
+ end
- context 'with sort: :created_asc' do
- let(:args) { { sort: :created_asc } }
+ context 'with sort: asc' do
+ let(:args) { { sort: :created_asc } }
- it 'returns the releases ordered by created_at in ascending order' do
- expect(resolve_releases.to_a)
- .to match_array(all_releases)
- .and be_sorted(:created_at, :asc)
- end
+ it 'returns the releases ordered by created_at in ascending order' do
+ expect(resolve_releases.to_a)
+ .to match_array(all_releases)
+ .and be_sorted(:created_at, :asc)
end
end
end
diff --git a/spec/graphql/resolvers/saved_reply_resolver_spec.rb b/spec/graphql/resolvers/saved_reply_resolver_spec.rb
new file mode 100644
index 00000000000..f1cb0ca5214
--- /dev/null
+++ b/spec/graphql/resolvers/saved_reply_resolver_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::SavedReplyResolver, feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:saved_reply) { create(:saved_reply, user: current_user) }
+
+ describe 'feature flag disabled' do
+ before do
+ stub_feature_flags(saved_replies: false)
+ end
+
+ it 'does not return saved reply' do
+ expect(resolve_saved_reply).to be_nil
+ end
+ end
+
+ describe 'feature flag enabled' do
+ it 'returns users saved reply' do
+ expect(resolve_saved_reply).to eq(saved_reply)
+ end
+
+ it 'returns nil when saved reply is not found' do
+ expect(resolve_saved_reply({ id: 'gid://gitlab/Users::SavedReply/100' })).to be_nil
+ end
+
+ it 'returns nil when saved reply is another users' do
+ other_users_saved_reply = create(:saved_reply, user: create(:user))
+
+ expect(resolve_saved_reply({ id: other_users_saved_reply.to_global_id })).to be_nil
+ end
+ end
+
+ def resolve_saved_reply(args = { id: saved_reply.to_global_id })
+ resolve(described_class, args: args, ctx: { current_user: current_user })
+ end
+end
diff --git a/spec/graphql/resolvers/users/participants_resolver_spec.rb b/spec/graphql/resolvers/users/participants_resolver_spec.rb
index 27c3b9643ce..224213d1521 100644
--- a/spec/graphql/resolvers/users/participants_resolver_spec.rb
+++ b/spec/graphql/resolvers/users/participants_resolver_spec.rb
@@ -115,8 +115,8 @@ RSpec.describe Resolvers::Users::ParticipantsResolver do
create(:award_emoji, name: 'thumbsup', awardable: public_note)
# 1 extra query per source (3 emojis + 2 notes) to fetch participables collection
- # 1 extra query to load work item widgets collection
- expect { query.call }.not_to exceed_query_limit(control_count).with_threshold(6)
+ # 2 extra queries to load work item widgets collection
+ expect { query.call }.not_to exceed_query_limit(control_count).with_threshold(7)
end
it 'does not execute N+1 for system note metadata relation' do
diff --git a/spec/graphql/resolvers/work_items_resolver_spec.rb b/spec/graphql/resolvers/work_items_resolver_spec.rb
index d89ccc7f806..6da62e3adb7 100644
--- a/spec/graphql/resolvers/work_items_resolver_spec.rb
+++ b/spec/graphql/resolvers/work_items_resolver_spec.rb
@@ -101,7 +101,7 @@ RSpec.describe Resolvers::WorkItemsResolver do
end
it 'batches queries that only include IIDs', :request_store do
- result = batch_sync(max_queries: 7) do
+ result = batch_sync(max_queries: 8) do
[item1, item2]
.map { |item| resolve_items(iid: item.iid.to_s) }
.flat_map(&:to_a)
@@ -111,7 +111,7 @@ RSpec.describe Resolvers::WorkItemsResolver do
end
it 'finds a specific item with iids', :request_store do
- result = batch_sync(max_queries: 7) do
+ result = batch_sync(max_queries: 8) do
resolve_items(iids: [item1.iid]).to_a
end
diff --git a/spec/graphql/types/achievements/achievement_type_spec.rb b/spec/graphql/types/achievements/achievement_type_spec.rb
index 5c98753ac66..f967dc8e25e 100644
--- a/spec/graphql/types/achievements/achievement_type_spec.rb
+++ b/spec/graphql/types/achievements/achievement_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['Achievement'], feature_category: :users do
+RSpec.describe GitlabSchema.types['Achievement'], feature_category: :user_profile do
include GraphqlHelpers
let(:fields) do
@@ -12,7 +12,6 @@ RSpec.describe GitlabSchema.types['Achievement'], feature_category: :users do
name
avatar_url
description
- revokeable
created_at
updated_at
]
diff --git a/spec/graphql/types/ci/job_token_scope_type_spec.rb b/spec/graphql/types/ci/job_token_scope_type_spec.rb
index 569b59d6c70..01044364881 100644
--- a/spec/graphql/types/ci/job_token_scope_type_spec.rb
+++ b/spec/graphql/types/ci/job_token_scope_type_spec.rb
@@ -2,17 +2,24 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
+RSpec.describe GitlabSchema.types['CiJobTokenScopeType'], feature_category: :continuous_integration do
specify { expect(described_class.graphql_name).to eq('CiJobTokenScopeType') }
it 'has the correct fields' do
- expected_fields = [:projects]
+ expected_fields = [:projects, :inboundAllowlist, :outboundAllowlist]
expect(described_class).to have_graphql_fields(*expected_fields)
end
describe 'query' do
- let(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
+ let(:project) do
+ create(
+ :project,
+ ci_outbound_job_token_scope_enabled: true,
+ ci_inbound_job_token_scope_enabled: true
+ ).tap(&:save!)
+ end
+
let_it_be(:current_user) { create(:user) }
let(:query) do
@@ -25,6 +32,16 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
path
}
}
+ inboundAllowlist {
+ nodes {
+ path
+ }
+ }
+ outboundAllowlist {
+ nodes {
+ path
+ }
+ }
}
}
}
@@ -33,30 +50,73 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
subject { GitlabSchema.execute(query, context: { current_user: current_user }).as_json }
- let(:projects_field) { subject.dig('data', 'project', 'ciJobTokenScope', 'projects', 'nodes') }
- let(:returned_project_paths) { projects_field.map { |project| project['path'] } }
+ let(:scope_field) { subject.dig('data', 'project', 'ciJobTokenScope') }
+ let(:errors_field) { subject['errors'] }
+ let(:projects_field) { scope_field&.dig('projects', 'nodes') }
+ let(:outbound_allowlist_field) { scope_field&.dig('outboundAllowlist', 'nodes') }
+ let(:inbound_allowlist_field) { scope_field&.dig('inboundAllowlist', 'nodes') }
+ let(:returned_project_paths) { projects_field.map { |p| p['path'] } }
+ let(:returned_outbound_paths) { outbound_allowlist_field.map { |p| p['path'] } }
+ let(:returned_inbound_paths) { inbound_allowlist_field.map { |p| p['path'] } }
+
+ context 'without access to scope' do
+ before do
+ project.add_member(current_user, :developer)
+ end
+
+ it 'returns no projects' do
+ expect(projects_field).to be_nil
+ expect(outbound_allowlist_field).to be_nil
+ expect(inbound_allowlist_field).to be_nil
+ expect(errors_field.first['message']).to include "don't have permission"
+ end
+ end
context 'with access to scope' do
before do
project.add_member(current_user, :maintainer)
end
- context 'when multiple projects in the allow list' do
- let!(:link) { create(:ci_job_token_project_scope_link, source_project: project) }
+ context 'when multiple projects in the allow lists' do
+ include Ci::JobTokenScopeHelpers
+ let!(:outbound_allowlist_project) { create_project_in_allowlist(project, direction: :outbound) }
+ let!(:inbound_allowlist_project) { create_project_in_allowlist(project, direction: :inbound) }
+ let!(:both_allowlists_project) { create_project_in_both_allowlists(project) }
context 'when linked projects are readable' do
before do
- link.target_project.add_member(current_user, :developer)
+ outbound_allowlist_project.add_member(current_user, :developer)
+ inbound_allowlist_project.add_member(current_user, :developer)
+ both_allowlists_project.add_member(current_user, :developer)
end
- it 'returns readable projects in scope' do
- expect(returned_project_paths).to contain_exactly(project.path, link.target_project.path)
+ shared_examples 'returns projects' do
+ it 'returns readable projects in scope' do
+ outbound_paths = [project.path, outbound_allowlist_project.path, both_allowlists_project.path]
+ inbound_paths = [project.path, inbound_allowlist_project.path, both_allowlists_project.path]
+
+ expect(returned_project_paths).to contain_exactly(*outbound_paths)
+ expect(returned_outbound_paths).to contain_exactly(*outbound_paths)
+ expect(returned_inbound_paths).to contain_exactly(*inbound_paths)
+ end
+ end
+
+ it_behaves_like 'returns projects'
+
+ context 'when job token scope is disabled' do
+ before do
+ project.ci_cd_settings.update!(job_token_scope_enabled: false)
+ end
+
+ it_behaves_like 'returns projects'
end
end
- context 'when linked project is not readable' do
+ context 'when linked projects are not readable' do
it 'returns readable projects in scope' do
expect(returned_project_paths).to contain_exactly(project.path)
+ expect(returned_outbound_paths).to contain_exactly(project.path)
+ expect(returned_inbound_paths).to contain_exactly(project.path)
end
end
@@ -71,6 +131,8 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
it 'returns readable projects in scope' do
expect(returned_project_paths).to contain_exactly(project.path)
+ expect(returned_outbound_paths).to contain_exactly(project.path)
+ expect(returned_inbound_paths).to contain_exactly(project.path)
end
end
end
diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb
index ce1558c4097..714eaebfe73 100644
--- a/spec/graphql/types/ci/job_type_spec.rb
+++ b/spec/graphql/types/ci/job_type_spec.rb
@@ -22,6 +22,7 @@ RSpec.describe Types::Ci::JobType do
detailedStatus
duration
downstreamPipeline
+ erasedAt
finished_at
id
kind
@@ -32,6 +33,7 @@ RSpec.describe Types::Ci::JobType do
pipeline
playable
previousStageJobsOrNeeds
+ project
queued_at
queued_duration
refName
diff --git a/spec/graphql/types/ci/pipeline_schedule_variable_type_spec.rb b/spec/graphql/types/ci/pipeline_schedule_variable_type_spec.rb
index 1c98539e308..2e5e6ad204f 100644
--- a/spec/graphql/types/ci/pipeline_schedule_variable_type_spec.rb
+++ b/spec/graphql/types/ci/pipeline_schedule_variable_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::Ci::PipelineScheduleVariableType do
+RSpec.describe Types::Ci::PipelineScheduleVariableType, feature_category: :continuous_integration do
specify { expect(described_class.graphql_name).to eq('PipelineScheduleVariable') }
specify { expect(described_class.interfaces).to contain_exactly(Types::Ci::VariableInterface) }
specify { expect(described_class).to require_graphql_authorizations(:read_pipeline_schedule_variables) }
diff --git a/spec/graphql/types/ci/pipeline_type_spec.rb b/spec/graphql/types/ci/pipeline_type_spec.rb
index 5683b3f86c4..67209874b54 100644
--- a/spec/graphql/types/ci/pipeline_type_spec.rb
+++ b/spec/graphql/types/ci/pipeline_type_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Types::Ci::PipelineType do
if Gitlab.ee?
expected_fields += %w[
security_report_summary security_report_findings security_report_finding
- code_quality_reports dast_profile
+ code_quality_reports dast_profile code_quality_report_summary
]
end
diff --git a/spec/graphql/types/ci/runner_architecture_type_spec.rb b/spec/graphql/types/ci/runner_architecture_type_spec.rb
index 60709acfd53..58ec73323c6 100644
--- a/spec/graphql/types/ci/runner_architecture_type_spec.rb
+++ b/spec/graphql/types/ci/runner_architecture_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::Ci::RunnerArchitectureType do
+RSpec.describe Types::Ci::RunnerArchitectureType, feature_category: :runner do
specify { expect(described_class.graphql_name).to eq('RunnerArchitecture') }
it 'exposes the expected fields' do
diff --git a/spec/graphql/types/ci/runner_platform_type_spec.rb b/spec/graphql/types/ci/runner_platform_type_spec.rb
index 29b8e885183..1b0f5a5ec71 100644
--- a/spec/graphql/types/ci/runner_platform_type_spec.rb
+++ b/spec/graphql/types/ci/runner_platform_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::Ci::RunnerPlatformType do
+RSpec.describe Types::Ci::RunnerPlatformType, feature_category: :runner_fleet do
specify { expect(described_class.graphql_name).to eq('RunnerPlatform') }
it 'exposes the expected fields' do
diff --git a/spec/graphql/types/ci/runner_setup_type_spec.rb b/spec/graphql/types/ci/runner_setup_type_spec.rb
index 197e717e964..d3e47b52a80 100644
--- a/spec/graphql/types/ci/runner_setup_type_spec.rb
+++ b/spec/graphql/types/ci/runner_setup_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::Ci::RunnerSetupType do
+RSpec.describe Types::Ci::RunnerSetupType, feature_category: :runner_fleet do
specify { expect(described_class.graphql_name).to eq('RunnerSetup') }
it 'exposes the expected fields' do
diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb
index b078d7f5fac..a2d107ae295 100644
--- a/spec/graphql/types/ci/runner_type_spec.rb
+++ b/spec/graphql/types/ci/runner_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['CiRunner'] do
+RSpec.describe GitlabSchema.types['CiRunner'], feature_category: :runner do
specify { expect(described_class.graphql_name).to eq('CiRunner') }
specify { expect(described_class).to require_graphql_authorizations(:read_runner) }
@@ -13,6 +13,7 @@ RSpec.describe GitlabSchema.types['CiRunner'] do
version short_sha revision locked run_untagged ip_address runner_type tag_list
project_count job_count admin_url edit_admin_url user_permissions executor_name architecture_name platform_name
maintenance_note maintenance_note_html groups projects jobs token_expires_at owner_project job_execution_status
+ ephemeral_authentication_token
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/ci/runner_upgrade_status_enum_spec.rb b/spec/graphql/types/ci/runner_upgrade_status_enum_spec.rb
index ef378f3fc5a..4aa9ad094a6 100644
--- a/spec/graphql/types/ci/runner_upgrade_status_enum_spec.rb
+++ b/spec/graphql/types/ci/runner_upgrade_status_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::Ci::RunnerUpgradeStatusEnum do
+RSpec.describe Types::Ci::RunnerUpgradeStatusEnum, feature_category: :runner_fleet do
let(:model_only_enum_values) { %w[not_processed] }
let(:expected_graphql_source_values) do
Ci::RunnerVersion.statuses.keys - model_only_enum_values
@@ -15,6 +15,7 @@ RSpec.describe Types::Ci::RunnerUpgradeStatusEnum do
expected_graphql_source_values
.map(&:upcase)
.map { |v| v == 'INVALID_VERSION' ? 'INVALID' : v }
+ .map { |v| v == 'UNAVAILABLE' ? 'NOT_AVAILABLE' : v }
)
end
diff --git a/spec/graphql/types/ci/runner_web_url_edge_spec.rb b/spec/graphql/types/ci/runner_web_url_edge_spec.rb
index 08718df0a5b..07a9655b3e1 100644
--- a/spec/graphql/types/ci/runner_web_url_edge_spec.rb
+++ b/spec/graphql/types/ci/runner_web_url_edge_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::Ci::RunnerWebUrlEdge do
+RSpec.describe Types::Ci::RunnerWebUrlEdge, feature_category: :runner_fleet do
specify { expect(described_class.graphql_name).to eq('RunnerWebUrlEdge') }
it 'contains URL attributes' do
diff --git a/spec/graphql/types/ci/variable_sort_enum_spec.rb b/spec/graphql/types/ci/variable_sort_enum_spec.rb
new file mode 100644
index 00000000000..1702360a21f
--- /dev/null
+++ b/spec/graphql/types/ci/variable_sort_enum_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::VariableSortEnum, feature_category: :pipeline_authoring do
+ it 'exposes the available order methods' do
+ expect(described_class.values).to match(
+ 'KEY_ASC' => have_attributes(value: :key_asc),
+ 'KEY_DESC' => have_attributes(value: :key_desc)
+ )
+ end
+end
diff --git a/spec/graphql/types/commit_signatures/verification_status_enum_spec.rb b/spec/graphql/types/commit_signatures/verification_status_enum_spec.rb
index cb7ce19c9fc..a0d99f5f0c1 100644
--- a/spec/graphql/types/commit_signatures/verification_status_enum_spec.rb
+++ b/spec/graphql/types/commit_signatures/verification_status_enum_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe GitlabSchema.types['VerificationStatus'] do
.to match_array(%w[
UNVERIFIED UNVERIFIED_KEY VERIFIED
SAME_USER_DIFFERENT_EMAIL OTHER_USER UNKNOWN_KEY
- MULTIPLE_SIGNATURES
+ MULTIPLE_SIGNATURES REVOKED_KEY
])
end
end
diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb
index 0b65778ce90..6820cf2738e 100644
--- a/spec/graphql/types/group_type_spec.rb
+++ b/spec/graphql/types/group_type_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe GitlabSchema.types['Group'] do
dependency_proxy_image_prefix dependency_proxy_image_ttl_policy
shared_runners_setting timelogs organization_state_counts organizations
contact_state_counts contacts work_item_types
- recent_issue_boards ci_variables
+ recent_issue_boards ci_variables releases
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -70,6 +70,13 @@ RSpec.describe GitlabSchema.types['Group'] do
it { is_expected.to have_graphql_resolver(Resolvers::Crm::OrganizationStateCountsResolver) }
end
+ describe 'releases field' do
+ subject { described_class.fields['releases'] }
+
+ it { is_expected.to have_graphql_type(Types::ReleaseType.connection_type) }
+ it { is_expected.to have_graphql_resolver(Resolvers::GroupReleasesResolver) }
+ end
+
it_behaves_like 'a GraphQL type with labels' do
let(:labels_resolver_arguments) { [:search_term, :includeAncestorGroups, :includeDescendantGroups, :onlyGroupLabels] }
end
diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb
index 498625dc642..7c6cf137a1e 100644
--- a/spec/graphql/types/issue_type_spec.rb
+++ b/spec/graphql/types/issue_type_spec.rb
@@ -228,29 +228,17 @@ RSpec.describe GitlabSchema.types['Issue'] do
subject { GitlabSchema.execute(query, context: { current_user: admin }).as_json }
- context 'when `ban_user_feature_flag` is enabled' do
- context 'when issue is hidden' do
- it 'returns `true`' do
- expect(subject.dig('data', 'project', 'issue', 'hidden')).to eq(true)
- end
- end
-
- context 'when issue is visible' do
- let(:issue) { visible_issue }
-
- it 'returns `false`' do
- expect(subject.dig('data', 'project', 'issue', 'hidden')).to eq(false)
- end
+ context 'when issue is hidden' do
+ it 'returns `true`' do
+ expect(subject.dig('data', 'project', 'issue', 'hidden')).to eq(true)
end
end
- context 'when `ban_user_feature_flag` is disabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
+ context 'when issue is visible' do
+ let(:issue) { visible_issue }
- it 'returns `nil`' do
- expect(subject.dig('data', 'project', 'issue', 'hidden')).to be_nil
+ it 'returns `false`' do
+ expect(subject.dig('data', 'project', 'issue', 'hidden')).to eq(false)
end
end
end
diff --git a/spec/graphql/types/notes/deleted_note_type_spec.rb b/spec/graphql/types/notes/deleted_note_type_spec.rb
new file mode 100644
index 00000000000..70985484e75
--- /dev/null
+++ b/spec/graphql/types/notes/deleted_note_type_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['DeletedNote'], feature_category: :team_planning do
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ id
+ discussion_id
+ last_discussion_note
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields).only
+ end
+end
diff --git a/spec/graphql/types/packages/package_details_type_spec.rb b/spec/graphql/types/packages/package_details_type_spec.rb
index d5688fc64c5..e4fe53f7660 100644
--- a/spec/graphql/types/packages/package_details_type_spec.rb
+++ b/spec/graphql/types/packages/package_details_type_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe GitlabSchema.types['PackageDetailsType'] do
it 'includes all the package fields' do
expected_fields = %w[
id name version created_at updated_at package_type tags project
- pipelines versions package_files dependency_links
+ pipelines versions package_files dependency_links public_package
npm_url maven_url conan_url nuget_url pypi_url pypi_setup_url
composer_url composer_config_repository_url
]
diff --git a/spec/graphql/types/permission_types/merge_request_spec.rb b/spec/graphql/types/permission_types/merge_request_spec.rb
index 2849dead9a8..2c5da9a933c 100644
--- a/spec/graphql/types/permission_types/merge_request_spec.rb
+++ b/spec/graphql/types/permission_types/merge_request_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Types::PermissionTypes::MergeRequest do
:read_merge_request, :admin_merge_request, :update_merge_request,
:create_note, :push_to_source_branch, :remove_source_branch,
:cherry_pick_on_current_merge_request, :revert_on_current_merge_request,
- :can_merge
+ :can_merge, :can_approve
]
expect(described_class).to have_graphql_fields(expected_permissions)
diff --git a/spec/graphql/types/permission_types/work_item_spec.rb b/spec/graphql/types/permission_types/work_item_spec.rb
index e604ce5d6e0..db6d78b1538 100644
--- a/spec/graphql/types/permission_types/work_item_spec.rb
+++ b/spec/graphql/types/permission_types/work_item_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Types::PermissionTypes::WorkItem do
it do
expected_permissions = [
- :read_work_item, :update_work_item, :delete_work_item
+ :read_work_item, :update_work_item, :delete_work_item, :admin_work_item
]
expected_permissions.each do |permission|
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 4151789372b..7f26190830e 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['Project'] do
include GraphqlHelpers
+ include ProjectForksHelper
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Project) }
@@ -37,7 +38,7 @@ RSpec.describe GitlabSchema.types['Project'] do
ci_template timelogs merge_commit_template squash_commit_template work_item_types
recent_issue_boards ci_config_path_or_default packages_cleanup_policy ci_variables
timelog_categories fork_targets branch_rules ci_config_variables pipeline_schedules languages
- incident_management_timeline_event_tags
+ incident_management_timeline_event_tags visible_forks
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -285,6 +286,17 @@ RSpec.describe GitlabSchema.types['Project'] do
end
end
end
+
+ context 'with empty repository' do
+ let_it_be(:project) { create(:project_empty_repo) }
+
+ it 'raises an error' do
+ expect(subject['errors'][0]['message']).to eq('You must <a target="_blank" rel="noopener noreferrer" ' \
+ 'href="http://localhost/help/user/project/repository/index.md#' \
+ 'add-files-to-a-repository">add at least one file to the ' \
+ 'repository</a> before using Security features.')
+ end
+ end
end
describe 'issue field' do
@@ -848,4 +860,54 @@ RSpec.describe GitlabSchema.types['Project'] do
end
end
end
+
+ describe 'visible_forks' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:fork_reporter) { fork_project(project, nil, { repository: true }) }
+ let_it_be(:fork_developer) { fork_project(project, nil, { repository: true }) }
+ let_it_be(:fork_group_developer) { fork_project(project, nil, { repository: true }) }
+ let_it_be(:fork_public) { fork_project(project, nil, { repository: true }) }
+ let_it_be(:fork_private) { fork_project(project, nil, { repository: true }) }
+
+ let(:minimum_access_level) { '' }
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ visibleForks#{minimum_access_level} {
+ nodes {
+ fullPath
+ }
+ }
+ }
+ }
+ )
+ end
+
+ let(:forks) do
+ subject.dig('data', 'project', 'visibleForks', 'nodes')
+ end
+
+ subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
+
+ before do
+ fork_reporter.add_reporter(user)
+ fork_developer.add_developer(user)
+ fork_group_developer.group.add_developer(user)
+ end
+
+ it 'contains all forks' do
+ expect(forks.count).to eq(5)
+ end
+
+ context 'with minimum_access_level DEVELOPER' do
+ let(:minimum_access_level) { '(minimumAccessLevel: DEVELOPER)' }
+
+ it 'contains forks with developer access' do
+ expect(forks).to contain_exactly(a_hash_including('fullPath' => fork_developer.full_path),
+a_hash_including('fullPath' => fork_group_developer.full_path))
+ end
+ end
+ end
end
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index f06759e30c8..100ecc94f35 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -2,49 +2,15 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['Query'] do
+RSpec.describe GitlabSchema.types['Query'], feature_category: :shared do
+ include_context 'with FOSS query type fields'
+
it 'is called Query' do
expect(described_class.graphql_name).to eq('Query')
end
it 'has the expected fields' do
- expected_fields = [
- :board_list,
- :ci_application_settings,
- :ci_config,
- :ci_variables,
- :container_repository,
- :current_user,
- :design_management,
- :echo,
- :gitpod_enabled,
- :group,
- :issue,
- :issues,
- :jobs,
- :merge_request,
- :metadata,
- :milestone,
- :namespace,
- :package,
- :project,
- :projects,
- :query_complexity,
- :runner,
- :runner_platforms,
- :runner_setup,
- :runners,
- :snippets,
- :timelogs,
- :todo,
- :topics,
- :usage_trends_measurements,
- :user,
- :users,
- :work_item
- ]
-
- expect(described_class).to have_graphql_fields(*expected_fields).at_least
+ expect(described_class).to have_graphql_fields(*expected_foss_fields).at_least
end
describe 'namespace field' do
diff --git a/spec/graphql/types/user_type_spec.rb b/spec/graphql/types/user_type_spec.rb
index 45cb960cf20..a6b5d454b60 100644
--- a/spec/graphql/types/user_type_spec.rb
+++ b/spec/graphql/types/user_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['User'], feature_category: :users do
+RSpec.describe GitlabSchema.types['User'], feature_category: :user_profile do
specify { expect(described_class.graphql_name).to eq('User') }
specify do
@@ -46,6 +46,7 @@ RSpec.describe GitlabSchema.types['User'], feature_category: :users do
preferencesGitpodPath
profileEnableGitpodPath
savedReplies
+ savedReply
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/users/email_type_spec.rb b/spec/graphql/types/users/email_type_spec.rb
index fb484915428..107bbf81e98 100644
--- a/spec/graphql/types/users/email_type_spec.rb
+++ b/spec/graphql/types/users/email_type_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe GitlabSchema.types['Email'], feature_category: :users do
+RSpec.describe GitlabSchema.types['Email'], feature_category: :user_profile do
it 'has the correct fields' do
expected_fields = [
:id,
diff --git a/spec/graphql/types/users/namespace_commit_email_type_spec.rb b/spec/graphql/types/users/namespace_commit_email_type_spec.rb
index ccab881676e..27e50f7285e 100644
--- a/spec/graphql/types/users/namespace_commit_email_type_spec.rb
+++ b/spec/graphql/types/users/namespace_commit_email_type_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe GitlabSchema.types['NamespaceCommitEmail'], feature_category: :users do
+RSpec.describe GitlabSchema.types['NamespaceCommitEmail'], feature_category: :user_profile do
it 'has the correct fields' do
expected_fields = [
:id,
diff --git a/spec/graphql/types/work_item_type_spec.rb b/spec/graphql/types/work_item_type_spec.rb
index dded96fde3a..42d56598944 100644
--- a/spec/graphql/types/work_item_type_spec.rb
+++ b/spec/graphql/types/work_item_type_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe GitlabSchema.types['WorkItem'] do
it 'has specific fields' do
fields = %i[
+ author
confidential
description
description_html