diff options
Diffstat (limited to 'spec/support/shared_examples/requests/api')
29 files changed, 701 insertions, 409 deletions
diff --git a/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb b/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb index f5c41416763..3ff52166990 100644 --- a/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb @@ -18,7 +18,7 @@ RSpec.shared_examples 'returns repositories for allowed users' do |user_type, sc subject expect(json_response.length).to eq(2) - expect(json_response.map { |repository| repository['id'] }).to contain_exactly( + expect(json_response.pluck('id')).to contain_exactly( root_repository.id, test_repository.id) expect(response.body).not_to include('tags') expect(response.body).not_to include('tags_count') @@ -47,7 +47,7 @@ RSpec.shared_examples 'returns tags for allowed users' do |user_type, scope| subject expect(json_response.length).to eq(2) - expect(json_response.map { |repository| repository['id'] }).to contain_exactly( + expect(json_response.pluck('id')).to contain_exactly( root_repository.id, test_repository.id) expect(response.body).to include('tags') end diff --git a/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb b/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb index f31cbcfdec1..804221b7416 100644 --- a/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb @@ -4,7 +4,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| let!(:custom_attribute1) { attributable.custom_attributes.create! key: 'foo', value: 'foo' } let!(:custom_attribute2) { attributable.custom_attributes.create! key: 'bar', value: 'bar' } - describe "GET /#{attributable_name} with custom attributes filter" do + describe "GET /#{attributable_name} with custom attributes filter", :aggregate_failures do before do other_attributable end @@ -14,13 +14,13 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| get api("/#{attributable_name}", user), params: { custom_attributes: { foo: 'foo', bar: 'bar' } } expect(response).to have_gitlab_http_status(:ok) - expect(json_response.map { |r| r['id'] }).to include(attributable.id, other_attributable.id) + expect(json_response.pluck('id')).to include(attributable.id, other_attributable.id) end end context 'with an authorized user' do it 'filters by custom attributes' do - get api("/#{attributable_name}", admin), params: { custom_attributes: { foo: 'foo', bar: 'bar' } } + get api("/#{attributable_name}", admin, admin_mode: true), params: { custom_attributes: { foo: 'foo', bar: 'bar' } } expect(response).to have_gitlab_http_status(:ok) expect(json_response.size).to be 1 @@ -29,7 +29,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| end end - describe "GET /#{attributable_name} with custom attributes" do + describe "GET /#{attributable_name} with custom attributes", :aggregate_failures do before do other_attributable end @@ -46,7 +46,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| context 'with an authorized user' do it 'does not include custom attributes by default' do - get api("/#{attributable_name}", admin) + get api("/#{attributable_name}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(json_response).not_to be_empty @@ -54,7 +54,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| end it 'includes custom attributes if requested' do - get api("/#{attributable_name}", admin), params: { with_custom_attributes: true } + get api("/#{attributable_name}", admin, admin_mode: true), params: { with_custom_attributes: true } expect(response).to have_gitlab_http_status(:ok) expect(json_response).not_to be_empty @@ -72,7 +72,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| end end - describe "GET /#{attributable_name}/:id with custom attributes" do + describe "GET /#{attributable_name}/:id with custom attributes", :aggregate_failures do context 'with an unauthorized user' do it 'does not include custom attributes' do get api("/#{attributable_name}/#{attributable.id}", user), params: { with_custom_attributes: true } @@ -84,14 +84,14 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| context 'with an authorized user' do it 'does not include custom attributes by default' do - get api("/#{attributable_name}/#{attributable.id}", admin) + get api("/#{attributable_name}/#{attributable.id}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(json_response).not_to include 'custom_attributes' end it 'includes custom attributes if requested' do - get api("/#{attributable_name}/#{attributable.id}", admin), params: { with_custom_attributes: true } + get api("/#{attributable_name}/#{attributable.id}", admin, admin_mode: true), params: { with_custom_attributes: true } expect(response).to have_gitlab_http_status(:ok) expect(json_response['custom_attributes']).to contain_exactly( @@ -102,7 +102,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| end end - describe "GET /#{attributable_name}/:id/custom_attributes" do + describe "GET /#{attributable_name}/:id/custom_attributes", :aggregate_failures do context 'with an unauthorized user' do subject { get api("/#{attributable_name}/#{attributable.id}/custom_attributes", user) } @@ -111,7 +111,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| context 'with an authorized user' do it 'returns all custom attributes' do - get api("/#{attributable_name}/#{attributable.id}/custom_attributes", admin) + get api("/#{attributable_name}/#{attributable.id}/custom_attributes", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(json_response).to contain_exactly( @@ -122,7 +122,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| end end - describe "GET /#{attributable_name}/:id/custom_attributes/:key" do + describe "GET /#{attributable_name}/:id/custom_attributes/:key", :aggregate_failures do context 'with an unauthorized user' do subject { get api("/#{attributable_name}/#{attributable.id}/custom_attributes/foo", user) } @@ -131,7 +131,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| context 'with an authorized user' do it 'returns a single custom attribute' do - get api("/#{attributable_name}/#{attributable.id}/custom_attributes/foo", admin) + get api("/#{attributable_name}/#{attributable.id}/custom_attributes/foo", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(json_response).to eq({ 'key' => 'foo', 'value' => 'foo' }) @@ -139,7 +139,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| end end - describe "PUT /#{attributable_name}/:id/custom_attributes/:key" do + describe "PUT /#{attributable_name}/:id/custom_attributes/:key", :aggregate_failures do context 'with an unauthorized user' do subject { put api("/#{attributable_name}/#{attributable.id}/custom_attributes/foo", user), params: { value: 'new' } } @@ -149,7 +149,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| context 'with an authorized user' do it 'creates a new custom attribute' do expect do - put api("/#{attributable_name}/#{attributable.id}/custom_attributes/new", admin), params: { value: 'new' } + put api("/#{attributable_name}/#{attributable.id}/custom_attributes/new", admin, admin_mode: true), params: { value: 'new' } end.to change { attributable.custom_attributes.count }.by(1) expect(response).to have_gitlab_http_status(:ok) @@ -159,7 +159,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| it 'updates an existing custom attribute' do expect do - put api("/#{attributable_name}/#{attributable.id}/custom_attributes/foo", admin), params: { value: 'new' } + put api("/#{attributable_name}/#{attributable.id}/custom_attributes/foo", admin, admin_mode: true), params: { value: 'new' } end.not_to change { attributable.custom_attributes.count } expect(response).to have_gitlab_http_status(:ok) @@ -169,7 +169,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| end end - describe "DELETE /#{attributable_name}/:id/custom_attributes/:key" do + describe "DELETE /#{attributable_name}/:id/custom_attributes/:key", :aggregate_failures do context 'with an unauthorized user' do subject { delete api("/#{attributable_name}/#{attributable.id}/custom_attributes/foo", user) } @@ -179,7 +179,7 @@ RSpec.shared_examples 'custom attributes endpoints' do |attributable_name| context 'with an authorized user' do it 'deletes an existing custom attribute' do expect do - delete api("/#{attributable_name}/#{attributable.id}/custom_attributes/foo", admin) + delete api("/#{attributable_name}/#{attributable.id}/custom_attributes/foo", admin, admin_mode: true) end.to change { attributable.custom_attributes.count }.by(-1) expect(response).to have_gitlab_http_status(:no_content) diff --git a/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb index 6d29076da0f..bc7ad570441 100644 --- a/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb @@ -165,3 +165,41 @@ RSpec.shared_examples 'Debian packages write endpoint' do |desired_behavior, suc it_behaves_like 'rejects Debian access with unknown container id', :unauthorized, :basic end + +RSpec.shared_examples 'Debian packages endpoint catching ObjectStorage::RemoteStoreError' do + include_context 'Debian repository access', :public, :developer, :basic do + it "returns forbidden" do + expect(::Packages::Debian::CreatePackageFileService).to receive(:new).and_raise ObjectStorage::RemoteStoreError + + subject + + expect(response).to have_gitlab_http_status(:forbidden) + end + end +end + +RSpec.shared_examples 'Debian packages index endpoint' do |success_body| + it_behaves_like 'Debian packages read endpoint', 'GET', :success, success_body + + context 'when no ComponentFile is found' do + let(:target_component_name) { component.name + FFaker::Lorem.word } + + it_behaves_like 'Debian packages read endpoint', 'GET', :no_content, /^$/ + end +end + +RSpec.shared_examples 'Debian packages index sha256 endpoint' do |success_body| + it_behaves_like 'Debian packages read endpoint', 'GET', :success, success_body + + context 'with empty checksum' do + let(:target_sha256) { 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' } + + it_behaves_like 'Debian packages read endpoint', 'GET', :no_content, /^$/ + end + + context 'when ComponentFile is not found' do + let(:target_component_name) { component.name + FFaker::Lorem.word } + + it_behaves_like 'Debian packages read endpoint', 'GET', :not_found, /^{"message":"404 Not Found"}$/ + end +end 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 f577e2ad323..2996c794e52 100644 --- a/spec/support/shared_examples/requests/api/discussions_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb @@ -123,18 +123,6 @@ RSpec.shared_examples 'discussions API' do |parent_type, noteable_type, id_name, expect_snowplow_event(category: 'Notes::CreateService', action: 'execute', label: 'note', value: anything) end - context 'with notes_create_service_tracking feature flag disabled' do - before do - stub_feature_flags(notes_create_service_tracking: false) - end - - it 'does not track Notes::CreateService events', :snowplow do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), params: { body: 'hi!' } - - expect_no_snowplow_event(category: 'Notes::CreateService', action: 'execute') - end - end - context 'when an admin or owner makes the request' do it 'accepts the creation date to be set' do creation_time = 2.weeks.ago @@ -243,8 +231,7 @@ RSpec.shared_examples 'discussions API' do |parent_type, noteable_type, id_name, it 'returns a 404 error when note id not found' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}/notes/#{non_existing_record_id}", user), - params: { body: 'Hello!' } + "discussions/#{note.discussion_id}/notes/#{non_existing_record_id}", user), params: { body: 'Hello!' } expect(response).to have_gitlab_http_status(:not_found) end diff --git a/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb index 6c8b792bf92..930c47dac52 100644 --- a/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb @@ -480,6 +480,7 @@ RSpec.shared_examples 'graphql issue list request spec' do context 'when fetching escalation status' do let_it_be(:escalation_status) { create(:incident_management_issuable_escalation_status, issue: issue_a) } + let_it_be(:incident_type) { WorkItems::Type.default_by_type(:incident) } let(:fields) do <<~QUERY @@ -491,7 +492,7 @@ RSpec.shared_examples 'graphql issue list request spec' do end before do - issue_a.update_columns(issue_type: Issue.issue_types[:incident]) + issue_a.update_columns(issue_type: WorkItems::Type.base_types[:incident], work_item_type_id: incident_type.id) end it 'returns the escalation status values' do diff --git a/spec/support/shared_examples/requests/api/graphql/mutations/snippets_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/mutations/snippets_shared_examples.rb index b459e479c91..53329c5caec 100644 --- a/spec/support/shared_examples/requests/api/graphql/mutations/snippets_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/graphql/mutations/snippets_shared_examples.rb @@ -6,7 +6,7 @@ RSpec.shared_examples 'when the snippet is not found' do end it_behaves_like 'a mutation that returns top-level errors', - errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR] + errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR] end RSpec.shared_examples 'snippet edit usage data counters' do diff --git a/spec/support/shared_examples/requests/api/graphql/mutations/subscription_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/mutations/subscription_shared_examples.rb index 40b88ef370f..4dc0264172f 100644 --- a/spec/support/shared_examples/requests/api/graphql/mutations/subscription_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/graphql/mutations/subscription_shared_examples.rb @@ -36,9 +36,9 @@ RSpec.shared_examples 'a subscribable resource api' do context 'when the user is not authorized' do it_behaves_like 'a mutation that returns top-level errors', - errors: ["The resource that you are attempting to access "\ - "does not exist or you don't have permission to "\ - "perform this action"] + errors: ["The resource that you are attempting to access "\ + "does not exist or you don't have permission to "\ + "perform this action"] end context 'when user is authorized' do diff --git a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb index f5835460a77..5e9dfc826d4 100644 --- a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb @@ -279,11 +279,11 @@ RSpec.shared_examples 'group and project packages query' do end def npm_pipeline_ids - graphql_data_npm_package.dig('pipelines', 'nodes').map { |pipeline| pipeline['id'] } + graphql_data_npm_package.dig('pipelines', 'nodes').pluck('id') end def composer_pipeline_ids - graphql_data_composer_package.dig('pipelines', 'nodes').map { |pipeline| pipeline['id'] } + graphql_data_composer_package.dig('pipelines', 'nodes').pluck('id') end def graphql_data_npm_package diff --git a/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb index b4019d7c232..161f4a02b8c 100644 --- a/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb @@ -38,7 +38,7 @@ RSpec.shared_examples 'a package with files' do context 'with package files pending destruction' do let_it_be(:package_file_pending_destruction) { create(:package_file, :pending_destruction, package: package) } - let(:response_package_file_ids) { package_files_response.map { |pf| pf['id'] } } + let(:response_package_file_ids) { package_files_response.pluck('id') } it 'does not return them' do expect(package.reload.package_files).to include(package_file_pending_destruction) diff --git a/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb b/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb index 6b4d8cae2ce..6648c18fb70 100644 --- a/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb +++ b/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb @@ -13,13 +13,15 @@ RSpec.shared_examples 'a GraphQL query for access levels' do |access_level_kind| let(:maintainer_access_level) { access_levels.for_role.first } let(:maintainer_access_level_data) { access_levels_data.first } let(:access_levels_data) do - graphql_data_at('project', - 'branchRules', - 'nodes', - 0, - 'branchProtection', - "#{access_level_kind.to_s.camelize(:lower)}AccessLevels", - 'nodes') + graphql_data_at( + 'project', + 'branchRules', + 'nodes', + 0, + 'branchProtection', + "#{access_level_kind.to_s.camelize(:lower)}AccessLevels", + 'nodes' + ) end let(:query) do 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 f2002de4b55..a2c34aa6a54 100644 --- a/spec/support/shared_examples/requests/api/hooks_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/hooks_shared_examples.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true RSpec.shared_examples 'web-hook API endpoints test hook' do |prefix| - describe "POST #{prefix}/:hook_id" do + describe "POST #{prefix}/:hook_id", :aggregate_failures do it 'tests the hook' do expect(WebHookService) .to receive(:new).with(hook, anything, String, force: false) .and_return(instance_double(WebHookService, execute: nil)) - post api(hook_uri, user) + post api(hook_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:created) end @@ -17,7 +17,7 @@ end RSpec.shared_examples 'web-hook API endpoints with branch-filter' do |prefix| describe "POST #{prefix}/hooks" do it "returns a 422 error if branch filter is not valid" do - post api(collection_uri, user), + post api(collection_uri, user, admin_mode: user.admin?), params: { url: "http://example.com", push_events_branch_filter: '~badbranchname/' } expect(response).to have_gitlab_http_status(:unprocessable_entity) @@ -58,10 +58,10 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| let(:default_values) { {} } - describe "GET #{prefix}/hooks" do + describe "GET #{prefix}/hooks", :aggregate_failures do context "authorized user" do it "returns all hooks" do - get api(collection_uri, user) + get api(collection_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_collection_schema @@ -70,7 +70,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| context "when user is forbidden" do it "prevents access to hooks" do - get api(collection_uri, unauthorized_user) + get api(collection_uri, unauthorized_user, admin_mode: true) expect(response).to have_gitlab_http_status(:forbidden) end @@ -90,7 +90,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| end it 'returns the names of the url variables' do - get api(collection_uri, user) + get api(collection_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:ok) expect(json_response).to contain_exactly( @@ -102,10 +102,10 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| end end - describe "GET #{prefix}/hooks/:hook_id" do + describe "GET #{prefix}/hooks/:hook_id", :aggregate_failures do context "authorized user" do it "returns a project hook" do - get api(hook_uri, user) + get api(hook_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_hook_schema @@ -114,7 +114,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| end it "returns a 404 error if hook id is not available" do - get api(hook_uri(non_existing_record_id), user) + get api(hook_uri(non_existing_record_id), user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end @@ -125,7 +125,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| end it "has the correct alert status", :aggregate_failures do - get api(hook_uri, user) + get api(hook_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:ok) @@ -135,12 +135,12 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| context 'the hook is backed-off' do before do - WebHook::FAILURE_THRESHOLD.times { hook.backoff! } + WebHooks::AutoDisabling::FAILURE_THRESHOLD.times { hook.backoff! } hook.backoff! end it "has the correct alert status", :aggregate_failures do - get api(hook_uri, user) + get api(hook_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:ok) @@ -156,7 +156,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| context "when user is forbidden" do it "does not access an existing hook" do - get api(hook_uri, unauthorized_user) + get api(hook_uri, unauthorized_user, admin_mode: true) expect(response).to have_gitlab_http_status(:forbidden) end @@ -171,13 +171,12 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| end end - describe "POST #{prefix}/hooks" do + describe "POST #{prefix}/hooks", :aggregate_failures do let(:hook_creation_params) { hook_params } it "adds hook", :aggregate_failures do expect do - post api(collection_uri, user), - params: hook_creation_params + post api(collection_uri, user, admin_mode: user.admin?), params: hook_creation_params end.to change { hooks_count }.by(1) expect(response).to have_gitlab_http_status(:created) @@ -201,8 +200,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| token = "secret token" expect do - post api(collection_uri, user), - params: { url: "http://example.com", token: token } + post api(collection_uri, user, admin_mode: user.admin?), params: { url: "http://example.com", token: token } end.to change { hooks_count }.by(1) expect(response).to have_gitlab_http_status(:created) @@ -216,19 +214,19 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| end it "returns a 400 error if url not given" do - post api(collection_uri, user), params: { event_names.first => true } + post api(collection_uri, user, admin_mode: user.admin?), params: { event_names.first => true } expect(response).to have_gitlab_http_status(:bad_request) end it "returns a 400 error if no parameters are provided" do - post api(collection_uri, user) + post api(collection_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:bad_request) end it 'sets default values for events', :aggregate_failures do - post api(collection_uri, user), params: { url: 'http://mep.mep' } + post api(collection_uri, user, admin_mode: user.admin?), params: { url: 'http://mep.mep' } expect(response).to have_gitlab_http_status(:created) expect(response).to match_hook_schema @@ -239,22 +237,22 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| end it "returns a 422 error if token not valid" do - post api(collection_uri, user), + post api(collection_uri, user, admin_mode: user.admin?), params: { url: "http://example.com", token: "foo\nbar" } expect(response).to have_gitlab_http_status(:unprocessable_entity) end it "returns a 422 error if url not valid" do - post api(collection_uri, user), params: { url: "ftp://example.com" } + post api(collection_uri, user, admin_mode: user.admin?), params: { url: "ftp://example.com" } expect(response).to have_gitlab_http_status(:unprocessable_entity) end end - describe "PUT #{prefix}/hooks/:hook_id" do + describe "PUT #{prefix}/hooks/:hook_id", :aggregate_failures do it "updates an existing hook" do - put api(hook_uri, user), params: update_params + put api(hook_uri, user, admin_mode: user.admin?), params: update_params expect(response).to have_gitlab_http_status(:ok) expect(response).to match_hook_schema @@ -267,7 +265,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| it 'updates the URL variables' do hook.update!(url_variables: { 'abc' => 'some value' }) - put api(hook_uri, user), + put api(hook_uri, user, admin_mode: user.admin?), params: { url_variables: [{ key: 'def', value: 'other value' }] } expect(response).to have_gitlab_http_status(:ok) @@ -280,7 +278,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| it "adds the token without including it in the response" do token = "secret token" - put api(hook_uri, user), params: { url: "http://example.org", token: token } + put api(hook_uri, user, admin_mode: user.admin?), params: { url: "http://example.org", token: token } expect(response).to have_gitlab_http_status(:ok) expect(json_response["url"]).to eq("http://example.org") @@ -291,68 +289,68 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| end it "returns 404 error if hook id not found" do - put api(hook_uri(non_existing_record_id), user), params: { url: 'http://example.org' } + put api(hook_uri(non_existing_record_id), user, admin_mode: user.admin?), params: { url: 'http://example.org' } expect(response).to have_gitlab_http_status(:not_found) end it "returns 400 error if no parameters are provided" do - put api(hook_uri, user) + put api(hook_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:bad_request) end it "returns a 422 error if url is not valid" do - put api(hook_uri, user), params: { url: 'ftp://example.com' } + put api(hook_uri, user, admin_mode: user.admin?), params: { url: 'ftp://example.com' } expect(response).to have_gitlab_http_status(:unprocessable_entity) end it "returns a 422 error if token is not valid" do - put api(hook_uri, user), params: { token: %w[foo bar].join("\n") } + put api(hook_uri, user, admin_mode: user.admin?), params: { token: %w[foo bar].join("\n") } expect(response).to have_gitlab_http_status(:unprocessable_entity) end end - describe "DELETE /projects/:id/hooks/:hook_id" do + describe "DELETE /projects/:id/hooks/:hook_id", :aggregate_failures do it "deletes hook from project" do expect do - delete api(hook_uri, user) + delete api(hook_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:no_content) end.to change { hooks_count }.by(-1) end it "returns a 404 error when deleting non existent hook" do - delete api(hook_uri(non_existing_record_id), user) + delete api(hook_uri(non_existing_record_id), user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end it "returns a 404 error if hook id not given" do - delete api(collection_uri, user) + delete api(collection_uri, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end it "returns forbidden if a user attempts to delete hooks they do not own" do - delete api(hook_uri, unauthorized_user) + delete api(hook_uri, unauthorized_user, admin_mode: true) expect(response).to have_gitlab_http_status(:forbidden) expect(WebHook.exists?(hook.id)).to be_truthy end it_behaves_like '412 response' do - let(:request) { api(hook_uri, user) } + let(:request) { api(hook_uri, user, admin_mode: user.admin?) } end end describe "PUT #{prefix}/hooks/:hook_id/url_variables/:key", :aggregate_failures do it 'sets the variable' do expect do - put api("#{hook_uri}/url_variables/abc", user), - params: { value: 'some secret value' } + put api("#{hook_uri}/url_variables/abc", user, admin_mode: user.admin?), + params: { value: 'some secret value' } end.to change { hook.reload.url_variables }.to(eq('abc' => 'some secret value')) expect(response).to have_gitlab_http_status(:no_content) @@ -361,30 +359,30 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| it 'overwrites existing values' do hook.update!(url_variables: { 'abc' => 'xyz', 'def' => 'other value' }) - put api("#{hook_uri}/url_variables/abc", user), - params: { value: 'some secret value' } + put api("#{hook_uri}/url_variables/abc", user, admin_mode: user.admin?), + params: { value: 'some secret value' } expect(response).to have_gitlab_http_status(:no_content) expect(hook.reload.url_variables).to eq('abc' => 'some secret value', 'def' => 'other value') end it "returns a 404 error when editing non existent hook" do - put api("#{hook_uri(non_existing_record_id)}/url_variables/abc", user), - params: { value: 'xyz' } + put api("#{hook_uri(non_existing_record_id)}/url_variables/abc", user, admin_mode: user.admin?), + params: { value: 'xyz' } expect(response).to have_gitlab_http_status(:not_found) end it "returns a 422 error when the key is illegal" do - put api("#{hook_uri}/url_variables/abc%20def", user), - params: { value: 'xyz' } + put api("#{hook_uri}/url_variables/abc%20def", user, admin_mode: user.admin?), + params: { value: 'xyz' } expect(response).to have_gitlab_http_status(:unprocessable_entity) end it "returns a 422 error when the value is illegal" do - put api("#{hook_uri}/url_variables/abc", user), - params: { value: '' } + put api("#{hook_uri}/url_variables/abc", user, admin_mode: user.admin?), + params: { value: '' } expect(response).to have_gitlab_http_status(:unprocessable_entity) end @@ -397,7 +395,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| it 'unsets the variable' do expect do - delete api("#{hook_uri}/url_variables/abc", user) + delete api("#{hook_uri}/url_variables/abc", user, admin_mode: user.admin?) end.to change { hook.reload.url_variables }.to(eq({ 'def' => 'other value' })) expect(response).to have_gitlab_http_status(:no_content) @@ -406,13 +404,13 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix| it 'returns 404 for keys that do not exist' do hook.update!(url_variables: { 'def' => 'other value' }) - delete api("#{hook_uri}/url_variables/abc", user) + delete api("#{hook_uri}/url_variables/abc", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end it "returns a 404 error when deleting a variable from a non existent hook" do - delete api(hook_uri(non_existing_record_id) + "/url_variables/abc", user) + delete api(hook_uri(non_existing_record_id) + "/url_variables/abc", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end diff --git a/spec/support/shared_examples/requests/api/integrations/github_enterprise_jira_dvcs_end_of_life_shared_examples.rb b/spec/support/shared_examples/requests/api/integrations/github_enterprise_jira_dvcs_end_of_life_shared_examples.rb new file mode 100644 index 00000000000..6799dec7b80 --- /dev/null +++ b/spec/support/shared_examples/requests/api/integrations/github_enterprise_jira_dvcs_end_of_life_shared_examples.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.shared_examples 'a GitHub Enterprise Jira DVCS reversible end of life endpoint' do + it 'is a reachable endpoint' do + subject + + expect(response).not_to have_gitlab_http_status(:not_found) + end + + context 'when the flag is disabled' do + before do + stub_feature_flags(jira_dvcs_end_of_life_amnesty: false) + end + + it 'presents as an endpoint that does not exist' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end +end diff --git a/spec/support/shared_examples/requests/api/integrations/slack/slack_request_verification_shared_examples.rb b/spec/support/shared_examples/requests/api/integrations/slack/slack_request_verification_shared_examples.rb new file mode 100644 index 00000000000..ddda9ca6bcc --- /dev/null +++ b/spec/support/shared_examples/requests/api/integrations/slack/slack_request_verification_shared_examples.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.shared_examples 'Slack request verification' do + describe 'unauthorized request' do + shared_examples 'an unauthorized request' do + specify do + subject + + expect(response).to have_gitlab_http_status(:unauthorized) + end + end + + shared_examples 'a successful request that generates a tracked error' do + specify do + expect(Gitlab::ErrorTracking).to receive(:track_exception).once + + subject + + expect(response).to have_gitlab_http_status(:no_content) + expect(response.body).to be_empty + end + end + + context 'when the slack_app_signing_secret setting is not set' do + before do + stub_application_setting(slack_app_signing_secret: nil) + end + + it_behaves_like 'an unauthorized request' + end + + context 'when the timestamp header has expired' do + before do + headers[::API::Integrations::Slack::Request::VERIFICATION_TIMESTAMP_HEADER] = 5.minutes.ago.to_i.to_s + end + + it_behaves_like 'an unauthorized request' + end + + context 'when the timestamp header is missing' do + before do + headers.delete(::API::Integrations::Slack::Request::VERIFICATION_TIMESTAMP_HEADER) + end + + it_behaves_like 'an unauthorized request' + end + + context 'when the signature header is missing' do + before do + headers.delete(::API::Integrations::Slack::Request::VERIFICATION_SIGNATURE_HEADER) + end + + it_behaves_like 'an unauthorized request' + end + + context 'when the signature is not verified' do + before do + headers[::API::Integrations::Slack::Request::VERIFICATION_SIGNATURE_HEADER] = 'unverified_signature' + end + + it_behaves_like 'an unauthorized request' + end + + context 'when type param is missing' do + it_behaves_like 'a successful request that generates a tracked error' + end + end +end diff --git a/spec/support/shared_examples/requests/api/issuable_update_shared_examples.rb b/spec/support/shared_examples/requests/api/issuable_update_shared_examples.rb index 1045a92f332..e2c9874e7fc 100644 --- a/spec/support/shared_examples/requests/api/issuable_update_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/issuable_update_shared_examples.rb @@ -34,5 +34,14 @@ RSpec.shared_examples 'issuable update endpoint' do expect(json_response['labels']).to include '&' expect(json_response['labels']).to include '?' end + + it 'clears milestone when milestone_id=0' do + entity.update!(milestone: milestone) + + put api(url, user), params: { milestone_id: 0 } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['milestone']).to be_nil + end end end diff --git a/spec/support/shared_examples/requests/api/labels_api_shared_examples.rb b/spec/support/shared_examples/requests/api/labels_api_shared_examples.rb index 41d21490343..fba0533251a 100644 --- a/spec/support/shared_examples/requests/api/labels_api_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/labels_api_shared_examples.rb @@ -9,6 +9,6 @@ RSpec.shared_examples 'fetches labels' do expect(json_response).to be_an Array expect(json_response).to all(match_schema('public_api/v4/labels/label')) expect(json_response.size).to eq(expected_labels.size) - expect(json_response.map { |r| r['name'] }).to match_array(expected_labels) + expect(json_response.pluck('name')).to match_array(expected_labels) end end diff --git a/spec/support/shared_examples/requests/api/milestones_shared_examples.rb b/spec/support/shared_examples/requests/api/milestones_shared_examples.rb index 1ea11ba3d7c..ee7d0e86771 100644 --- a/spec/support/shared_examples/requests/api/milestones_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/milestones_shared_examples.rb @@ -52,7 +52,7 @@ RSpec.shared_examples 'group and project milestones' do |route_definition| expect(response).to have_gitlab_http_status(:ok) expect(json_response).to be_an Array expect(json_response.length).to eq(2) - expect(json_response.map { |m| m['id'] }).to match_array([closed_milestone.id, other_milestone.id]) + expect(json_response.pluck('id')).to match_array([closed_milestone.id, other_milestone.id]) end it 'does not return any milestone if none found' do @@ -293,7 +293,7 @@ RSpec.shared_examples 'group and project milestones' do |route_definition| expect(json_response).to be_an Array # 2 for projects, 3 for group(which has another project with an issue) expect(json_response.size).to be_between(2, 3) - expect(json_response.map { |issue| issue['id'] }).to include(issue.id, confidential_issue.id) + expect(json_response.pluck('id')).to include(issue.id, confidential_issue.id) end it 'does not return confidential issues to team members with guest role' do @@ -306,7 +306,7 @@ RSpec.shared_examples 'group and project milestones' do |route_definition| expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.size).to eq(1) - expect(json_response.map { |issue| issue['id'] }).to include(issue.id) + expect(json_response.pluck('id')).to include(issue.id) end it 'does not return confidential issues to regular users' do @@ -316,7 +316,7 @@ RSpec.shared_examples 'group and project milestones' do |route_definition| expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.size).to eq(1) - expect(json_response.map { |issue| issue['id'] }).to include(issue.id) + expect(json_response.pluck('id')).to include(issue.id) end it 'returns issues ordered by label priority' do 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 new file mode 100644 index 00000000000..2ca62698daf --- /dev/null +++ b/spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +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) + + expect(json_response).to include({ "error_code" => 'RESOURCE_DOES_NOT_EXIST' }) + end +end + +RSpec.shared_examples 'MLflow|Requires api scope' do + context 'when user has access but token has wrong scope' do + let(:access_token) { tokens[:read] } + + it { is_expected.to have_gitlab_http_status(:forbidden) } + end +end + +RSpec.shared_examples 'MLflow|Requires read_api scope' do + context 'when user has access but token has wrong scope' do + let(:access_token) { tokens[:no_access] } + + it { is_expected.to have_gitlab_http_status(:forbidden) } + end +end + +RSpec.shared_examples 'MLflow|Bad Request' do + it "is Bad Request" do + is_expected.to have_gitlab_http_status(:bad_request) + end +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 + + context 'when ff is disabled' do + let(:ff_value) { false } + + it "is Not Found" do + is_expected.to have_gitlab_http_status(:not_found) + end + end +end + +RSpec.shared_examples 'MLflow|Bad Request on missing required' do |keys| + keys.each do |key| + 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 + end + end +end diff --git a/spec/support/shared_examples/requests/api/notes_shared_examples.rb b/spec/support/shared_examples/requests/api/notes_shared_examples.rb index efe5ed3bcf9..b44ff952cdf 100644 --- a/spec/support/shared_examples/requests/api/notes_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/notes_shared_examples.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| - describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do + describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes", :aggregate_failures do context 'sorting' do before do params = { noteable: noteable, author: user } @@ -12,9 +12,9 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| context 'without sort params' do it 'sorts by created_at in descending order by default' do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?) - response_dates = json_response.map { |note| note['created_at'] } + response_dates = json_response.pluck('created_at') expect(json_response.length).to eq(4) expect(response_dates).to eq(response_dates.sort.reverse) @@ -23,7 +23,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| it 'fetches notes using parent path as id paremeter' do parent_id = CGI.escape(parent.full_path) - get api("/#{parent_type}/#{parent_id}/#{noteable_type}/#{noteable[id_name]}/notes", user) + get api("/#{parent_type}/#{parent_id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:ok) end @@ -40,18 +40,18 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| end it 'page breaks first page correctly' do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?per_page=4", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?per_page=4", user, admin_mode: user.admin?) - response_ids = json_response.map { |note| note['id'] } + response_ids = json_response.pluck('id') expect(response_ids).to include(@note2.id) expect(response_ids).not_to include(@first_note.id) end it 'page breaks second page correctly' do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?per_page=4&page=2", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?per_page=4&page=2", user, admin_mode: user.admin?) - response_ids = json_response.map { |note| note['id'] } + response_ids = json_response.pluck('id') expect(response_ids).not_to include(@note2.id) expect(response_ids).to include(@first_note.id) @@ -60,27 +60,27 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| end it 'sorts by ascending order when requested' do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?sort=asc", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?sort=asc", user, admin_mode: user.admin?) - response_dates = json_response.map { |note| note['created_at'] } + response_dates = json_response.pluck('created_at') expect(json_response.length).to eq(4) expect(response_dates).to eq(response_dates.sort) end it 'sorts by updated_at in descending order when requested' do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at", user, admin_mode: user.admin?) - response_dates = json_response.map { |note| note['updated_at'] } + response_dates = json_response.pluck('updated_at') expect(json_response.length).to eq(4) expect(response_dates).to eq(response_dates.sort.reverse) end it 'sorts by updated_at in ascending order when requested' do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at&sort=asc", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at&sort=asc", user, admin_mode: user.admin?) - response_dates = json_response.map { |note| note['updated_at'] } + response_dates = json_response.pluck('updated_at') expect(json_response.length).to eq(4) expect(response_dates).to eq(response_dates.sort) @@ -88,7 +88,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| end it "returns an array of notes" do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:ok) expect(response).to include_pagination_headers @@ -97,7 +97,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| end it "returns a 404 error when noteable id not found" do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{non_existing_record_id}/notes", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{non_existing_record_id}/notes", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end @@ -105,36 +105,36 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| it "returns 404 when not authorized" do parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user, admin_mode: private_user.admin?) expect(response).to have_gitlab_http_status(:not_found) end end - describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do + describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id", :aggregate_failures do it "returns a note by id" do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:ok) expect(json_response['body']).to eq(note.note) end it "returns a 404 error if note not found" do - get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{non_existing_record_id}", user) + get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{non_existing_record_id}", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end end - describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do + describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes", :aggregate_failures do let(:params) { { body: 'hi!' } } subject do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?), params: params end it "creates a new note" do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: 'hi!' } + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?), params: { body: 'hi!' } expect(response).to have_gitlab_http_status(:created) expect(json_response['body']).to eq('hi!') @@ -143,7 +143,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| end it "returns a 400 bad request error if body not given" do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user) + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:bad_request) end @@ -158,7 +158,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| uri = "/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes" expect do - post api(uri, user), params: { body: 'hi!' } + post api(uri, user, admin_mode: user.admin?), params: { body: 'hi!' } end.to change { Event.count }.by(1) end @@ -169,7 +169,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| context 'by an admin' do it 'sets the creation time on the new note' do admin = create(:admin) - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", admin), params: params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:created) expect(json_response['body']).to eq('hi!') @@ -185,7 +185,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| let(:user) { project.first_owner } it 'sets the creation time on the new note' do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?), params: params expect(response).to have_gitlab_http_status(:created) expect(json_response['body']).to eq('hi!') @@ -215,7 +215,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| when 'groups' context 'by a group owner' do it 'sets the creation time on the new note' do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?), params: params expect(response).to have_gitlab_http_status(:created) expect(json_response['body']).to eq('hi!') @@ -253,7 +253,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| context 'when the user is posting an award emoji on their own noteable' do it 'creates a new note' do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: ':+1:' } + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?), params: { body: ':+1:' } expect(response).to have_gitlab_http_status(:created) expect(json_response['body']).to eq(':+1:') @@ -266,7 +266,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| end it 'responds with 404' do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user), + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user, admin_mode: private_user.admin?), params: { body: 'Foo' } expect(response).to have_gitlab_http_status(:not_found) @@ -299,11 +299,11 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| end end - describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do + describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id", :aggregate_failures do let(:params) { { body: 'Hello!' } } subject do - put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user), params: params + put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user, admin_mode: user.admin?), params: params end context 'when only body param is present' do @@ -329,40 +329,40 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name| end it 'returns a 404 error when note id not found' do - put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{non_existing_record_id}", user), - params: { body: 'Hello!' } + put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{non_existing_record_id}", user, admin_mode: user.admin?), + params: { body: 'Hello!' } expect(response).to have_gitlab_http_status(:not_found) end it 'returns a 400 bad request error if body is empty' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "notes/#{note.id}", user), params: { body: '' } + "notes/#{note.id}", user, admin_mode: user.admin?), params: { body: '' } expect(response).to have_gitlab_http_status(:bad_request) end end - describe "DELETE /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do + describe "DELETE /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id", :aggregate_failures do it 'deletes a note' do delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "notes/#{note.id}", user) + "notes/#{note.id}", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:no_content) # Check if note is really deleted delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "notes/#{note.id}", user) + "notes/#{note.id}", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end it 'returns a 404 error when note id not found' do - delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{non_existing_record_id}", user) + delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{non_existing_record_id}", user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end it_behaves_like '412 response' do - let(:request) { api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user) } + let(:request) { api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user, admin_mode: user.admin?) } end end end @@ -370,16 +370,16 @@ end RSpec.shared_examples 'noteable API with confidential notes' do |parent_type, noteable_type, id_name| it_behaves_like 'noteable API', parent_type, noteable_type, id_name - describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do + describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes", :aggregate_failures do let(:params) { { body: 'hi!' } } subject do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?), params: params end context 'with internal param' do it "creates a confidential note if internal is set to true" do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params.merge(internal: true) + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?), params: params.merge(internal: true) expect(response).to have_gitlab_http_status(:created) expect(json_response['body']).to eq('hi!') @@ -391,7 +391,7 @@ RSpec.shared_examples 'noteable API with confidential notes' do |parent_type, no context 'with deprecated confidential param' do it "creates a confidential note if confidential is set to true" do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params.merge(confidential: true) + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user, admin_mode: user.admin?), params: params.merge(confidential: true) expect(response).to have_gitlab_http_status(:created) expect(json_response['body']).to eq('hi!') diff --git a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb index b55639a6b82..f53532d00d7 100644 --- a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb @@ -507,55 +507,118 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project| it_behaves_like 'returning response status', status end - shared_examples 'handling different package names, visibilities and user roles' do - where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do - :scoped_naming_convention | :public | :anonymous | :accept | :ok - :scoped_naming_convention | :public | :guest | :accept | :ok - :scoped_naming_convention | :public | :reporter | :accept | :ok - :scoped_no_naming_convention | :public | :anonymous | :accept | :ok - :scoped_no_naming_convention | :public | :guest | :accept | :ok - :scoped_no_naming_convention | :public | :reporter | :accept | :ok - :unscoped | :public | :anonymous | :accept | :ok - :unscoped | :public | :guest | :accept | :ok - :unscoped | :public | :reporter | :accept | :ok - :non_existing | :public | :anonymous | :reject | :not_found - :non_existing | :public | :guest | :reject | :not_found - :non_existing | :public | :reporter | :reject | :not_found - - :scoped_naming_convention | :private | :anonymous | :reject | :not_found - :scoped_naming_convention | :private | :guest | :reject | :forbidden - :scoped_naming_convention | :private | :reporter | :accept | :ok - :scoped_no_naming_convention | :private | :anonymous | :reject | :not_found - :scoped_no_naming_convention | :private | :guest | :reject | :forbidden - :scoped_no_naming_convention | :private | :reporter | :accept | :ok - :unscoped | :private | :anonymous | :reject | :not_found - :unscoped | :private | :guest | :reject | :forbidden - :unscoped | :private | :reporter | :accept | :ok - :non_existing | :private | :anonymous | :reject | :not_found - :non_existing | :private | :guest | :reject | :forbidden - :non_existing | :private | :reporter | :reject | :not_found - - :scoped_naming_convention | :internal | :anonymous | :reject | :not_found - :scoped_naming_convention | :internal | :guest | :accept | :ok - :scoped_naming_convention | :internal | :reporter | :accept | :ok - :scoped_no_naming_convention | :internal | :anonymous | :reject | :not_found - :scoped_no_naming_convention | :internal | :guest | :accept | :ok - :scoped_no_naming_convention | :internal | :reporter | :accept | :ok - :unscoped | :internal | :anonymous | :reject | :not_found - :unscoped | :internal | :guest | :accept | :ok - :unscoped | :internal | :reporter | :accept | :ok - :non_existing | :internal | :anonymous | :reject | :not_found - :non_existing | :internal | :guest | :reject | :not_found - :non_existing | :internal | :reporter | :reject | :not_found + shared_examples 'handling all conditions' do + where(:auth, :package_name_type, :visibility, :user_role, :expected_result, :expected_status) do + nil | :scoped_naming_convention | :public | nil | :accept | :ok + nil | :scoped_no_naming_convention | :public | nil | :accept | :ok + nil | :unscoped | :public | nil | :accept | :ok + nil | :non_existing | :public | nil | :reject | :not_found + nil | :scoped_naming_convention | :private | nil | :reject | :not_found + nil | :scoped_no_naming_convention | :private | nil | :reject | :not_found + nil | :unscoped | :private | nil | :reject | :not_found + nil | :non_existing | :private | nil | :reject | :not_found + nil | :scoped_naming_convention | :internal | nil | :reject | :not_found + nil | :scoped_no_naming_convention | :internal | nil | :reject | :not_found + nil | :unscoped | :internal | nil | :reject | :not_found + nil | :non_existing | :internal | nil | :reject | :not_found + + :oauth | :scoped_naming_convention | :public | :guest | :accept | :ok + :oauth | :scoped_naming_convention | :public | :reporter | :accept | :ok + :oauth | :scoped_no_naming_convention | :public | :guest | :accept | :ok + :oauth | :scoped_no_naming_convention | :public | :reporter | :accept | :ok + :oauth | :unscoped | :public | :guest | :accept | :ok + :oauth | :unscoped | :public | :reporter | :accept | :ok + :oauth | :non_existing | :public | :guest | :reject | :not_found + :oauth | :non_existing | :public | :reporter | :reject | :not_found + :oauth | :scoped_naming_convention | :private | :guest | :reject | :forbidden + :oauth | :scoped_naming_convention | :private | :reporter | :accept | :ok + :oauth | :scoped_no_naming_convention | :private | :guest | :reject | :forbidden + :oauth | :scoped_no_naming_convention | :private | :reporter | :accept | :ok + :oauth | :unscoped | :private | :guest | :reject | :forbidden + :oauth | :unscoped | :private | :reporter | :accept | :ok + :oauth | :non_existing | :private | :guest | :reject | :forbidden + :oauth | :non_existing | :private | :reporter | :reject | :not_found + :oauth | :scoped_naming_convention | :internal | :guest | :accept | :ok + :oauth | :scoped_naming_convention | :internal | :reporter | :accept | :ok + :oauth | :scoped_no_naming_convention | :internal | :guest | :accept | :ok + :oauth | :scoped_no_naming_convention | :internal | :reporter | :accept | :ok + :oauth | :unscoped | :internal | :guest | :accept | :ok + :oauth | :unscoped | :internal | :reporter | :accept | :ok + :oauth | :non_existing | :internal | :guest | :reject | :not_found + :oauth | :non_existing | :internal | :reporter | :reject | :not_found + + :personal_access_token | :scoped_naming_convention | :public | :guest | :accept | :ok + :personal_access_token | :scoped_naming_convention | :public | :reporter | :accept | :ok + :personal_access_token | :scoped_no_naming_convention | :public | :guest | :accept | :ok + :personal_access_token | :scoped_no_naming_convention | :public | :reporter | :accept | :ok + :personal_access_token | :unscoped | :public | :guest | :accept | :ok + :personal_access_token | :unscoped | :public | :reporter | :accept | :ok + :personal_access_token | :non_existing | :public | :guest | :reject | :not_found + :personal_access_token | :non_existing | :public | :reporter | :reject | :not_found + :personal_access_token | :scoped_naming_convention | :private | :guest | :reject | :forbidden + :personal_access_token | :scoped_naming_convention | :private | :reporter | :accept | :ok + :personal_access_token | :scoped_no_naming_convention | :private | :guest | :reject | :forbidden + :personal_access_token | :scoped_no_naming_convention | :private | :reporter | :accept | :ok + :personal_access_token | :unscoped | :private | :guest | :reject | :forbidden + :personal_access_token | :unscoped | :private | :reporter | :accept | :ok + :personal_access_token | :non_existing | :private | :guest | :reject | :forbidden + :personal_access_token | :non_existing | :private | :reporter | :reject | :not_found + :personal_access_token | :scoped_naming_convention | :internal | :guest | :accept | :ok + :personal_access_token | :scoped_naming_convention | :internal | :reporter | :accept | :ok + :personal_access_token | :scoped_no_naming_convention | :internal | :guest | :accept | :ok + :personal_access_token | :scoped_no_naming_convention | :internal | :reporter | :accept | :ok + :personal_access_token | :unscoped | :internal | :guest | :accept | :ok + :personal_access_token | :unscoped | :internal | :reporter | :accept | :ok + :personal_access_token | :non_existing | :internal | :guest | :reject | :not_found + :personal_access_token | :non_existing | :internal | :reporter | :reject | :not_found + + :job_token | :scoped_naming_convention | :public | :developer | :accept | :ok + :job_token | :scoped_no_naming_convention | :public | :developer | :accept | :ok + :job_token | :unscoped | :public | :developer | :accept | :ok + :job_token | :non_existing | :public | :developer | :reject | :not_found + :job_token | :scoped_naming_convention | :private | :developer | :accept | :ok + :job_token | :scoped_no_naming_convention | :private | :developer | :accept | :ok + :job_token | :unscoped | :private | :developer | :accept | :ok + :job_token | :non_existing | :private | :developer | :reject | :not_found + :job_token | :scoped_naming_convention | :internal | :developer | :accept | :ok + :job_token | :scoped_no_naming_convention | :internal | :developer | :accept | :ok + :job_token | :unscoped | :internal | :developer | :accept | :ok + :job_token | :non_existing | :internal | :developer | :reject | :not_found + + :deploy_token | :scoped_naming_convention | :public | nil | :accept | :ok + :deploy_token | :scoped_no_naming_convention | :public | nil | :accept | :ok + :deploy_token | :unscoped | :public | nil | :accept | :ok + :deploy_token | :non_existing | :public | nil | :reject | :not_found + :deploy_token | :scoped_naming_convention | :private | nil | :accept | :ok + :deploy_token | :scoped_no_naming_convention | :private | nil | :accept | :ok + :deploy_token | :unscoped | :private | nil | :accept | :ok + :deploy_token | :non_existing | :private | nil | :reject | :not_found + :deploy_token | :scoped_naming_convention | :internal | nil | :accept | :ok + :deploy_token | :scoped_no_naming_convention | :internal | nil | :accept | :ok + :deploy_token | :unscoped | :internal | nil | :accept | :ok + :deploy_token | :non_existing | :internal | nil | :reject | :not_found end with_them do - let(:anonymous) { user_role == :anonymous } + let(:headers) do + case auth + when :oauth + build_token_auth_header(token.plaintext_token) + when :personal_access_token + build_token_auth_header(personal_access_token.token) + when :job_token + build_token_auth_header(job.token) + when :deploy_token + build_token_auth_header(deploy_token.token) + else + {} + end + end - subject { get(url, headers: anonymous ? {} : headers) } + subject { get(url, headers: headers) } before do - project.send("add_#{user_role}", user) unless anonymous + project.send("add_#{user_role}", user) if user_role project.update!(visibility: visibility.to_s) end @@ -571,20 +634,6 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project| end end - shared_examples 'handling all conditions' do - context 'with oauth token' do - let(:headers) { build_token_auth_header(token.plaintext_token) } - - it_behaves_like 'handling different package names, visibilities and user roles' - end - - context 'with personal access token' do - let(:headers) { build_token_auth_header(personal_access_token.token) } - - it_behaves_like 'handling different package names, visibilities and user roles' - end - end - context 'with a group namespace' do it_behaves_like 'handling all conditions' end @@ -599,7 +648,6 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project| end RSpec.shared_examples 'handling create dist tag requests' do |scope: :project| - using RSpec::Parameterized::TableSyntax include_context 'set package name from package name type' let_it_be(:tag_name) { 'test' } @@ -617,82 +665,10 @@ RSpec.shared_examples 'handling create dist tag requests' do |scope: :project| it_behaves_like 'returning response status', status end - shared_examples 'handling different package names, visibilities and user roles' do - where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do - :scoped_naming_convention | :public | :anonymous | :reject | :forbidden - :scoped_naming_convention | :public | :guest | :reject | :forbidden - :scoped_naming_convention | :public | :developer | :accept | :ok - :scoped_no_naming_convention | :public | :anonymous | :reject | :forbidden - :scoped_no_naming_convention | :public | :guest | :reject | :forbidden - :scoped_no_naming_convention | :public | :developer | :accept | :ok - :unscoped | :public | :anonymous | :reject | :forbidden - :unscoped | :public | :guest | :reject | :forbidden - :unscoped | :public | :developer | :accept | :ok - :non_existing | :public | :anonymous | :reject | :forbidden - :non_existing | :public | :guest | :reject | :forbidden - :non_existing | :public | :developer | :reject | :not_found - - :scoped_naming_convention | :private | :anonymous | :reject | :not_found - :scoped_naming_convention | :private | :guest | :reject | :forbidden - :scoped_naming_convention | :private | :developer | :accept | :ok - :scoped_no_naming_convention | :private | :anonymous | :reject | :not_found - :scoped_no_naming_convention | :private | :guest | :reject | :forbidden - :scoped_no_naming_convention | :private | :developer | :accept | :ok - :unscoped | :private | :anonymous | :reject | :not_found - :unscoped | :private | :guest | :reject | :forbidden - :unscoped | :private | :developer | :accept | :ok - :non_existing | :private | :anonymous | :reject | :not_found - :non_existing | :private | :guest | :reject | :forbidden - :non_existing | :private | :developer | :reject | :not_found - - :scoped_naming_convention | :internal | :anonymous | :reject | :forbidden - :scoped_naming_convention | :internal | :guest | :reject | :forbidden - :scoped_naming_convention | :internal | :developer | :accept | :ok - :scoped_no_naming_convention | :internal | :anonymous | :reject | :forbidden - :scoped_no_naming_convention | :internal | :guest | :reject | :forbidden - :scoped_no_naming_convention | :internal | :developer | :accept | :ok - :unscoped | :internal | :anonymous | :reject | :forbidden - :unscoped | :internal | :guest | :reject | :forbidden - :unscoped | :internal | :developer | :accept | :ok - :non_existing | :internal | :anonymous | :reject | :forbidden - :non_existing | :internal | :guest | :reject | :forbidden - :non_existing | :internal | :developer | :reject | :not_found - end - - with_them do - let(:anonymous) { user_role == :anonymous } - - subject { put(url, env: env, headers: headers) } - - before do - project.send("add_#{user_role}", user) unless anonymous - project.update!(visibility: visibility.to_s) - end - - example_name = "#{params[:expected_result]} create package tag request" - status = params[:expected_status] - - if scope == :instance && params[:package_name_type] != :scoped_naming_convention - example_name = 'reject create package tag request' - status = :not_found - end - - it_behaves_like example_name, status: status - end - end - shared_examples 'handling all conditions' do - context 'with oauth token' do - let(:headers) { build_token_auth_header(token.plaintext_token) } + subject { put(url, env: env, headers: headers) } - it_behaves_like 'handling different package names, visibilities and user roles' - end - - context 'with personal access token' do - let(:headers) { build_token_auth_header(personal_access_token.token) } - - it_behaves_like 'handling different package names, visibilities and user roles' - end + it_behaves_like 'handling different package names, visibilities and user roles for tags create or delete', action: :create, scope: scope end context 'with a group namespace' do @@ -709,7 +685,6 @@ RSpec.shared_examples 'handling create dist tag requests' do |scope: :project| end RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project| - using RSpec::Parameterized::TableSyntax include_context 'set package name from package name type' let_it_be(:package_tag) { create(:packages_tag, package: package) } @@ -725,82 +700,10 @@ RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project| it_behaves_like 'returning response status', status end - shared_examples 'handling different package names, visibilities and user roles' do - where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do - :scoped_naming_convention | :public | :anonymous | :reject | :forbidden - :scoped_naming_convention | :public | :guest | :reject | :forbidden - :scoped_naming_convention | :public | :maintainer | :accept | :ok - :scoped_no_naming_convention | :public | :anonymous | :reject | :forbidden - :scoped_no_naming_convention | :public | :guest | :reject | :forbidden - :scoped_no_naming_convention | :public | :maintainer | :accept | :ok - :unscoped | :public | :anonymous | :reject | :forbidden - :unscoped | :public | :guest | :reject | :forbidden - :unscoped | :public | :maintainer | :accept | :ok - :non_existing | :public | :anonymous | :reject | :forbidden - :non_existing | :public | :guest | :reject | :forbidden - :non_existing | :public | :maintainer | :reject | :not_found - - :scoped_naming_convention | :private | :anonymous | :reject | :not_found - :scoped_naming_convention | :private | :guest | :reject | :forbidden - :scoped_naming_convention | :private | :maintainer | :accept | :ok - :scoped_no_naming_convention | :private | :anonymous | :reject | :not_found - :scoped_no_naming_convention | :private | :guest | :reject | :forbidden - :scoped_no_naming_convention | :private | :maintainer | :accept | :ok - :unscoped | :private | :anonymous | :reject | :not_found - :unscoped | :private | :guest | :reject | :forbidden - :unscoped | :private | :maintainer | :accept | :ok - :non_existing | :private | :anonymous | :reject | :not_found - :non_existing | :private | :guest | :reject | :forbidden - :non_existing | :private | :maintainer | :reject | :not_found - - :scoped_naming_convention | :internal | :anonymous | :reject | :forbidden - :scoped_naming_convention | :internal | :guest | :reject | :forbidden - :scoped_naming_convention | :internal | :maintainer | :accept | :ok - :scoped_no_naming_convention | :internal | :anonymous | :reject | :forbidden - :scoped_no_naming_convention | :internal | :guest | :reject | :forbidden - :scoped_no_naming_convention | :internal | :maintainer | :accept | :ok - :unscoped | :internal | :anonymous | :reject | :forbidden - :unscoped | :internal | :guest | :reject | :forbidden - :unscoped | :internal | :maintainer | :accept | :ok - :non_existing | :internal | :anonymous | :reject | :forbidden - :non_existing | :internal | :guest | :reject | :forbidden - :non_existing | :internal | :maintainer | :reject | :not_found - end - - with_them do - let(:anonymous) { user_role == :anonymous } - - subject { delete(url, headers: headers) } - - before do - project.send("add_#{user_role}", user) unless anonymous - project.update!(visibility: visibility.to_s) - end - - example_name = "#{params[:expected_result]} delete package tag request" - status = params[:expected_status] - - if scope == :instance && params[:package_name_type] != :scoped_naming_convention - example_name = 'reject delete package tag request' - status = :not_found - end - - it_behaves_like example_name, status: status - end - end - shared_examples 'handling all conditions' do - context 'with oauth token' do - let(:headers) { build_token_auth_header(token.plaintext_token) } - - it_behaves_like 'handling different package names, visibilities and user roles' - end - - context 'with personal access token' do - let(:headers) { build_token_auth_header(personal_access_token.token) } + subject { delete(url, headers: headers) } - it_behaves_like 'handling different package names, visibilities and user roles' - end + it_behaves_like 'handling different package names, visibilities and user roles for tags create or delete', action: :delete, scope: scope end context 'with a group namespace' do @@ -815,3 +718,134 @@ RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project| end end end + +RSpec.shared_examples 'handling different package names, visibilities and user roles for tags create or delete' do |action:, scope: :project| + using RSpec::Parameterized::TableSyntax + + role = action == :create ? :developer : :maintainer + + where(:auth, :package_name_type, :visibility, :user_role, :expected_result, :expected_status) do + nil | :scoped_naming_convention | :public | nil | :reject | :unauthorized + nil | :scoped_no_naming_convention | :public | nil | :reject | :unauthorized + nil | :unscoped | :public | nil | :reject | :unauthorized + nil | :non_existing | :public | nil | :reject | :unauthorized + nil | :scoped_naming_convention | :private | nil | :reject | :unauthorized + nil | :scoped_no_naming_convention | :private | nil | :reject | :unauthorized + nil | :unscoped | :private | nil | :reject | :unauthorized + nil | :non_existing | :private | nil | :reject | :unauthorized + nil | :scoped_naming_convention | :internal | nil | :reject | :unauthorized + nil | :scoped_no_naming_convention | :internal | nil | :reject | :unauthorized + nil | :unscoped | :internal | nil | :reject | :unauthorized + nil | :non_existing | :internal | nil | :reject | :unauthorized + + :oauth | :scoped_naming_convention | :public | :guest | :reject | :forbidden + :oauth | :scoped_naming_convention | :public | role | :accept | :ok + :oauth | :scoped_no_naming_convention | :public | :guest | :reject | :forbidden + :oauth | :scoped_no_naming_convention | :public | role | :accept | :ok + :oauth | :unscoped | :public | :guest | :reject | :forbidden + :oauth | :unscoped | :public | role | :accept | :ok + :oauth | :non_existing | :public | :guest | :reject | :forbidden + :oauth | :non_existing | :public | role | :reject | :not_found + :oauth | :scoped_naming_convention | :private | :guest | :reject | :forbidden + :oauth | :scoped_naming_convention | :private | role | :accept | :ok + :oauth | :scoped_no_naming_convention | :private | :guest | :reject | :forbidden + :oauth | :scoped_no_naming_convention | :private | role | :accept | :ok + :oauth | :unscoped | :private | :guest | :reject | :forbidden + :oauth | :unscoped | :private | role | :accept | :ok + :oauth | :non_existing | :private | :guest | :reject | :forbidden + :oauth | :non_existing | :private | role | :reject | :not_found + :oauth | :scoped_naming_convention | :internal | :guest | :reject | :forbidden + :oauth | :scoped_naming_convention | :internal | role | :accept | :ok + :oauth | :scoped_no_naming_convention | :internal | :guest | :reject | :forbidden + :oauth | :scoped_no_naming_convention | :internal | role | :accept | :ok + :oauth | :unscoped | :internal | :guest | :reject | :forbidden + :oauth | :unscoped | :internal | role | :accept | :ok + :oauth | :non_existing | :internal | :guest | :reject | :forbidden + :oauth | :non_existing | :internal | role | :reject | :not_found + + :personal_access_token | :scoped_naming_convention | :public | :guest | :reject | :forbidden + :personal_access_token | :scoped_naming_convention | :public | role | :accept | :ok + :personal_access_token | :scoped_no_naming_convention | :public | :guest | :reject | :forbidden + :personal_access_token | :scoped_no_naming_convention | :public | role | :accept | :ok + :personal_access_token | :unscoped | :public | :guest | :reject | :forbidden + :personal_access_token | :unscoped | :public | role | :accept | :ok + :personal_access_token | :non_existing | :public | :guest | :reject | :forbidden + :personal_access_token | :non_existing | :public | role | :reject | :not_found + :personal_access_token | :scoped_naming_convention | :private | :guest | :reject | :forbidden + :personal_access_token | :scoped_naming_convention | :private | role | :accept | :ok + :personal_access_token | :scoped_no_naming_convention | :private | :guest | :reject | :forbidden + :personal_access_token | :scoped_no_naming_convention | :private | role | :accept | :ok + :personal_access_token | :unscoped | :private | :guest | :reject | :forbidden + :personal_access_token | :unscoped | :private | role | :accept | :ok + :personal_access_token | :non_existing | :private | :guest | :reject | :forbidden + :personal_access_token | :non_existing | :private | role | :reject | :not_found + :personal_access_token | :scoped_naming_convention | :internal | :guest | :reject | :forbidden + :personal_access_token | :scoped_naming_convention | :internal | role | :accept | :ok + :personal_access_token | :scoped_no_naming_convention | :internal | :guest | :reject | :forbidden + :personal_access_token | :scoped_no_naming_convention | :internal | role | :accept | :ok + :personal_access_token | :unscoped | :internal | :guest | :reject | :forbidden + :personal_access_token | :unscoped | :internal | role | :accept | :ok + :personal_access_token | :non_existing | :internal | :guest | :reject | :forbidden + :personal_access_token | :non_existing | :internal | role | :reject | :not_found + + :job_token | :scoped_naming_convention | :public | role | :accept | :ok + :job_token | :scoped_no_naming_convention | :public | role | :accept | :ok + :job_token | :unscoped | :public | role | :accept | :ok + :job_token | :non_existing | :public | role | :reject | :not_found + :job_token | :scoped_naming_convention | :private | role | :accept | :ok + :job_token | :scoped_no_naming_convention | :private | role | :accept | :ok + :job_token | :unscoped | :private | role | :accept | :ok + :job_token | :non_existing | :private | role | :reject | :not_found + :job_token | :scoped_naming_convention | :internal | role | :accept | :ok + :job_token | :scoped_no_naming_convention | :internal | role | :accept | :ok + :job_token | :unscoped | :internal | role | :accept | :ok + :job_token | :non_existing | :internal | role | :reject | :not_found + + :deploy_token | :scoped_naming_convention | :public | nil | :accept | :ok + :deploy_token | :scoped_no_naming_convention | :public | nil | :accept | :ok + :deploy_token | :unscoped | :public | nil | :accept | :ok + :deploy_token | :non_existing | :public | nil | :reject | :not_found + :deploy_token | :scoped_naming_convention | :private | nil | :accept | :ok + :deploy_token | :scoped_no_naming_convention | :private | nil | :accept | :ok + :deploy_token | :unscoped | :private | nil | :accept | :ok + :deploy_token | :non_existing | :private | nil | :reject | :not_found + :deploy_token | :scoped_naming_convention | :internal | nil | :accept | :ok + :deploy_token | :scoped_no_naming_convention | :internal | nil | :accept | :ok + :deploy_token | :unscoped | :internal | nil | :accept | :ok + :deploy_token | :non_existing | :internal | nil | :reject | :not_found + end + + with_them do + let(:headers) do + case auth + when :oauth + build_token_auth_header(token.plaintext_token) + when :personal_access_token + build_token_auth_header(personal_access_token.token) + when :job_token + build_token_auth_header(job.token) + when :deploy_token + build_token_auth_header(deploy_token.token) + else + {} + end + end + + before do + project.send("add_#{user_role}", user) if user_role + project.update!(visibility: visibility.to_s) + end + + example_name = "#{params[:expected_result]} #{action} package tag request" + status = params[:expected_status] + + if scope == :instance && params[:package_name_type] != :scoped_naming_convention + example_name = "reject #{action} package tag request" + # Due to #authenticate_non_get, anonymous requests on private resources + # are rejected with unauthorized status + status = params[:auth].nil? ? :unauthorized : :not_found + end + + it_behaves_like example_name, status: status + end +end diff --git a/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb index 1d79a61fbb0..7c20ea661b5 100644 --- a/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb @@ -1,13 +1,5 @@ # frozen_string_literal: true -RSpec.shared_examples 'rejects package tags access' do |status:| - before do - package.update!(name: package_name) unless package_name == 'non-existing-package' - end - - it_behaves_like 'returning response status', status -end - RSpec.shared_examples 'accept package tags request' do |status:| using RSpec::Parameterized::TableSyntax include_context 'dependency proxy helpers context' @@ -23,6 +15,7 @@ RSpec.shared_examples 'accept package tags request' do |status:| end it_behaves_like 'returning response status', status + it_behaves_like 'track event', :list_tags it 'returns a valid json response' do subject @@ -63,6 +56,7 @@ RSpec.shared_examples 'accept create package tag request' do |user_type| end it_behaves_like 'returning response status', :no_content + it_behaves_like 'track event', :create_tag it 'creates the package tag' do expect { subject }.to change { Packages::Tag.count }.by(1) @@ -145,6 +139,7 @@ RSpec.shared_examples 'accept delete package tag request' do |user_type| end it_behaves_like 'returning response status', :no_content + it_behaves_like 'track event', :delete_tag it 'returns a valid response' do subject @@ -190,3 +185,21 @@ RSpec.shared_examples 'accept delete package tag request' do |user_type| end end end + +RSpec.shared_examples 'track event' do |event_name| + let(:event_user) do + if auth == :deploy_token + deploy_token + elsif user_role + user + end + end + + let(:snowplow_gitlab_standard_context) do + { project: project, namespace: project.namespace, property: 'i_package_npm_user' }.tap do |context| + context[:user] = event_user if event_user + end + end + + it_behaves_like 'a package tracking event', described_class.name, event_name.to_s +end diff --git a/spec/support/shared_examples/requests/api/nuget_endpoints_shared_examples.rb b/spec/support/shared_examples/requests/api/nuget_endpoints_shared_examples.rb index 17d8b9c7fab..7cafe8bb368 100644 --- a/spec/support/shared_examples/requests/api/nuget_endpoints_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/nuget_endpoints_shared_examples.rb @@ -36,6 +36,7 @@ RSpec.shared_examples 'handling nuget service requests' do |example_names_with_s with_them do let(:token) { user_token ? personal_access_token.token : 'wrong' } let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) } + let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) } subject { get api(url), headers: headers } @@ -72,6 +73,7 @@ RSpec.shared_examples 'handling nuget service requests' do |example_names_with_s with_them do let(:job) { user_token ? create(:ci_build, project: project, user: user, status: :running) : double(token: 'wrong') } let(:headers) { user_role == :anonymous ? {} : job_basic_auth_header(job) } + let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) } subject { get api(url), headers: headers } @@ -140,6 +142,7 @@ RSpec.shared_examples 'handling nuget metadata requests with package name' do |e with_them do let(:token) { user_token ? personal_access_token.token : 'wrong' } let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) } + let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) } subject { get api(url), headers: headers } @@ -207,6 +210,7 @@ RSpec.shared_examples 'handling nuget metadata requests with package name and pa with_them do let(:token) { user_token ? personal_access_token.token : 'wrong' } let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) } + let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) } subject { get api(url), headers: headers } @@ -277,6 +281,7 @@ RSpec.shared_examples 'handling nuget search requests' do |example_names_with_st with_them do let(:token) { user_token ? personal_access_token.token : 'wrong' } let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) } + let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) } subject { get api(url), headers: headers } diff --git a/spec/support/shared_examples/requests/api/packages_shared_examples.rb b/spec/support/shared_examples/requests/api/packages_shared_examples.rb index 98264baa61d..3168f25e4fa 100644 --- a/spec/support/shared_examples/requests/api/packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/packages_shared_examples.rb @@ -143,37 +143,37 @@ RSpec.shared_examples 'job token for package uploads' do |authorize_endpoint: fa end RSpec.shared_examples 'a package tracking event' do |category, action, service_ping_context = true| - before do - stub_feature_flags(collect_package_events: true) - end - let(:context) do - [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, - event: snowplow_gitlab_standard_context[:property]).to_h] + [ + Gitlab::Tracking::ServicePingContext.new( + data_source: :redis_hll, + event: snowplow_gitlab_standard_context[:property] + ).to_h + ] end it "creates a gitlab tracking event #{action}", :snowplow, :aggregate_failures do - expect { subject }.to change { Packages::Event.count }.by(1) + subject if service_ping_context - expect_snowplow_event(category: category, action: action, - label: "redis_hll_counters.user_packages.user_packages_total_unique_counts_monthly", - context: context, **snowplow_gitlab_standard_context) + expect_snowplow_event( + category: category, + action: action, + label: "redis_hll_counters.user_packages.user_packages_total_unique_counts_monthly", + context: context, + **snowplow_gitlab_standard_context + ) else expect_snowplow_event(category: category, action: action, **snowplow_gitlab_standard_context) end end end -RSpec.shared_examples 'not a package tracking event' do - before do - stub_feature_flags(collect_package_events: true) - end - +RSpec.shared_examples 'not a package tracking event' do |category, action| it 'does not create a gitlab tracking event', :snowplow, :aggregate_failures do - expect { subject }.not_to change { Packages::Event.count } + subject - expect_no_snowplow_event + expect_no_snowplow_event category: category, action: action end end @@ -183,3 +183,15 @@ RSpec.shared_examples 'bumping the package last downloaded at field' do .to change { package.reload.last_downloaded_at }.from(nil).to(instance_of(ActiveSupport::TimeWithZone)) end end + +RSpec.shared_examples 'a successful package creation' do + it 'creates npm package with file' do + expect { subject } + .to change { project.packages.count }.by(1) + .and change { Packages::PackageFile.count }.by(1) + .and change { Packages::Tag.count }.by(1) + .and change { Packages::Npm::Metadatum.count }.by(1) + + expect(response).to have_gitlab_http_status(:ok) + end +end diff --git a/spec/support/shared_examples/requests/api/pipelines/visibility_table_shared_examples.rb b/spec/support/shared_examples/requests/api/pipelines/visibility_table_shared_examples.rb index 8dd2ef6ccc6..9847ea4e1e2 100644 --- a/spec/support/shared_examples/requests/api/pipelines/visibility_table_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/pipelines/visibility_table_shared_examples.rb @@ -224,10 +224,10 @@ RSpec.shared_examples 'pipelines visibility table' do project.project_feature.update!(project_feature_attributes) project.add_role(ci_user, user_role) if user_role && user_role != :non_member - get api(pipelines_api_path, api_user) + get api(pipelines_api_path, api_user, admin_mode: is_admin) end - it do + specify do expect(response).to have_gitlab_http_status(response_status) expect(api_response).to match(expected_response) end diff --git a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb index 6065b1163c4..9bd430c3b4f 100644 --- a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb @@ -254,6 +254,13 @@ RSpec.shared_examples 'pypi simple API endpoint' do with_them do let(:token) { user_token ? personal_access_token.token : 'wrong' } let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) } + let(:snowplow_gitlab_standard_context) do + if user_role == :anonymous || (visibility_level == :public && !user_token) + snowplow_context + else + snowplow_context.merge(user: user) + end + end before do project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s)) @@ -269,7 +276,7 @@ RSpec.shared_examples 'pypi simple API endpoint' do let(:url) { "/projects/#{project.id}/packages/pypi/simple/my-package" } let(:headers) { basic_auth_header(user.username, personal_access_token.token) } - let(:snowplow_gitlab_standard_context) { { project: project, namespace: group, property: 'i_package_pypi_user' } } + let(:snowplow_gitlab_standard_context) { snowplow_context.merge({ project: project, user: user }) } it_behaves_like 'PyPI package versions', :developer, :success 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 2154a76d765..3913d29e086 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 @@ -9,7 +9,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type| let(:repository_storage_move_id) { storage_move.id } def get_container_repository_storage_move - get api(url, user) + get api(url, user, admin_mode: user.admin?) end it 'returns a container repository storage move', :aggregate_failures do @@ -39,7 +39,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type| shared_examples 'get container repository storage move list' do def get_container_repository_storage_moves - get api(url, user) + get api(url, user, admin_mode: user.admin?) end it 'returns container repository storage moves', :aggregate_failures do @@ -70,7 +70,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type| get_container_repository_storage_moves - json_ids = json_response.map { |storage_move| storage_move['id'] } + json_ids = json_response.pluck('id') expect(json_ids).to eq([storage_move.id, storage_move_middle.id, storage_move_oldest.id]) end @@ -90,7 +90,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type| let(:container_id) { non_existing_record_id } it 'returns not found' do - get api(url, user) + get api(url, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end @@ -108,7 +108,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type| let(:repository_storage_move_id) { storage_move.id } it 'returns not found' do - get api(url, user) + get api(url, user, admin_mode: user.admin?) expect(response).to have_gitlab_http_status(:not_found) end @@ -127,20 +127,20 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type| end end - describe "POST /#{container_type}/:id/repository_storage_moves" do + describe "POST /#{container_type}/:id/repository_storage_moves", :aggregate_failures do let(:container_id) { container.id } let(:url) { "/#{container_type}/#{container_id}/repository_storage_moves" } let(:destination_storage_name) { 'test_second_storage' } def create_container_repository_storage_move - post api(url, user), params: { destination_storage_name: destination_storage_name } + post api(url, user, admin_mode: user.admin?), params: { destination_storage_name: destination_storage_name } end before do stub_storage_settings('test_second_storage' => { 'path' => 'tmp/tests/extra_storage' }) end - it 'schedules a container repository storage move', :aggregate_failures do + it 'schedules a container repository storage move' do create_container_repository_storage_move storage_move = container.repository_storage_moves.last @@ -158,7 +158,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type| it { expect { create_container_repository_storage_move }.to be_denied_for(:user) } end - context 'destination_storage_name is missing', :aggregate_failures do + context 'destination_storage_name is missing' do let(:destination_storage_name) { nil } it 'schedules a container repository storage move' do @@ -192,7 +192,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type| let(:destination_storage_name) { 'test_second_storage' } def create_container_repository_storage_moves - post api(url, user), params: { + post api(url, user, admin_mode: user.admin?), params: { source_storage_name: source_storage_name, destination_storage_name: destination_storage_name } diff --git a/spec/support/shared_examples/requests/api/resolvable_discussions_shared_examples.rb b/spec/support/shared_examples/requests/api/resolvable_discussions_shared_examples.rb index b5139bd8c99..2770e293683 100644 --- a/spec/support/shared_examples/requests/api/resolvable_discussions_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/resolvable_discussions_shared_examples.rb @@ -71,8 +71,7 @@ RSpec.shared_examples 'resolvable discussions API' do |parent_type, noteable_typ it 'returns a 404 error when note id not found' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}/notes/#{non_existing_record_id}", user), - params: { body: 'Hello!' } + "discussions/#{note.discussion_id}/notes/#{non_existing_record_id}", user), params: { body: 'Hello!' } expect(response).to have_gitlab_http_status(:not_found) end diff --git a/spec/support/shared_examples/requests/api/snippets_shared_examples.rb b/spec/support/shared_examples/requests/api/snippets_shared_examples.rb index 1b92eb56f54..56f2394c005 100644 --- a/spec/support/shared_examples/requests/api/snippets_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/snippets_shared_examples.rb @@ -1,12 +1,19 @@ # frozen_string_literal: true RSpec.shared_examples 'raw snippet files' do - let_it_be(:user_token) { create(:personal_access_token, user: snippet.author) } let(:snippet_id) { snippet.id } - let(:user) { snippet.author } + let_it_be(:user) { snippet.author } let(:file_path) { '%2Egitattributes' } let(:ref) { 'master' } + let_it_be(:user_token) do + if user.admin? + create(:personal_access_token, :admin_mode, user: user) + else + create(:personal_access_token, user: user) + end + end + subject { get api(api_path, personal_access_token: user_token) } context 'with an invalid snippet ID' do @@ -15,8 +22,10 @@ RSpec.shared_examples 'raw snippet files' do it 'returns 404' do subject - expect(response).to have_gitlab_http_status(:not_found) - expect(json_response['message']).to eq('404 Snippet Not Found') + aggregate_failures do + expect(response).to have_gitlab_http_status(:not_found) + expect(json_response['message']).to eq('404 Snippet Not Found') + end end end @@ -185,7 +194,7 @@ RSpec.shared_examples 'snippet individual non-file updates' do end RSpec.shared_examples 'invalid snippet updates' do - it 'returns 404 for invalid snippet id' do + it 'returns 404 for invalid snippet id', :aggregate_failures do update_snippet(snippet_id: non_existing_record_id, params: { title: 'foo' }) expect(response).to have_gitlab_http_status(:not_found) @@ -204,7 +213,7 @@ RSpec.shared_examples 'invalid snippet updates' do expect(response).to have_gitlab_http_status(:bad_request) end - it 'returns 400 if title is blank' do + it 'returns 400 if title is blank', :aggregate_failures do update_snippet(params: { title: '' }) expect(response).to have_gitlab_http_status(:bad_request) @@ -236,7 +245,9 @@ RSpec.shared_examples 'snippet access with different users' do it 'returns the correct response' do request_user = user_for(requester) - get api(path, request_user) + admin_mode = requester == :admin + + get api(path, request_user, admin_mode: admin_mode) expect(response).to have_gitlab_http_status(status) end @@ -250,8 +261,6 @@ RSpec.shared_examples 'snippet access with different users' do other_user when :admin admin - else - nil end end diff --git a/spec/support/shared_examples/requests/api/status_shared_examples.rb b/spec/support/shared_examples/requests/api/status_shared_examples.rb index 40843ccbd15..ff3947c0e73 100644 --- a/spec/support/shared_examples/requests/api/status_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/status_shared_examples.rb @@ -21,6 +21,23 @@ RSpec.shared_examples '400 response' do end end +RSpec.shared_examples '401 response' do + let(:message) { nil } + + before do + # Fires the request + request + end + + it 'returns 401' do + expect(response).to have_gitlab_http_status(:unauthorized) + + if message.present? + expect(json_response['message']).to eq(message) + end + end +end + RSpec.shared_examples '403 response' do before do # Fires the request @@ -54,7 +71,7 @@ RSpec.shared_examples '412 response' do let(:params) { nil } let(:success_status) { 204 } - context 'for a modified ressource' do + context 'for a modified resource' do before do delete request, params: params, headers: { 'HTTP_IF_UNMODIFIED_SINCE' => '1990-01-12T00:00:48-0600' } end @@ -65,7 +82,7 @@ RSpec.shared_examples '412 response' do end end - context 'for an unmodified ressource' do + context 'for an unmodified resource' do before do delete request, params: params, headers: { 'HTTP_IF_UNMODIFIED_SINCE' => Time.now } end diff --git a/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb b/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb index 86a1fd76d09..398421c7a79 100644 --- a/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb @@ -173,8 +173,7 @@ RSpec.shared_examples 'time tracking endpoints' do |issuable_name| describe "GET /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_stats" do it "returns the time stats for #{issuable_name}" do - issuable.update!(spend_time: { duration: 1800, user_id: user.id }, - time_estimate: 3600) + issuable.update!(spend_time: { duration: 1800, user_id: user.id }, time_estimate: 3600) get api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_stats", user) |