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/support/shared_examples/requests/api')
-rw-r--r--spec/support/shared_examples/requests/api/discussions_shared_examples.rb30
-rw-r--r--spec/support/shared_examples/requests/api/graphql/work_item_type_list_shared_examples.rb49
-rw-r--r--spec/support/shared_examples/requests/api/graphql_rest/milestones_shared_examples.rb83
-rw-r--r--spec/support/shared_examples/requests/api/hooks_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb118
-rw-r--r--spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb42
-rw-r--r--spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb68
-rw-r--r--spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb4
8 files changed, 320 insertions, 76 deletions
diff --git a/spec/support/shared_examples/requests/api/discussions_shared_examples.rb b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
index 2996c794e52..5cc87fb9654 100644
--- a/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
@@ -1,23 +1,29 @@
# frozen_string_literal: true
RSpec.shared_examples 'with cross-reference system notes' do
- let(:merge_request) { create(:merge_request) }
- let(:project) { merge_request.project }
- let(:new_merge_request) { create(:merge_request) }
- let(:commit) { new_merge_request.project.commit }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:pat) { create(:personal_access_token, user: user) }
+ let_it_be(:project) { create(:project, :small_repo) }
+ let_it_be(:project2) { create(:project, :small_repo) }
+ let_it_be(:project3) { create(:project, :small_repo) }
+
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+ let_it_be(:new_merge_request) { create(:merge_request, source_project: project2) }
+ let_it_be(:hidden_merge_request) { create(:merge_request, source_project: project3) }
+
let!(:note) { create(:system_note, noteable: merge_request, project: project, note: cross_reference) }
let!(:note_metadata) { create(:system_note_metadata, note: note, action: 'cross_reference') }
let(:cross_reference) { "test commit #{commit.to_reference(project)}" }
- let(:pat) { create(:personal_access_token, user: user) }
+ let(:commit) { new_merge_request.project.commit }
- before do
- project.add_developer(user)
- new_merge_request.project.add_developer(user)
+ let!(:new_note) { create(:system_note, noteable: merge_request, project: project, note: hidden_cross_reference) }
+ let!(:new_note_metadata) { create(:system_note_metadata, note: new_note, action: 'cross_reference') }
+ let(:hidden_cross_reference) { "test commit #{hidden_commit.to_reference(project)}" }
+ let(:hidden_commit) { hidden_merge_request.project.commit }
- hidden_merge_request = create(:merge_request)
- new_cross_reference = "test commit #{hidden_merge_request.project.commit.to_reference(project)}"
- new_note = create(:system_note, noteable: merge_request, project: project, note: new_cross_reference)
- create(:system_note_metadata, note: new_note, action: 'cross_reference')
+ before_all do
+ project.add_developer(user)
+ project2.add_developer(user)
end
it 'returns only the note that the user should see' do
diff --git a/spec/support/shared_examples/requests/api/graphql/work_item_type_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/work_item_type_list_shared_examples.rb
new file mode 100644
index 00000000000..beb3085a606
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/work_item_type_list_shared_examples.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'graphql work item type list request spec' do |context_name = nil|
+ include_context context_name || 'with work item types request context'
+
+ context 'when user has access to the group' do
+ it_behaves_like 'a working graphql query that returns data' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+ end
+
+ it 'returns all default work item types' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data_at(parent_key, :workItemTypes, :nodes)).to match_array(expected_work_item_type_response)
+ end
+
+ it 'prevents N+1 queries' do
+ # Destroy 2 existing types
+ WorkItems::Type.by_type([:issue, :task]).delete_all
+
+ post_graphql(query, current_user: current_user) # warm-up
+
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) { post_graphql(query, current_user: current_user) }
+ expect(graphql_errors).to be_blank
+
+ # Add back the 2 deleted types
+ expect do
+ Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.upsert_types
+ end.to change { WorkItems::Type.count }.by(2)
+
+ expect { post_graphql(query, current_user: current_user) }.to issue_same_number_of_queries_as(control)
+ expect(graphql_errors).to be_blank
+ end
+ end
+
+ context "when user doesn't have access to the parent" do
+ let(:current_user) { create(:user) }
+
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'does not return the parent' do
+ expect(graphql_data).to eq(parent_key.to_s => nil)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/graphql_rest/milestones_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql_rest/milestones_shared_examples.rb
new file mode 100644
index 00000000000..8e147f43091
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql_rest/milestones_shared_examples.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+# Examples for both GraphQL and REST APIs
+RSpec.shared_examples 'group milestones including ancestors and descendants' do
+ context 'for group milestones' do
+ let_it_be(:current_user) { create(:user) }
+
+ context 'when including descendant milestones in a public group' do
+ let_it_be(:group) { create(:group, :public) }
+
+ let(:params) { { include_descendants: true } }
+
+ it 'finds milestones only in accessible projects and groups' do
+ accessible_group = create(:group, :private, parent: group)
+ accessible_project = create(:project, group: accessible_group)
+ accessible_group.add_developer(current_user)
+ inaccessible_group = create(:group, :private, parent: group)
+ inaccessible_project = create(:project, :private, group: group)
+ milestone1 = create(:milestone, group: group)
+ milestone2 = create(:milestone, group: accessible_group)
+ milestone3 = create(:milestone, project: accessible_project)
+ create(:milestone, group: inaccessible_group)
+ create(:milestone, project: inaccessible_project)
+
+ milestone_ids = query_group_milestone_ids(params)
+
+ expect(milestone_ids).to match_array([milestone1, milestone2, milestone3].pluck(:id))
+ end
+ end
+
+ describe 'include_descendants and include_ancestors' do
+ let_it_be(:parent_group) { create(:group, :public) }
+ let_it_be(:group) { create(:group, :public, parent: parent_group) }
+ let_it_be(:accessible_group) { create(:group, :private, parent: group) }
+ let_it_be(:accessible_project) { create(:project, group: accessible_group) }
+ let_it_be(:inaccessible_group) { create(:group, :private, parent: group) }
+ let_it_be(:inaccessible_project) { create(:project, :private, group: group) }
+ let_it_be(:milestone1) { create(:milestone, group: group) }
+ let_it_be(:milestone2) { create(:milestone, group: accessible_group) }
+ let_it_be(:milestone3) { create(:milestone, project: accessible_project) }
+ let_it_be(:milestone4) { create(:milestone, group: inaccessible_group) }
+ let_it_be(:milestone5) { create(:milestone, project: inaccessible_project) }
+ let_it_be(:milestone6) { create(:milestone, group: parent_group) }
+
+ before_all do
+ accessible_group.add_developer(current_user)
+ end
+
+ context 'when including neither ancestor nor descendant milestones in a public group' do
+ let(:params) { {} }
+
+ it 'finds milestones only in accessible projects and groups' do
+ expect(query_group_milestone_ids(params)).to match_array([milestone1.id])
+ end
+ end
+
+ context 'when including descendant milestones in a public group' do
+ let(:params) { { include_descendants: true } }
+
+ it 'finds milestones only in accessible projects and groups' do
+ expect(query_group_milestone_ids(params)).to match_array([milestone1, milestone2, milestone3].pluck(:id))
+ end
+ end
+
+ context 'when including ancestor milestones in a public group' do
+ let(:params) { { include_ancestors: true } }
+
+ it 'finds milestones only in accessible projects and groups' do
+ expect(query_group_milestone_ids(params)).to match_array([milestone1, milestone6].pluck(:id))
+ end
+ end
+
+ context 'when including both ancestor and descendant milestones in a public group' do
+ let(:params) { { include_descendants: true, include_ancestors: true } }
+
+ it 'finds milestones only in accessible projects and groups' do
+ expect(query_group_milestone_ids(params))
+ .to match_array([milestone1, milestone2, milestone3, milestone6].pluck(:id))
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/hooks_shared_examples.rb b/spec/support/shared_examples/requests/api/hooks_shared_examples.rb
index 7489dc7c1d6..de458bc87db 100644
--- a/spec/support/shared_examples/requests/api/hooks_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/hooks_shared_examples.rb
@@ -84,7 +84,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix|
end
end
- context 'the hook has URL variables' do
+ context 'the hook has URL variables', if: prefix != '/projects/:id' do
before do
hook.update!(url_variables: { 'token' => 'supers3cret' })
end
diff --git a/spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb b/spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb
index 7978f43610d..5ae0b8b10b6 100644
--- a/spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb
@@ -1,5 +1,53 @@
# frozen_string_literal: true
+RSpec.shared_examples 'MLflow|an endpoint that requires authentication' do
+ context 'when not authenticated' do
+ let(:headers) { {} }
+
+ it "is Unauthorized" do
+ is_expected.to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'when user does not have access' do
+ let(:access_token) { tokens[:different_user] }
+
+ it "is Not Found" do
+ is_expected.to have_gitlab_http_status(:not_found)
+ end
+ end
+end
+
+RSpec.shared_examples 'MLflow|an endpoint that requires read_model_registry' do
+ context 'when user does not have read_model_registry' do
+ before do
+ allow(Ability).to receive(:allowed?).and_call_original
+ allow(Ability).to receive(:allowed?)
+ .with(current_user, :read_model_registry, project)
+ .and_return(false)
+ end
+
+ it "is Not Found" do
+ is_expected.to have_gitlab_http_status(:not_found)
+ end
+ end
+end
+
+RSpec.shared_examples 'MLflow|an endpoint that requires write_model_registry' do
+ context 'when user does not have read_model_registry' do
+ before do
+ allow(Ability).to receive(:allowed?).and_call_original
+ allow(Ability).to receive(:allowed?)
+ .with(current_user, :write_model_registry, project)
+ .and_return(false)
+ end
+
+ it "is Not Found" do
+ is_expected.to have_gitlab_http_status(:unauthorized)
+ end
+ end
+end
+
RSpec.shared_examples 'MLflow|Not Found - Resource Does Not Exist' do
it "is Resource Does Not Exist", :aggregate_failures do
is_expected.to have_gitlab_http_status(:not_found)
@@ -44,21 +92,7 @@ RSpec.shared_examples 'MLflow|Bad Request' do
end
RSpec.shared_examples 'MLflow|shared error cases' do
- context 'when not authenticated' do
- let(:headers) { {} }
-
- it "is Unauthorized" do
- is_expected.to have_gitlab_http_status(:unauthorized)
- end
- end
-
- context 'when user does not have access' do
- let(:access_token) { tokens[:different_user] }
-
- it "is Not Found" do
- is_expected.to have_gitlab_http_status(:not_found)
- end
- end
+ it_behaves_like 'MLflow|an endpoint that requires authentication'
context 'when model experiments is unavailable' do
before do
@@ -75,34 +109,8 @@ RSpec.shared_examples 'MLflow|shared error cases' do
end
RSpec.shared_examples 'MLflow|shared model registry error cases' do
- context 'when not authenticated' do
- let(:headers) { {} }
-
- it "is Unauthorized" do
- is_expected.to have_gitlab_http_status(:unauthorized)
- end
- end
-
- context 'when user does not have access' do
- let(:access_token) { tokens[:different_user] }
-
- it "is Not Found" do
- is_expected.to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when model registry is unavailable' do
- before do
- allow(Ability).to receive(:allowed?).and_call_original
- allow(Ability).to receive(:allowed?)
- .with(current_user, :read_model_registry, project)
- .and_return(false)
- end
-
- it "is Not Found" do
- is_expected.to have_gitlab_http_status(:not_found)
- end
- end
+ it_behaves_like 'MLflow|an endpoint that requires authentication'
+ it_behaves_like 'MLflow|an endpoint that requires read_model_registry'
end
RSpec.shared_examples 'MLflow|Bad Request on missing required' do |keys|
@@ -110,9 +118,27 @@ RSpec.shared_examples 'MLflow|Bad Request on missing required' do |keys|
context "when \"#{key}\" is missing" do
let(:params) { default_params.tap { |p| p.delete(key) } }
- it "is Bad Request" do
- is_expected.to have_gitlab_http_status(:bad_request)
- end
+ it_behaves_like 'MLflow|Bad Request'
end
end
end
+
+RSpec.shared_examples 'MLflow|an invalid request' do
+ it_behaves_like 'MLflow|Bad Request'
+end
+
+RSpec.shared_examples 'MLflow|an authenticated resource' do
+ it_behaves_like 'MLflow|an endpoint that requires authentication'
+ it_behaves_like 'MLflow|Requires read_api scope'
+end
+
+RSpec.shared_examples 'MLflow|a read-only model registry resource' do
+ it_behaves_like 'MLflow|an endpoint that requires authentication'
+ it_behaves_like 'MLflow|an endpoint that requires read_model_registry'
+end
+
+RSpec.shared_examples 'MLflow|a read/write model registry resource' do
+ it_behaves_like 'MLflow|an endpoint that requires authentication'
+ it_behaves_like 'MLflow|an endpoint that requires read_model_registry'
+ it_behaves_like 'MLflow|an endpoint that requires write_model_registry'
+end
diff --git a/spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb
index 47cbd268a65..30a1398bf94 100644
--- a/spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb
@@ -15,11 +15,31 @@ RSpec.shared_examples 'Endpoint not found if read_model_registry not available'
end
end
-RSpec.shared_examples 'creates model experiments package files' do
+RSpec.shared_examples 'Endpoint not found if write_model_registry not available' do
+ context 'when write_model_registry is disabled for current project' do
+ before do
+ allow(Ability).to receive(:allowed?).and_call_original
+ allow(Ability).to receive(:allowed?)
+ .with(user, :write_model_registry, project)
+ .and_return(false)
+ end
+
+ it { is_expected.to have_gitlab_http_status(:not_found) }
+ end
+end
+
+RSpec.shared_examples 'Not found when model version does not exist' do
+ context 'when model version does not exist' do
+ let(:version) { "#{non_existing_record_id}.0.0" }
+
+ it { is_expected.to have_gitlab_http_status(:not_found) }
+ end
+end
+
+RSpec.shared_examples 'creates package files for model versions' do
it 'creates package files', :aggregate_failures do
expect { api_response }
- .to change { project.packages.count }.by(1)
- .and change { Packages::PackageFile.count }.by(1)
+ .to change { Packages::PackageFile.count }.by(1)
expect(api_response).to have_gitlab_http_status(:created)
package_file = project.packages.last.package_files.reload.last
@@ -59,7 +79,7 @@ RSpec.shared_examples 'process ml model package upload' do
context 'with correct params' do
it_behaves_like 'package workhorse uploads'
- it_behaves_like 'creates model experiments package files'
+ it_behaves_like 'creates package files for model versions'
# To be reactivated with https://gitlab.com/gitlab-org/gitlab/-/issues/414270
# it_behaves_like 'a package tracking event', '::API::MlModelPackages', 'push_package'
end
@@ -81,7 +101,7 @@ RSpec.shared_examples 'process ml model package upload' do
stub_package_file_object_storage(direct_upload: true)
end
- it_behaves_like 'creates model experiments package files'
+ it_behaves_like 'creates package files for model versions'
['123123', '../../123123'].each do |remote_id|
context "with invalid remote_id: #{remote_id}" do
@@ -102,7 +122,7 @@ RSpec.shared_examples 'process ml model package upload' do
stub_package_file_object_storage(direct_upload: false)
end
- it_behaves_like 'creates model experiments package files'
+ it_behaves_like 'creates package files for model versions'
end
end
end
@@ -112,13 +132,5 @@ RSpec.shared_examples 'process ml model package download' do
it { is_expected.to have_gitlab_http_status(:success) }
end
- context 'when record does not exist' do
- it 'response is not found' do
- expect_next_instance_of(::Packages::MlModel::PackageFinder) do |instance|
- expect(instance).to receive(:execute!).and_raise(ActiveRecord::RecordNotFound)
- end
-
- expect(api_response).to have_gitlab_http_status(:not_found)
- end
- end
+ it_behaves_like 'Not found when model version does not exist'
end
diff --git a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
index c23d514abfc..8281b7d4024 100644
--- a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
@@ -741,3 +741,71 @@ RSpec.shared_examples 'process nuget delete request' do |user_type, status|
end
end
end
+
+RSpec.shared_examples 'nuget symbol file endpoint' do
+ let_it_be(:symbol) { create(:nuget_symbol) }
+ let_it_be(:filename) { symbol.file.filename }
+ let_it_be(:signature) { symbol.signature }
+ let_it_be(:checksum) { symbol.file_sha256.delete("\n") }
+
+ let(:headers) { { 'Symbolchecksum' => "SHA256:#{checksum}" } }
+
+ subject { get api(url), headers: headers }
+
+ it { is_expected.to have_request_urgency(:low) }
+
+ context 'with nuget_symbol_server_enabled setting enabled' do
+ before do
+ allow_next_instance_of(::Namespace::PackageSetting) do |setting|
+ allow(setting).to receive(:nuget_symbol_server_enabled).and_return(true)
+ end
+ end
+
+ context 'with valid target' do
+ it 'returns the symbol file' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.media_type).to eq('application/octet-stream')
+ expect(response.body).to eq(symbol.file.read)
+ end
+ end
+
+ context 'when target does not exist' do
+ let(:target) { double(id: 1234567890) }
+
+ it_behaves_like 'returning response status', :not_found
+ end
+
+ context 'when target exists' do
+ context 'when symbol file does not exist' do
+ let(:filename) { 'non-existent-file.pdb' }
+ let(:signature) { 'non-existent-signature' }
+
+ it_behaves_like 'returning response status', :not_found
+ end
+
+ context 'when symbol file checksum does not match' do
+ let(:checksum) { 'non-matching-checksum' }
+
+ it_behaves_like 'returning response status', :not_found
+ end
+
+ context 'when symbol file checksum is missing' do
+ let(:headers) { {} }
+
+ it_behaves_like 'returning response status', :bad_request
+ end
+ end
+ end
+
+ context 'with nuget_symbol_server_enabled setting disabled' do
+ before do
+ allow_next_instance_of(::Namespace::PackageSetting) do |setting|
+ allow(setting).to receive(:nuget_symbol_server_enabled).and_return(false)
+ end
+ end
+
+ it_behaves_like 'returning response status', :forbidden
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb b/spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb
index 181bab41e09..f400c5fa201 100644
--- a/spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb
@@ -90,7 +90,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type|
end
before do
- stub_storage_settings('test_second_storage' => { 'path' => 'tmp/tests/extra_storage' })
+ stub_storage_settings('test_second_storage' => {})
end
it 'schedules a container repository storage move' do
@@ -203,7 +203,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type|
end
before do
- stub_storage_settings('test_second_storage' => { 'path' => 'tmp/tests/extra_storage' })
+ stub_storage_settings('test_second_storage' => {})
end
it 'schedules the worker' do