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-06-14 18:09:43 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-14 18:09:43 +0300
commit7a33080fff9a735cbe77968d67b13ffa92c0ffae (patch)
tree71a880649c8d3e551ec6bd94e93d08a9a9b5bde7 /spec/requests
parent9223573b85bcfdd21953f52e0d2c5cb587e366a1 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/requests')
-rw-r--r--spec/requests/api/graphql/users/set_namespace_commit_email_spec.rb106
-rw-r--r--spec/requests/api/project_packages_spec.rb243
2 files changed, 343 insertions, 6 deletions
diff --git a/spec/requests/api/graphql/users/set_namespace_commit_email_spec.rb b/spec/requests/api/graphql/users/set_namespace_commit_email_spec.rb
new file mode 100644
index 00000000000..1db6f83ce4f
--- /dev/null
+++ b/spec/requests/api/graphql/users/set_namespace_commit_email_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Setting namespace commit email', feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let(:current_user) { create(:user) }
+ let(:group) { create(:group, :public) }
+ let(:email) { create(:email, :confirmed, user: current_user) }
+ let(:input) { {} }
+ let(:namespace_id) { group.to_global_id }
+ let(:email_id) { email.to_global_id }
+
+ let(:resource_or_permission_error) do
+ "The resource that you are attempting to access does not exist or you don't have permission to perform this action"
+ end
+
+ let(:mutation) do
+ variables = {
+ namespace_id: namespace_id,
+ email_id: email_id
+ }
+ graphql_mutation(:user_set_namespace_commit_email, variables.merge(input),
+ <<-QL.strip_heredoc
+ namespaceCommitEmail {
+ email {
+ id
+ }
+ }
+ errors
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:user_set_namespace_commit_email)
+ end
+
+ shared_examples 'success' do
+ it 'creates a namespace commit email' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response.dig('namespaceCommitEmail', 'email', 'id')).to eq(email.to_global_id.to_s)
+ expect(graphql_errors).to be_nil
+ end
+ end
+
+ before do
+ group.add_reporter(current_user)
+ end
+
+ context 'when current_user is nil' do
+ it 'returns the top level error' do
+ post_graphql_mutation(mutation, current_user: nil)
+
+ expect(graphql_errors.first).to match a_hash_including(
+ 'message' => resource_or_permission_error)
+ end
+ end
+
+ context 'when the user cannot access the namespace' do
+ let(:namespace_id) { create(:group).to_global_id }
+
+ it 'returns the top level error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors).not_to be_empty
+ expect(graphql_errors.first).to match a_hash_including(
+ 'message' => resource_or_permission_error)
+ end
+ end
+
+ context 'when the service returns an error' do
+ let(:email_id) { create(:email).to_global_id }
+
+ it 'returns the error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['errors']).to contain_exactly("Email must be provided.")
+ expect(mutation_response['namespaceCommitEmail']).to be_nil
+ end
+ end
+
+ context 'when namespace is a group' do
+ it_behaves_like 'success'
+ end
+
+ context 'when namespace is a user' do
+ let(:namespace_id) { current_user.namespace.to_global_id }
+
+ it_behaves_like 'success'
+ end
+
+ context 'when namespace is a project' do
+ let_it_be(:project) { create(:project) }
+
+ let(:namespace_id) { project.project_namespace.to_global_id }
+
+ before do
+ project.add_reporter(current_user)
+ end
+
+ it_behaves_like 'success'
+ end
+end
diff --git a/spec/requests/api/project_packages_spec.rb b/spec/requests/api/project_packages_spec.rb
index c003ae9cd48..b84b7e9c52d 100644
--- a/spec/requests/api/project_packages_spec.rb
+++ b/spec/requests/api/project_packages_spec.rb
@@ -3,9 +3,11 @@
require 'spec_helper'
RSpec.describe API::ProjectPackages, feature_category: :package_registry do
- let_it_be(:project) { create(:project, :public) }
+ using RSpec::Parameterized::TableSyntax
- let(:user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project, :public) }
+
+ let_it_be(:user) { create(:user) }
let!(:package1) { create(:npm_package, :last_downloaded_at, project: project, version: '3.1.0', name: "@#{project.root_namespace.path}/foo1") }
let(:package_url) { "/projects/#{project.id}/packages/#{package1.id}" }
let!(:package2) { create(:nuget_package, project: project, version: '2.0.4') }
@@ -101,7 +103,7 @@ RSpec.describe API::ProjectPackages, feature_category: :package_registry do
end
context 'project is private' do
- let(:project) { create(:project, :private) }
+ let_it_be(:project) { create(:project, :private) }
context 'for unauthenticated user' do
it_behaves_like 'rejects packages access', :project, :no_type, :not_found
@@ -235,7 +237,7 @@ RSpec.describe API::ProjectPackages, feature_category: :package_registry do
expect do
get api(package_url, user)
- end.not_to exceed_query_limit(control)
+ end.not_to exceed_query_limit(control).with_threshold(4)
end
end
@@ -286,7 +288,7 @@ RSpec.describe API::ProjectPackages, feature_category: :package_registry do
end
context 'project is private' do
- let(:project) { create(:project, :private) }
+ let_it_be(:project) { create(:project, :private) }
it 'returns 404 for non authenticated user' do
get api(package_url)
@@ -362,6 +364,235 @@ RSpec.describe API::ProjectPackages, feature_category: :package_registry do
end
end
+ describe 'GET /projects/:id/packages/:package_id/pipelines' do
+ let(:package_pipelines_url) { "/projects/#{project.id}/packages/#{package1.id}/pipelines" }
+
+ let(:tokens) do
+ {
+ personal_access_token: personal_access_token.token,
+ job_token: job.token
+ }
+ end
+
+ let_it_be(:personal_access_token) { create(:personal_access_token) }
+ let_it_be(:user) { personal_access_token.user }
+ let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
+ let(:headers) { {} }
+
+ subject { get api(package_pipelines_url) }
+
+ shared_examples 'returns package pipelines' do |expected_status|
+ it 'returns the first page of package pipelines' do
+ subject
+
+ expect(response).to have_gitlab_http_status(expected_status)
+ expect(response).to match_response_schema('public_api/v4/packages/pipelines')
+ expect(json_response.length).to eq(3)
+ expect(json_response.pluck('id')).to eq(pipelines.reverse.map(&:id))
+ end
+ end
+
+ context 'without the need for a license' do
+ context 'when the package does not exist' do
+ let(:package_pipelines_url) { "/projects/#{project.id}/packages/0/pipelines" }
+
+ it_behaves_like 'returning response status', :not_found
+ end
+
+ context 'when there are no pipelines for the package' do
+ let(:package_pipelines_url) { "/projects/#{project.id}/packages/#{package2.id}/pipelines" }
+
+ it 'returns an empty response' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(response).to match_response_schema('public_api/v4/packages/pipelines')
+ expect(json_response.length).to eq(0)
+ end
+ end
+
+ context 'with valid package and pipelines' do
+ let!(:pipelines) do
+ create_list(:ci_pipeline, 3, user: user, project: project).each do |pipeline|
+ create(:package_build_info, package: package1, pipeline: pipeline)
+ end
+ end
+
+ where(:visibility, :user_role, :member, :token_type, :valid_token, :shared_examples_name, :expected_status) do
+ :public | :developer | true | :personal_access_token | true | 'returns package pipelines' | :success
+ :public | :guest | true | :personal_access_token | true | 'returns package pipelines' | :success
+ :public | :developer | true | :personal_access_token | false | 'returning response status' | :unauthorized
+ :public | :guest | true | :personal_access_token | false | 'returning response status' | :unauthorized
+ :public | :developer | false | :personal_access_token | true | 'returns package pipelines' | :success
+ :public | :guest | false | :personal_access_token | true | 'returns package pipelines' | :success
+ :public | :developer | false | :personal_access_token | false | 'returning response status' | :unauthorized
+ :public | :guest | false | :personal_access_token | false | 'returning response status' | :unauthorized
+ :public | :anonymous | false | nil | true | 'returns package pipelines' | :success
+ :private | :developer | true | :personal_access_token | true | 'returns package pipelines' | :success
+ :private | :guest | true | :personal_access_token | true | 'returning response status' | :forbidden
+ :private | :developer | true | :personal_access_token | false | 'returning response status' | :unauthorized
+ :private | :guest | true | :personal_access_token | false | 'returning response status' | :unauthorized
+ :private | :developer | false | :personal_access_token | true | 'returning response status' | :not_found
+ :private | :guest | false | :personal_access_token | true | 'returning response status' | :not_found
+ :private | :developer | false | :personal_access_token | false | 'returning response status' | :unauthorized
+ :private | :guest | false | :personal_access_token | false | 'returning response status' | :unauthorized
+ :private | :anonymous | false | nil | true | 'returning response status' | :not_found
+ :public | :developer | true | :job_token | true | 'returns package pipelines' | :success
+ :public | :guest | true | :job_token | true | 'returns package pipelines' | :success
+ :public | :developer | true | :job_token | false | 'returning response status' | :unauthorized
+ :public | :guest | true | :job_token | false | 'returning response status' | :unauthorized
+ :public | :developer | false | :job_token | true | 'returns package pipelines' | :success
+ :public | :guest | false | :job_token | true | 'returns package pipelines' | :success
+ :public | :developer | false | :job_token | false | 'returning response status' | :unauthorized
+ :public | :guest | false | :job_token | false | 'returning response status' | :unauthorized
+ :private | :developer | true | :job_token | true | 'returns package pipelines' | :success
+ # TODO uncomment the spec below when https://gitlab.com/gitlab-org/gitlab/-/issues/370998 is resolved
+ # :private | :guest | true | :job_token | true | 'returning response status' | :forbidden
+ :private | :developer | true | :job_token | false | 'returning response status' | :unauthorized
+ :private | :guest | true | :job_token | false | 'returning response status' | :unauthorized
+ :private | :developer | false | :job_token | true | 'returning response status' | :not_found
+ :private | :guest | false | :job_token | true | 'returning response status' | :not_found
+ :private | :developer | false | :job_token | false | 'returning response status' | :unauthorized
+ :private | :guest | false | :job_token | false | 'returning response status' | :unauthorized
+ end
+
+ with_them do
+ subject { get api(package_pipelines_url), headers: headers }
+
+ let(:invalid_token) { 'invalid-token123' }
+ let(:token) { valid_token ? tokens[token_type] : invalid_token }
+ let(:headers) do
+ case token_type
+ when :personal_access_token
+ { Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER => token }
+ when :job_token
+ { Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER => token }
+ when nil
+ {}
+ end
+ end
+
+ before do
+ project.update!(visibility: visibility.to_s)
+ project.send("add_#{user_role}", user) if member && user_role != :anonymous
+ end
+
+ it_behaves_like params[:shared_examples_name], params[:expected_status]
+ end
+ end
+
+ context 'pagination' do
+ shared_context 'setup pipeline records' do
+ let!(:pipelines) do
+ create_list(:package_build_info, 21, :with_pipeline, package: package1)
+ end
+ end
+
+ shared_examples 'returns the default number of pipelines' do
+ it do
+ subject
+
+ expect(json_response.size).to eq(20)
+ end
+ end
+
+ shared_examples 'returns an error about the invalid per_page value' do
+ it do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to match(/per_page does not have a valid value/)
+ end
+ end
+
+ context 'without pagination params' do
+ include_context 'setup pipeline records'
+
+ it_behaves_like 'returns the default number of pipelines'
+ end
+
+ context 'with valid per_page value' do
+ let(:per_page) { 11 }
+
+ subject { get api(package_pipelines_url, user), params: { per_page: per_page } }
+
+ include_context 'setup pipeline records'
+
+ it 'returns the correct number of pipelines' do
+ subject
+
+ expect(json_response.size).to eq(per_page)
+ end
+ end
+
+ context 'with invalid pagination params' do
+ subject { get api(package_pipelines_url, user), params: { per_page: per_page } }
+
+ context 'with non-positive per_page' do
+ let(:per_page) { -2 }
+
+ it_behaves_like 'returns an error about the invalid per_page value'
+ end
+
+ context 'with a too high value for per_page' do
+ let(:per_page) { 21 }
+
+ it_behaves_like 'returns an error about the invalid per_page value'
+ end
+ end
+
+ context 'with valid pagination params' do
+ let_it_be(:package1) { create(:npm_package, :last_downloaded_at, project: project) }
+ let_it_be(:build_info1) { create(:package_build_info, :with_pipeline, package: package1) }
+ let_it_be(:build_info2) { create(:package_build_info, :with_pipeline, package: package1) }
+ let_it_be(:build_info3) { create(:package_build_info, :with_pipeline, package: package1) }
+
+ let(:pipeline1) { build_info1.pipeline }
+ let(:pipeline2) { build_info2.pipeline }
+ let(:pipeline3) { build_info3.pipeline }
+
+ let(:per_page) { 2 }
+
+ context 'with no cursor supplied' do
+ subject { get api(package_pipelines_url, user), params: { per_page: per_page } }
+
+ it 'returns first 2 pipelines' do
+ subject
+
+ expect(json_response.pluck('id')).to contain_exactly(pipeline3.id, pipeline2.id)
+ end
+ end
+
+ context 'with a cursor parameter' do
+ let(:cursor) { Base64.urlsafe_encode64(Gitlab::Json.dump(cursor_attributes)) }
+
+ subject { get api(package_pipelines_url, user), params: { per_page: per_page, cursor: cursor } }
+
+ before do
+ subject
+ end
+
+ context 'with a cursor for the next page' do
+ let(:cursor_attributes) { { "id" => build_info2.id, "_kd" => "n" } }
+
+ it 'returns the next page of records' do
+ expect(json_response.pluck('id')).to contain_exactly(pipeline1.id)
+ end
+ end
+
+ context 'with a cursor for the previous page' do
+ let(:cursor_attributes) { { "id" => build_info1.id, "_kd" => "p" } }
+
+ it 'returns the previous page of records' do
+ expect(json_response.pluck('id')).to contain_exactly(pipeline3.id, pipeline2.id)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
describe 'DELETE /projects/:id/packages/:package_id' do
context 'without the need for a license' do
context 'project is public' do
@@ -379,7 +610,7 @@ RSpec.describe API::ProjectPackages, feature_category: :package_registry do
end
context 'project is private' do
- let(:project) { create(:project, :private) }
+ let_it_be(:project) { create(:project, :private) }
before do
expect(::Packages::Maven::Metadata::SyncWorker).not_to receive(:perform_async)