summaryrefslogtreecommitdiff
path: root/spec/requests
diff options
context:
space:
mode:
Diffstat (limited to 'spec/requests')
-rw-r--r--spec/requests/api/discussions_spec.rb33
-rw-r--r--spec/requests/api/issues_spec.rb24
-rw-r--r--spec/requests/api/jobs_spec.rb6
-rw-r--r--spec/requests/api/merge_requests_spec.rb4
-rw-r--r--spec/requests/api/pipeline_schedules_spec.rb23
-rw-r--r--spec/requests/api/project_hooks_spec.rb4
-rw-r--r--spec/requests/api/project_import_spec.rb68
-rw-r--r--spec/requests/api/project_snapshots_spec.rb51
-rw-r--r--spec/requests/api/projects_spec.rb51
-rw-r--r--spec/requests/api/repositories_spec.rb15
-rw-r--r--spec/requests/api/runner_spec.rb147
-rw-r--r--spec/requests/api/runners_spec.rb155
-rw-r--r--spec/requests/api/users_spec.rb12
-rw-r--r--spec/requests/api/v3/builds_spec.rb4
-rw-r--r--spec/requests/api/v3/merge_requests_spec.rb4
-rw-r--r--spec/requests/lfs_http_spec.rb19
-rw-r--r--spec/requests/openid_connect_spec.rb9
17 files changed, 499 insertions, 130 deletions
diff --git a/spec/requests/api/discussions_spec.rb b/spec/requests/api/discussions_spec.rb
index 4a44b219a67..ef34192f888 100644
--- a/spec/requests/api/discussions_spec.rb
+++ b/spec/requests/api/discussions_spec.rb
@@ -2,32 +2,53 @@ require 'spec_helper'
describe API::Discussions do
let(:user) { create(:user) }
- let!(:project) { create(:project, :public, namespace: user.namespace) }
+ let!(:project) { create(:project, :public, :repository, namespace: user.namespace) }
let(:private_user) { create(:user) }
before do
- project.add_reporter(user)
+ project.add_developer(user)
end
- context "when noteable is an Issue" do
+ context 'when noteable is an Issue' do
let!(:issue) { create(:issue, project: project, author: user) }
let!(:issue_note) { create(:discussion_note_on_issue, noteable: issue, project: project, author: user) }
- it_behaves_like "discussions API", 'projects', 'issues', 'iid' do
+ it_behaves_like 'discussions API', 'projects', 'issues', 'iid' do
let(:parent) { project }
let(:noteable) { issue }
let(:note) { issue_note }
end
end
- context "when noteable is a Snippet" do
+ context 'when noteable is a Snippet' do
let!(:snippet) { create(:project_snippet, project: project, author: user) }
let!(:snippet_note) { create(:discussion_note_on_snippet, noteable: snippet, project: project, author: user) }
- it_behaves_like "discussions API", 'projects', 'snippets', 'id' do
+ it_behaves_like 'discussions API', 'projects', 'snippets', 'id' do
let(:parent) { project }
let(:noteable) { snippet }
let(:note) { snippet_note }
end
end
+
+ context 'when noteable is a Merge Request' do
+ let!(:noteable) { create(:merge_request_with_diffs, source_project: project, target_project: project, author: user) }
+ let!(:note) { create(:discussion_note_on_merge_request, noteable: noteable, project: project, author: user) }
+ let!(:diff_note) { create(:diff_note_on_merge_request, noteable: noteable, project: project, author: user) }
+ let(:parent) { project }
+
+ it_behaves_like 'discussions API', 'projects', 'merge_requests', 'iid'
+ it_behaves_like 'diff discussions API', 'projects', 'merge_requests', 'iid'
+ it_behaves_like 'resolvable discussions API', 'projects', 'merge_requests', 'iid'
+ end
+
+ context 'when noteable is a Commit' do
+ let!(:noteable) { create(:commit, project: project, author: user) }
+ let!(:note) { create(:discussion_note_on_commit, commit_id: noteable.id, project: project, author: user) }
+ let!(:diff_note) { create(:diff_note_on_commit, commit_id: noteable.id, project: project, author: user) }
+ let(:parent) { project }
+
+ it_behaves_like 'discussions API', 'projects', 'repository/commits', 'id'
+ it_behaves_like 'diff discussions API', 'projects', 'repository/commits', 'id'
+ end
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 6614e8cea43..90f9c4ad214 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -384,6 +384,30 @@ describe API::Issues do
end
let(:base_url) { "/groups/#{group.id}/issues" }
+ context 'when group has subgroups', :nested_groups do
+ let(:subgroup_1) { create(:group, parent: group) }
+ let(:subgroup_2) { create(:group, parent: subgroup_1) }
+
+ let(:subgroup_1_project) { create(:project, namespace: subgroup_1) }
+ let(:subgroup_2_project) { create(:project, namespace: subgroup_2) }
+
+ let!(:issue_1) { create(:issue, project: subgroup_1_project) }
+ let!(:issue_2) { create(:issue, project: subgroup_2_project) }
+
+ before do
+ group.add_developer(user)
+ end
+
+ it 'also returns subgroups projects issues' do
+ get api(base_url, user)
+
+ issue_ids = json_response.map { |issue| issue['id'] }
+
+ expect_paginated_array_response(size: 5)
+ expect(issue_ids).to include(issue_1.id, issue_2.id)
+ end
+ end
+
it 'returns all group issues (including opened and closed)' do
get api(base_url, admin)
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index 3ffdfdc0e9a..0a2963452e4 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -281,7 +281,7 @@ describe API::Jobs do
get_artifact_file(artifact)
expect(response).to have_gitlab_http_status(200)
- expect(response.headers)
+ expect(response.headers.to_h)
.to include('Content-Type' => 'application/json',
'Gitlab-Workhorse-Send-Data' => /artifacts-entry/)
end
@@ -311,7 +311,7 @@ describe API::Jobs do
it 'returns specific job artifacts' do
expect(response).to have_gitlab_http_status(200)
- expect(response.headers).to include(download_headers)
+ expect(response.headers.to_h).to include(download_headers)
expect(response.body).to match_file(job.artifacts_file.file.file)
end
end
@@ -462,7 +462,7 @@ describe API::Jobs do
end
it { expect(response).to have_http_status(:ok) }
- it { expect(response.headers).to include(download_headers) }
+ it { expect(response.headers.to_h).to include(download_headers) }
end
context 'when artifacts are stored remotely' do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 3764aec0c71..f64623d7018 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -861,7 +861,7 @@ describe API::MergeRequests do
expect(json_response['title']).to eq('Test merge_request')
end
- it 'returns 422 when target project has disabled merge requests' do
+ it 'returns 403 when target project has disabled merge requests' do
project.project_feature.update(merge_requests_access_level: 0)
post api("/projects/#{forked_project.id}/merge_requests", user2),
@@ -871,7 +871,7 @@ describe API::MergeRequests do
author: user2,
target_project_id: project.id
- expect(response).to have_gitlab_http_status(422)
+ expect(response).to have_gitlab_http_status(403)
end
it "returns 400 when source_branch is missing" do
diff --git a/spec/requests/api/pipeline_schedules_spec.rb b/spec/requests/api/pipeline_schedules_spec.rb
index 7ea25059756..91d4d5d3de9 100644
--- a/spec/requests/api/pipeline_schedules_spec.rb
+++ b/spec/requests/api/pipeline_schedules_spec.rb
@@ -17,6 +17,17 @@ describe API::PipelineSchedules do
pipeline_schedule.pipelines << build(:ci_pipeline, project: project)
end
+ def create_pipeline_schedules(count)
+ create_list(:ci_pipeline_schedule, count, project: project)
+ .each do |pipeline_schedule|
+ create(:user).tap do |user|
+ project.add_developer(user)
+ pipeline_schedule.update_attributes(owner: user)
+ end
+ pipeline_schedule.pipelines << build(:ci_pipeline, project: project)
+ end
+ end
+
it 'returns list of pipeline_schedules' do
get api("/projects/#{project.id}/pipeline_schedules", developer)
@@ -26,18 +37,14 @@ describe API::PipelineSchedules do
end
it 'avoids N + 1 queries' do
+ # We need at least two users to trigger a preload for that relation.
+ create_pipeline_schedules(1)
+
control_count = ActiveRecord::QueryRecorder.new do
get api("/projects/#{project.id}/pipeline_schedules", developer)
end.count
- create_list(:ci_pipeline_schedule, 10, project: project)
- .each do |pipeline_schedule|
- create(:user).tap do |user|
- project.add_developer(user)
- pipeline_schedule.update_attributes(owner: user)
- end
- pipeline_schedule.pipelines << build(:ci_pipeline, project: project)
- end
+ create_pipeline_schedules(10)
expect do
get api("/projects/#{project.id}/pipeline_schedules", developer)
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index 392cad667be..12a183fed1e 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -33,6 +33,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
expect(json_response.first['merge_requests_events']).to eq(true)
expect(json_response.first['tag_push_events']).to eq(true)
expect(json_response.first['note_events']).to eq(true)
+ expect(json_response.first['confidential_note_events']).to eq(true)
expect(json_response.first['job_events']).to eq(true)
expect(json_response.first['pipeline_events']).to eq(true)
expect(json_response.first['wiki_page_events']).to eq(true)
@@ -62,6 +63,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events)
expect(json_response['tag_push_events']).to eq(hook.tag_push_events)
expect(json_response['note_events']).to eq(hook.note_events)
+ expect(json_response['confidential_note_events']).to eq(hook.confidential_note_events)
expect(json_response['job_events']).to eq(hook.job_events)
expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
@@ -104,6 +106,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
expect(json_response['merge_requests_events']).to eq(false)
expect(json_response['tag_push_events']).to eq(false)
expect(json_response['note_events']).to eq(false)
+ expect(json_response['confidential_note_events']).to eq(nil)
expect(json_response['job_events']).to eq(true)
expect(json_response['pipeline_events']).to eq(false)
expect(json_response['wiki_page_events']).to eq(true)
@@ -152,6 +155,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events)
expect(json_response['tag_push_events']).to eq(hook.tag_push_events)
expect(json_response['note_events']).to eq(hook.note_events)
+ expect(json_response['confidential_note_events']).to eq(hook.confidential_note_events)
expect(json_response['job_events']).to eq(hook.job_events)
expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
diff --git a/spec/requests/api/project_import_spec.rb b/spec/requests/api/project_import_spec.rb
index 987f6e26971..f68057a92a1 100644
--- a/spec/requests/api/project_import_spec.rb
+++ b/spec/requests/api/project_import_spec.rb
@@ -40,7 +40,7 @@ describe API::ProjectImport do
expect(response).to have_gitlab_http_status(201)
end
- it 'schedules an import at the user namespace level' do
+ it 'does not shedule an import for a nampespace that does not exist' do
expect_any_instance_of(Project).not_to receive(:import_schedule)
expect(::Projects::CreateService).not_to receive(:new)
@@ -71,6 +71,72 @@ describe API::ProjectImport do
expect(json_response['error']).to eq('file is invalid')
end
+ it 'stores params that can be overridden' do
+ stub_import(namespace)
+ override_params = { 'description' => 'Hello world' }
+
+ post api('/projects/import', user),
+ path: 'test-import',
+ file: fixture_file_upload(file),
+ namespace: namespace.id,
+ override_params: override_params
+ import_project = Project.find(json_response['id'])
+
+ expect(import_project.import_data.data['override_params']).to eq(override_params)
+ end
+
+ it 'does not store params that are not allowed' do
+ stub_import(namespace)
+ override_params = { 'not_allowed' => 'Hello world' }
+
+ post api('/projects/import', user),
+ path: 'test-import',
+ file: fixture_file_upload(file),
+ namespace: namespace.id,
+ override_params: override_params
+ import_project = Project.find(json_response['id'])
+
+ expect(import_project.import_data.data['override_params']).to be_empty
+ end
+
+ it 'correctly overrides params during the import' do
+ override_params = { 'description' => 'Hello world' }
+
+ Sidekiq::Testing.inline! do
+ post api('/projects/import', user),
+ path: 'test-import',
+ file: fixture_file_upload(file),
+ namespace: namespace.id,
+ override_params: override_params
+ end
+ import_project = Project.find(json_response['id'])
+
+ expect(import_project.description).to eq('Hello world')
+ end
+
+ context 'when target path already exists in namespace' do
+ let(:existing_project) { create(:project, namespace: user.namespace) }
+
+ it 'does not schedule an import' do
+ expect_any_instance_of(Project).not_to receive(:import_schedule)
+
+ post api('/projects/import', user), path: existing_project.path, file: fixture_file_upload(file)
+
+ expect(response).to have_gitlab_http_status(400)
+ expect(json_response['message']).to eq('Name has already been taken')
+ end
+
+ context 'when param overwrite is true' do
+ it 'schedules an import' do
+ stub_import(user.namespace)
+
+ post api('/projects/import', user), path: existing_project.path, file: fixture_file_upload(file), overwrite: true
+
+ expect(response).to have_gitlab_http_status(201)
+ end
+ end
+ end
+
def stub_import(namespace)
expect_any_instance_of(Project).to receive(:import_schedule)
expect(::Projects::CreateService).to receive(:new).with(user, hash_including(namespace_id: namespace.id)).and_call_original
diff --git a/spec/requests/api/project_snapshots_spec.rb b/spec/requests/api/project_snapshots_spec.rb
new file mode 100644
index 00000000000..07a920f8d28
--- /dev/null
+++ b/spec/requests/api/project_snapshots_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+describe API::ProjectSnapshots do
+ include WorkhorseHelpers
+
+ let(:project) { create(:project) }
+ let(:admin) { create(:admin) }
+
+ describe 'GET /projects/:id/snapshot' do
+ def expect_snapshot_response_for(repository)
+ type, params = workhorse_send_data
+
+ expect(type).to eq('git-snapshot')
+ expect(params).to eq(
+ 'GitalyServer' => {
+ 'address' => Gitlab::GitalyClient.address(repository.project.repository_storage),
+ 'token' => Gitlab::GitalyClient.token(repository.project.repository_storage)
+ },
+ 'GetSnapshotRequest' => Gitaly::GetSnapshotRequest.new(
+ repository: repository.gitaly_repository
+ ).to_json
+ )
+ end
+
+ it 'returns authentication error as project owner' do
+ get api("/projects/#{project.id}/snapshot", project.owner)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+
+ it 'returns authentication error as unauthenticated user' do
+ get api("/projects/#{project.id}/snapshot", nil)
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ it 'requests project repository raw archive as administrator' do
+ get api("/projects/#{project.id}/snapshot", admin), wiki: '0'
+
+ expect(response).to have_gitlab_http_status(200)
+ expect_snapshot_response_for(project.repository)
+ end
+
+ it 'requests wiki repository raw archive as administrator' do
+ get api("/projects/#{project.id}/snapshot", admin), wiki: '1'
+
+ expect(response).to have_gitlab_http_status(200)
+ expect_snapshot_response_for(project.wiki.repository)
+ end
+ end
+end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 2ec29a79e93..85a571b8f0e 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1,6 +1,18 @@
# -*- coding: utf-8 -*-
require 'spec_helper'
+shared_examples 'languages and percentages JSON response' do
+ let(:expected_languages) { project.repository.languages.map { |language| language.values_at(:label, :value)}.to_h }
+
+ it 'returns expected language values' do
+ get api("/projects/#{project.id}/languages", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq(expected_languages)
+ expect(json_response.count).to be > 1
+ end
+end
+
describe API::Projects do
let(:user) { create(:user) }
let(:user2) { create(:user) }
@@ -673,7 +685,8 @@ describe API::Projects do
issues_enabled: false,
merge_requests_enabled: false,
wiki_enabled: false,
- request_access_enabled: true
+ request_access_enabled: true,
+ jobs_enabled: true
})
post api("/projects/user/#{user.id}", admin), project
@@ -1694,6 +1707,42 @@ describe API::Projects do
end
end
+ describe 'GET /projects/:id/languages' do
+ context 'with an authorized user' do
+ it_behaves_like 'languages and percentages JSON response' do
+ let(:project) { project3 }
+ end
+
+ it 'returns not_found(404) for not existing project' do
+ get api("/projects/9999999999/languages", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'with not authorized user' do
+ it 'returns not_found for existing but unauthorized project' do
+ get api("/projects/#{project3.id}/languages", user3)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'without user' do
+ let(:project_public) { create(:project, :public, :repository) }
+
+ it_behaves_like 'languages and percentages JSON response' do
+ let(:project) { project_public }
+ end
+
+ it 'returns not_found for existing but unauthorized project' do
+ get api("/projects/#{project3.id}/languages", nil)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
describe 'DELETE /projects/:id' do
context 'when authenticated as user' do
it 'removes project' do
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 741800ff61d..9e6d69e3874 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -427,5 +427,20 @@ describe API::Repositories do
let(:request) { get api(route, guest) }
end
end
+
+ # Regression: https://gitlab.com/gitlab-org/gitlab-ce/issues/45363
+ describe 'Links header contains working URLs when no `order_by` nor `sort` is given' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:current_user) { nil }
+
+ it 'returns `Link` header that includes URLs with default value for `order_by` & `sort`' do
+ get api(route, current_user)
+
+ first_link_url = response.headers['Link'].split(';').first
+
+ expect(first_link_url).to include('order_by=commits')
+ expect(first_link_url).to include('sort=asc')
+ end
+ end
end
end
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 4f3420cc0ad..9ae39f2ef44 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -40,18 +40,36 @@ describe API::Runner do
expect(json_response['token']).to eq(runner.token)
expect(runner.run_untagged).to be true
expect(runner.token).not_to eq(registration_token)
+ expect(runner).to be_instance_type
end
context 'when project token is used' do
let(:project) { create(:project) }
- it 'creates runner' do
+ it 'creates project runner' do
post api('/runners'), token: project.runners_token
expect(response).to have_gitlab_http_status 201
expect(project.runners.size).to eq(1)
- expect(Ci::Runner.first.token).not_to eq(registration_token)
- expect(Ci::Runner.first.token).not_to eq(project.runners_token)
+ runner = Ci::Runner.first
+ expect(runner.token).not_to eq(registration_token)
+ expect(runner.token).not_to eq(project.runners_token)
+ expect(runner).to be_project_type
+ end
+ end
+
+ context 'when group token is used' do
+ let(:group) { create(:group) }
+
+ it 'creates a group runner' do
+ post api('/runners'), token: group.runners_token
+
+ expect(response).to have_http_status 201
+ expect(group.runners.size).to eq(1)
+ runner = Ci::Runner.first
+ expect(runner.token).not_to eq(registration_token)
+ expect(runner.token).not_to eq(group.runners_token)
+ expect(runner).to be_group_type
end
end
end
@@ -406,7 +424,7 @@ describe API::Runner do
expect(json_response['image']).to eq({ 'name' => 'ruby:2.1', 'entrypoint' => '/bin/sh' })
expect(json_response['services']).to eq([{ 'name' => 'postgres', 'entrypoint' => nil,
'alias' => nil, 'command' => nil },
- { 'name' => 'docker:dind', 'entrypoint' => '/bin/sh',
+ { 'name' => 'docker:stable-dind', 'entrypoint' => '/bin/sh',
'alias' => 'docker', 'command' => 'sleep 30' }])
expect(json_response['steps']).to eq(expected_steps)
expect(json_response['artifacts']).to eq(expected_artifacts)
@@ -950,12 +968,53 @@ describe API::Runner do
describe 'POST /api/v4/jobs/:id/artifacts/authorize' do
context 'when using token as parameter' do
- it 'authorizes posting artifacts to running job' do
- authorize_artifacts_with_token_in_params
+ context 'posting artifacts to running job' do
+ subject do
+ authorize_artifacts_with_token_in_params
+ end
- expect(response).to have_gitlab_http_status(200)
- expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
- expect(json_response['TempPath']).not_to be_nil
+ shared_examples 'authorizes local file' do
+ it 'succeeds' do
+ subject
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
+ expect(json_response['TempPath']).to eq(JobArtifactUploader.workhorse_local_upload_path)
+ expect(json_response['RemoteObject']).to be_nil
+ end
+ end
+
+ context 'when using local storage' do
+ it_behaves_like 'authorizes local file'
+ end
+
+ context 'when using remote storage' do
+ context 'when direct upload is enabled' do
+ before do
+ stub_artifacts_object_storage(enabled: true, direct_upload: true)
+ end
+
+ it 'succeeds' do
+ subject
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
+ expect(json_response['TempPath']).to eq(JobArtifactUploader.workhorse_local_upload_path)
+ expect(json_response['RemoteObject']).to have_key('ID')
+ expect(json_response['RemoteObject']).to have_key('GetURL')
+ expect(json_response['RemoteObject']).to have_key('StoreURL')
+ expect(json_response['RemoteObject']).to have_key('DeleteURL')
+ end
+ end
+
+ context 'when direct upload is disabled' do
+ before do
+ stub_artifacts_object_storage(enabled: true, direct_upload: false)
+ end
+
+ it_behaves_like 'authorizes local file'
+ end
+ end
end
it 'fails to post too large artifact' do
@@ -1051,20 +1110,45 @@ describe API::Runner do
end
end
- context 'when uses regular file post' do
- before do
- upload_artifacts(file_upload, headers_with_token, false)
+ context 'when uses accelerated file post' do
+ context 'for file stored locally' do
+ before do
+ upload_artifacts(file_upload, headers_with_token)
+ end
+
+ it_behaves_like 'successful artifacts upload'
end
- it_behaves_like 'successful artifacts upload'
- end
+ context 'for file stored remotelly' do
+ let!(:fog_connection) do
+ stub_artifacts_object_storage(direct_upload: true)
+ end
- context 'when uses accelerated file post' do
- before do
- upload_artifacts(file_upload, headers_with_token, true)
- end
+ before do
+ fog_connection.directories.get('artifacts').files.create(
+ key: 'tmp/upload/12312300',
+ body: 'content'
+ )
+
+ upload_artifacts(file_upload, headers_with_token,
+ { 'file.remote_id' => remote_id })
+ end
+
+ context 'when valid remote_id is used' do
+ let(:remote_id) { '12312300' }
+
+ it_behaves_like 'successful artifacts upload'
+ end
- it_behaves_like 'successful artifacts upload'
+ context 'when invalid remote_id is used' do
+ let(:remote_id) { 'invalid id' }
+
+ it 'responds with bad request' do
+ expect(response).to have_gitlab_http_status(500)
+ expect(json_response['message']).to eq("Missing file")
+ end
+ end
+ end
end
context 'when using runners token' do
@@ -1208,15 +1292,19 @@ describe API::Runner do
end
context 'when artifacts are being stored outside of tmp path' do
+ let(:new_tmpdir) { Dir.mktmpdir }
+
before do
+ # init before overwriting tmp dir
+ file_upload
+
# by configuring this path we allow to pass file from @tmpdir only
# but all temporary files are stored in system tmp directory
- @tmpdir = Dir.mktmpdir
- allow(JobArtifactUploader).to receive(:workhorse_upload_path).and_return(@tmpdir)
+ allow(Dir).to receive(:tmpdir).and_return(new_tmpdir)
end
after do
- FileUtils.remove_entry @tmpdir
+ FileUtils.remove_entry(new_tmpdir)
end
it' "fails to post artifacts for outside of tmp path"' do
@@ -1226,12 +1314,11 @@ describe API::Runner do
end
end
- def upload_artifacts(file, headers = {}, accelerated = true)
- params = if accelerated
- { 'file.path' => file.path, 'file.name' => file.original_filename }
- else
- { 'file' => file }
- end
+ def upload_artifacts(file, headers = {}, params = {})
+ params = params.merge({
+ 'file.path' => file.path,
+ 'file.name' => file.original_filename
+ })
post api("/jobs/#{job.id}/artifacts"), params, headers
end
@@ -1261,7 +1348,7 @@ describe API::Runner do
it 'download artifacts' do
expect(response).to have_http_status(200)
- expect(response.headers).to include download_headers
+ expect(response.headers.to_h).to include download_headers
end
end
@@ -1276,7 +1363,7 @@ describe API::Runner do
it 'uses workhorse send-url' do
expect(response).to have_gitlab_http_status(200)
- expect(response.headers).to include(
+ expect(response.headers.to_h).to include(
'Gitlab-Workhorse-Send-Data' => /send-url:/)
end
end
diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb
index d30f0cf36e2..f22fec31514 100644
--- a/spec/requests/api/runners_spec.rb
+++ b/spec/requests/api/runners_spec.rb
@@ -8,22 +8,27 @@ describe API::Runners do
let(:project) { create(:project, creator_id: user.id) }
let(:project2) { create(:project, creator_id: user.id) }
- let!(:shared_runner) { create(:ci_runner, :shared) }
- let!(:unused_specific_runner) { create(:ci_runner) }
+ let(:group) { create(:group).tap { |group| group.add_owner(user) } }
+ let(:group2) { create(:group).tap { |group| group.add_owner(user) } }
- let!(:specific_runner) do
- create(:ci_runner).tap do |runner|
+ let!(:shared_runner) { create(:ci_runner, :shared, description: 'Shared runner') }
+ let!(:unused_project_runner) { create(:ci_runner) }
+
+ let!(:project_runner) do
+ create(:ci_runner, description: 'Project runner').tap do |runner|
create(:ci_runner_project, runner: runner, project: project)
end
end
let!(:two_projects_runner) do
- create(:ci_runner).tap do |runner|
+ create(:ci_runner, description: 'Two projects runner').tap do |runner|
create(:ci_runner_project, runner: runner, project: project)
create(:ci_runner_project, runner: runner, project: project2)
end
end
+ let!(:group_runner) { create(:ci_runner, description: 'Group runner', groups: [group]) }
+
before do
# Set project access for users
create(:project_member, :master, user: user, project: project)
@@ -37,9 +42,13 @@ describe API::Runners do
get api('/runners', user)
shared = json_response.any? { |r| r['is_shared'] }
+ descriptions = json_response.map { |runner| runner['description'] }
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
+ expect(descriptions).to contain_exactly(
+ 'Project runner', 'Two projects runner'
+ )
expect(shared).to be_falsey
end
@@ -129,10 +138,16 @@ describe API::Runners do
context 'when runner is not shared' do
it "returns runner's details" do
- get api("/runners/#{specific_runner.id}", admin)
+ get api("/runners/#{project_runner.id}", admin)
expect(response).to have_gitlab_http_status(200)
- expect(json_response['description']).to eq(specific_runner.description)
+ expect(json_response['description']).to eq(project_runner.description)
+ end
+
+ it "returns the project's details for a project runner" do
+ get api("/runners/#{project_runner.id}", admin)
+
+ expect(json_response['projects'].first['id']).to eq(project.id)
end
end
@@ -146,10 +161,10 @@ describe API::Runners do
context "runner project's administrative user" do
context 'when runner is not shared' do
it "returns runner's details" do
- get api("/runners/#{specific_runner.id}", user)
+ get api("/runners/#{project_runner.id}", user)
expect(response).to have_gitlab_http_status(200)
- expect(json_response['description']).to eq(specific_runner.description)
+ expect(json_response['description']).to eq(project_runner.description)
end
end
@@ -164,18 +179,18 @@ describe API::Runners do
end
context 'other authorized user' do
- it "does not return runner's details" do
- get api("/runners/#{specific_runner.id}", user2)
+ it "does not return project runner's details" do
+ get api("/runners/#{project_runner.id}", user2)
- expect(response).to have_gitlab_http_status(403)
+ expect(response).to have_http_status(403)
end
end
context 'unauthorized user' do
- it "does not return runner's details" do
- get api("/runners/#{specific_runner.id}")
+ it "does not return project runner's details" do
+ get api("/runners/#{project_runner.id}")
- expect(response).to have_gitlab_http_status(401)
+ expect(response).to have_http_status(401)
end
end
end
@@ -212,16 +227,16 @@ describe API::Runners do
context 'when runner is not shared' do
it 'updates runner' do
- description = specific_runner.description
- runner_queue_value = specific_runner.ensure_runner_queue_value
+ description = project_runner.description
+ runner_queue_value = project_runner.ensure_runner_queue_value
- update_runner(specific_runner.id, admin, description: 'test')
- specific_runner.reload
+ update_runner(project_runner.id, admin, description: 'test')
+ project_runner.reload
expect(response).to have_gitlab_http_status(200)
- expect(specific_runner.description).to eq('test')
- expect(specific_runner.description).not_to eq(description)
- expect(specific_runner.ensure_runner_queue_value)
+ expect(project_runner.description).to eq('test')
+ expect(project_runner.description).not_to eq(description)
+ expect(project_runner.ensure_runner_queue_value)
.not_to eq(runner_queue_value)
end
end
@@ -247,29 +262,29 @@ describe API::Runners do
end
context 'when runner is not shared' do
- it 'does not update runner without access to it' do
- put api("/runners/#{specific_runner.id}", user2), description: 'test'
+ it 'does not update project runner without access to it' do
+ put api("/runners/#{project_runner.id}", user2), description: 'test'
- expect(response).to have_gitlab_http_status(403)
+ expect(response).to have_http_status(403)
end
- it 'updates runner with access to it' do
- description = specific_runner.description
- put api("/runners/#{specific_runner.id}", admin), description: 'test'
- specific_runner.reload
+ it 'updates project runner with access to it' do
+ description = project_runner.description
+ put api("/runners/#{project_runner.id}", admin), description: 'test'
+ project_runner.reload
expect(response).to have_gitlab_http_status(200)
- expect(specific_runner.description).to eq('test')
- expect(specific_runner.description).not_to eq(description)
+ expect(project_runner.description).to eq('test')
+ expect(project_runner.description).not_to eq(description)
end
end
end
context 'unauthorized user' do
- it 'does not delete runner' do
- put api("/runners/#{specific_runner.id}")
+ it 'does not delete project runner' do
+ put api("/runners/#{project_runner.id}")
- expect(response).to have_gitlab_http_status(401)
+ expect(response).to have_http_status(401)
end
end
end
@@ -293,17 +308,17 @@ describe API::Runners do
context 'when runner is not shared' do
it 'deletes unused runner' do
expect do
- delete api("/runners/#{unused_specific_runner.id}", admin)
+ delete api("/runners/#{unused_project_runner.id}", admin)
expect(response).to have_gitlab_http_status(204)
end.to change { Ci::Runner.specific.count }.by(-1)
end
- it 'deletes used runner' do
+ it 'deletes used project runner' do
expect do
- delete api("/runners/#{specific_runner.id}", admin)
+ delete api("/runners/#{project_runner.id}", admin)
- expect(response).to have_gitlab_http_status(204)
+ expect(response).to have_http_status(204)
end.to change { Ci::Runner.specific.count }.by(-1)
end
end
@@ -325,34 +340,34 @@ describe API::Runners do
context 'when runner is not shared' do
it 'does not delete runner without access to it' do
- delete api("/runners/#{specific_runner.id}", user2)
+ delete api("/runners/#{project_runner.id}", user2)
expect(response).to have_gitlab_http_status(403)
end
- it 'does not delete runner with more than one associated project' do
+ it 'does not delete project runner with more than one associated project' do
delete api("/runners/#{two_projects_runner.id}", user)
expect(response).to have_gitlab_http_status(403)
end
- it 'deletes runner for one owned project' do
+ it 'deletes project runner for one owned project' do
expect do
- delete api("/runners/#{specific_runner.id}", user)
+ delete api("/runners/#{project_runner.id}", user)
- expect(response).to have_gitlab_http_status(204)
+ expect(response).to have_http_status(204)
end.to change { Ci::Runner.specific.count }.by(-1)
end
it_behaves_like '412 response' do
- let(:request) { api("/runners/#{specific_runner.id}", user) }
+ let(:request) { api("/runners/#{project_runner.id}", user) }
end
end
end
context 'unauthorized user' do
- it 'does not delete runner' do
- delete api("/runners/#{specific_runner.id}")
+ it 'does not delete project runner' do
+ delete api("/runners/#{project_runner.id}")
- expect(response).to have_gitlab_http_status(401)
+ expect(response).to have_http_status(401)
end
end
end
@@ -361,8 +376,8 @@ describe API::Runners do
set(:job_1) { create(:ci_build) }
let!(:job_2) { create(:ci_build, :running, runner: shared_runner, project: project) }
let!(:job_3) { create(:ci_build, :failed, runner: shared_runner, project: project) }
- let!(:job_4) { create(:ci_build, :running, runner: specific_runner, project: project) }
- let!(:job_5) { create(:ci_build, :failed, runner: specific_runner, project: project) }
+ let!(:job_4) { create(:ci_build, :running, runner: project_runner, project: project) }
+ let!(:job_5) { create(:ci_build, :failed, runner: project_runner, project: project) }
context 'admin user' do
context 'when runner exists' do
@@ -380,7 +395,7 @@ describe API::Runners do
context 'when runner is specific' do
it 'return jobs' do
- get api("/runners/#{specific_runner.id}/jobs", admin)
+ get api("/runners/#{project_runner.id}/jobs", admin)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
@@ -392,7 +407,7 @@ describe API::Runners do
context 'when valid status is provided' do
it 'return filtered jobs' do
- get api("/runners/#{specific_runner.id}/jobs?status=failed", admin)
+ get api("/runners/#{project_runner.id}/jobs?status=failed", admin)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
@@ -405,7 +420,7 @@ describe API::Runners do
context 'when invalid status is provided' do
it 'return 400' do
- get api("/runners/#{specific_runner.id}/jobs?status=non-existing", admin)
+ get api("/runners/#{project_runner.id}/jobs?status=non-existing", admin)
expect(response).to have_gitlab_http_status(400)
end
@@ -433,7 +448,7 @@ describe API::Runners do
context 'when runner is specific' do
it 'return jobs' do
- get api("/runners/#{specific_runner.id}/jobs", user)
+ get api("/runners/#{project_runner.id}/jobs", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
@@ -445,7 +460,7 @@ describe API::Runners do
context 'when valid status is provided' do
it 'return filtered jobs' do
- get api("/runners/#{specific_runner.id}/jobs?status=failed", user)
+ get api("/runners/#{project_runner.id}/jobs?status=failed", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
@@ -458,7 +473,7 @@ describe API::Runners do
context 'when invalid status is provided' do
it 'return 400' do
- get api("/runners/#{specific_runner.id}/jobs?status=non-existing", user)
+ get api("/runners/#{project_runner.id}/jobs?status=non-existing", user)
expect(response).to have_gitlab_http_status(400)
end
@@ -476,7 +491,7 @@ describe API::Runners do
context 'other authorized user' do
it 'does not return jobs' do
- get api("/runners/#{specific_runner.id}/jobs", user2)
+ get api("/runners/#{project_runner.id}/jobs", user2)
expect(response).to have_gitlab_http_status(403)
end
@@ -484,7 +499,7 @@ describe API::Runners do
context 'unauthorized user' do
it 'does not return jobs' do
- get api("/runners/#{specific_runner.id}/jobs")
+ get api("/runners/#{project_runner.id}/jobs")
expect(response).to have_gitlab_http_status(401)
end
@@ -523,7 +538,7 @@ describe API::Runners do
describe 'POST /projects/:id/runners' do
context 'authorized user' do
- let(:specific_runner2) do
+ let(:project_runner2) do
create(:ci_runner).tap do |runner|
create(:ci_runner_project, runner: runner, project: project2)
end
@@ -531,23 +546,23 @@ describe API::Runners do
it 'enables specific runner' do
expect do
- post api("/projects/#{project.id}/runners", user), runner_id: specific_runner2.id
+ post api("/projects/#{project.id}/runners", user), runner_id: project_runner2.id
end.to change { project.runners.count }.by(+1)
expect(response).to have_gitlab_http_status(201)
end
it 'avoids changes when enabling already enabled runner' do
expect do
- post api("/projects/#{project.id}/runners", user), runner_id: specific_runner.id
+ post api("/projects/#{project.id}/runners", user), runner_id: project_runner.id
end.to change { project.runners.count }.by(0)
expect(response).to have_gitlab_http_status(409)
end
it 'does not enable locked runner' do
- specific_runner2.update(locked: true)
+ project_runner2.update(locked: true)
expect do
- post api("/projects/#{project.id}/runners", user), runner_id: specific_runner2.id
+ post api("/projects/#{project.id}/runners", user), runner_id: project_runner2.id
end.to change { project.runners.count }.by(0)
expect(response).to have_gitlab_http_status(403)
@@ -559,10 +574,16 @@ describe API::Runners do
expect(response).to have_gitlab_http_status(403)
end
+ it 'does not enable group runner' do
+ post api("/projects/#{project.id}/runners", user), runner_id: group_runner.id
+
+ expect(response).to have_http_status(403)
+ end
+
context 'user is admin' do
it 'enables any specific runner' do
expect do
- post api("/projects/#{project.id}/runners", admin), runner_id: unused_specific_runner.id
+ post api("/projects/#{project.id}/runners", admin), runner_id: unused_project_runner.id
end.to change { project.runners.count }.by(+1)
expect(response).to have_gitlab_http_status(201)
end
@@ -570,7 +591,7 @@ describe API::Runners do
context 'user is not admin' do
it 'does not enable runner without access to' do
- post api("/projects/#{project.id}/runners", user), runner_id: unused_specific_runner.id
+ post api("/projects/#{project.id}/runners", user), runner_id: unused_project_runner.id
expect(response).to have_gitlab_http_status(403)
end
@@ -619,7 +640,7 @@ describe API::Runners do
context 'when runner have one associated projects' do
it "does not disable project's runner" do
expect do
- delete api("/projects/#{project.id}/runners/#{specific_runner.id}", user)
+ delete api("/projects/#{project.id}/runners/#{project_runner.id}", user)
end.to change { project.runners.count }.by(0)
expect(response).to have_gitlab_http_status(403)
end
@@ -634,7 +655,7 @@ describe API::Runners do
context 'authorized user without permissions' do
it "does not disable project's runner" do
- delete api("/projects/#{project.id}/runners/#{specific_runner.id}", user2)
+ delete api("/projects/#{project.id}/runners/#{project_runner.id}", user2)
expect(response).to have_gitlab_http_status(403)
end
@@ -642,7 +663,7 @@ describe API::Runners do
context 'unauthorized user' do
it "does not disable project's runner" do
- delete api("/projects/#{project.id}/runners/#{specific_runner.id}")
+ delete api("/projects/#{project.id}/runners/#{project_runner.id}")
expect(response).to have_gitlab_http_status(401)
end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index f406d2ffb22..e8196980a8c 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -212,6 +212,18 @@ describe API::Users do
expect(json_response.last['id']).to eq(user.id)
end
+ it 'returns users with 2fa enabled' do
+ admin
+ user
+ user_with_2fa = create(:user, :two_factor_via_otp)
+
+ get api('/users', admin), { two_factor: 'enabled' }
+
+ expect(response).to match_response_schema('public_api/v4/user/admins')
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['id']).to eq(user_with_2fa.id)
+ end
+
it 'returns 400 when provided incorrect sort params' do
get api('/users', admin), { order_by: 'magic', sort: 'asc' }
diff --git a/spec/requests/api/v3/builds_spec.rb b/spec/requests/api/v3/builds_spec.rb
index 00f067889a0..485d7c2cc43 100644
--- a/spec/requests/api/v3/builds_spec.rb
+++ b/spec/requests/api/v3/builds_spec.rb
@@ -232,7 +232,7 @@ describe API::V3::Builds do
it 'returns specific job artifacts' do
expect(response).to have_http_status(200)
- expect(response.headers).to include(download_headers)
+ expect(response.headers.to_h).to include(download_headers)
expect(response.body).to match_file(build.artifacts_file.file.file)
end
end
@@ -332,7 +332,7 @@ describe API::V3::Builds do
end
it { expect(response).to have_http_status(200) }
- it { expect(response.headers).to include(download_headers) }
+ it { expect(response.headers.to_h).to include(download_headers) }
end
context 'when artifacts are stored remotely' do
diff --git a/spec/requests/api/v3/merge_requests_spec.rb b/spec/requests/api/v3/merge_requests_spec.rb
index 6b748369f0d..be70cb24dce 100644
--- a/spec/requests/api/v3/merge_requests_spec.rb
+++ b/spec/requests/api/v3/merge_requests_spec.rb
@@ -340,7 +340,7 @@ describe API::MergeRequests do
expect(json_response['title']).to eq('Test merge_request')
end
- it "returns 422 when target project has disabled merge requests" do
+ it "returns 403 when target project has disabled merge requests" do
project.project_feature.update(merge_requests_access_level: 0)
post v3_api("/projects/#{forked_project.id}/merge_requests", user2),
@@ -350,7 +350,7 @@ describe API::MergeRequests do
author: user2,
target_project_id: project.id
- expect(response).to have_gitlab_http_status(422)
+ expect(response).to have_gitlab_http_status(403)
end
it "returns 400 when source_branch is missing" do
diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb
index 1e6bd993c08..f80abb06fca 100644
--- a/spec/requests/lfs_http_spec.rb
+++ b/spec/requests/lfs_http_spec.rb
@@ -1016,7 +1016,7 @@ describe 'Git LFS API and storage' do
it_behaves_like 'a valid response' do
it 'responds with status 200, location of lfs remote store and object details' do
- expect(json_response['TempPath']).to be_nil
+ expect(json_response['TempPath']).to eq(LfsObjectUploader.workhorse_local_upload_path)
expect(json_response['RemoteObject']).to have_key('ID')
expect(json_response['RemoteObject']).to have_key('GetURL')
expect(json_response['RemoteObject']).to have_key('StoreURL')
@@ -1073,7 +1073,9 @@ describe 'Git LFS API and storage' do
['123123', '../../123123'].each do |remote_id|
context "with invalid remote_id: #{remote_id}" do
subject do
- put_finalize_with_args('file.remote_id' => remote_id)
+ put_finalize(with_tempfile: true, args: {
+ 'file.remote_id' => remote_id
+ })
end
it 'responds with status 403' do
@@ -1093,9 +1095,10 @@ describe 'Git LFS API and storage' do
end
subject do
- put_finalize_with_args(
+ put_finalize(with_tempfile: true, args: {
'file.remote_id' => '12312300',
- 'file.name' => 'name')
+ 'file.name' => 'name'
+ })
end
it 'responds with status 200' do
@@ -1331,7 +1334,7 @@ describe 'Git LFS API and storage' do
put "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}/#{sample_size}/authorize", nil, authorize_headers
end
- def put_finalize(lfs_tmp = lfs_tmp_file, with_tempfile: false)
+ def put_finalize(lfs_tmp = lfs_tmp_file, with_tempfile: false, args: {})
upload_path = LfsObjectUploader.workhorse_local_upload_path
file_path = upload_path + '/' + lfs_tmp if lfs_tmp
@@ -1340,12 +1343,12 @@ describe 'Git LFS API and storage' do
FileUtils.touch(file_path)
end
- args = {
+ extra_args = {
'file.path' => file_path,
'file.name' => File.basename(file_path)
- }.compact
+ }
- put_finalize_with_args(args)
+ put_finalize_with_args(args.merge(extra_args).compact)
end
def put_finalize_with_args(args)
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index 6bed8e812c0..cd1a6cfc427 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -153,4 +153,13 @@ describe 'OpenID Connect requests' do
end
end
end
+
+ context 'OpenID configuration information' do
+ it 'correctly returns the configuration' do
+ get '/.well-known/openid-configuration'
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response).to have_key('issuer')
+ end
+ end
end