summaryrefslogtreecommitdiff
path: root/spec/requests/api
diff options
context:
space:
mode:
Diffstat (limited to 'spec/requests/api')
-rw-r--r--spec/requests/api/doorkeeper_access_spec.rb16
-rw-r--r--spec/requests/api/environments_spec.rb5
-rw-r--r--spec/requests/api/groups_spec.rb4
-rw-r--r--spec/requests/api/issues_spec.rb7
-rw-r--r--spec/requests/api/jobs_spec.rb408
-rw-r--r--spec/requests/api/merge_requests_spec.rb7
-rw-r--r--spec/requests/api/milestones_spec.rb7
-rw-r--r--spec/requests/api/project_hooks_spec.rb8
-rw-r--r--spec/requests/api/projects_spec.rb4
-rw-r--r--spec/requests/api/users_spec.rb8
-rw-r--r--spec/requests/api/v3/builds_spec.rb (renamed from spec/requests/api/builds_spec.rb)30
-rw-r--r--spec/requests/api/v3/deployments_spec.rb71
-rw-r--r--spec/requests/api/v3/issues_spec.rb7
-rw-r--r--spec/requests/api/v3/merge_request_diffs_spec.rb49
-rw-r--r--spec/requests/api/v3/merge_requests_spec.rb7
-rw-r--r--spec/requests/api/v3/milestones_spec.rb7
-rw-r--r--spec/requests/api/v3/project_hooks_spec.rb216
17 files changed, 831 insertions, 30 deletions
diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb
index bd9ecaf2685..2974875510a 100644
--- a/spec/requests/api/doorkeeper_access_spec.rb
+++ b/spec/requests/api/doorkeeper_access_spec.rb
@@ -1,17 +1,23 @@
require 'spec_helper'
-describe API::API, api: true do
+describe API::API, api: true do
include ApiHelpers
let!(:user) { create(:user) }
let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) }
let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
- describe "when unauthenticated" do
+ describe "unauthenticated" do
it "returns authentication success" do
get api("/user"), access_token: token.token
expect(response).to have_http_status(200)
end
+
+ include_examples 'user login request with unique ip limit' do
+ def request
+ get api('/user'), access_token: token.token
+ end
+ end
end
describe "when token invalid" do
@@ -26,5 +32,11 @@ describe API::API, api: true do
get api("/user", user)
expect(response).to have_http_status(200)
end
+
+ include_examples 'user login request with unique ip limit' do
+ def request
+ get api('/user', user)
+ end
+ end
end
end
diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb
index f2fd1dfc8db..b54ee8e8b85 100644
--- a/spec/requests/api/environments_spec.rb
+++ b/spec/requests/api/environments_spec.rb
@@ -15,6 +15,8 @@ describe API::Environments, api: true do
describe 'GET /projects/:id/environments' do
context 'as member of the project' do
it 'returns project environments' do
+ project_data_keys = %w(id http_url_to_repo web_url name name_with_namespace path path_with_namespace)
+
get api("/projects/#{project.id}/environments", user)
expect(response).to have_http_status(200)
@@ -23,8 +25,7 @@ describe API::Environments, api: true do
expect(json_response.size).to eq(1)
expect(json_response.first['name']).to eq(environment.name)
expect(json_response.first['external_url']).to eq(environment.external_url)
- expect(json_response.first['project']['id']).to eq(project.id)
- expect(json_response.first['project']['visibility']).to be_present
+ expect(json_response.first['project'].keys).to contain_exactly(*project_data_keys)
end
end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 2b8fd7e31a1..2545da7b1db 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -76,6 +76,8 @@ describe API::Groups, api: true do
lfs_objects_size: 234,
build_artifacts_size: 345,
}.stringify_keys
+ exposed_attributes = attributes.dup
+ exposed_attributes['job_artifacts_size'] = exposed_attributes.delete('build_artifacts_size')
project1.statistics.update!(attributes)
@@ -85,7 +87,7 @@ describe API::Groups, api: true do
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response)
- .to satisfy_one { |group| group['statistics'] == attributes }
+ .to satisfy_one { |group| group['statistics'] == exposed_attributes }
end
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 710e4320fd1..aca7c6a0734 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -270,6 +270,13 @@ describe API::Issues, api: true do
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort)
end
+
+ it 'matches V4 response schema' do
+ get api('/issues', user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/issues')
+ end
end
end
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
new file mode 100644
index 00000000000..a4d27734cc2
--- /dev/null
+++ b/spec/requests/api/jobs_spec.rb
@@ -0,0 +1,408 @@
+require 'spec_helper'
+
+describe API::Jobs, api: true do
+ include ApiHelpers
+
+ let(:user) { create(:user) }
+ let(:api_user) { user }
+ let!(:project) { create(:project, :repository, creator: user, public_builds: false) }
+ let!(:developer) { create(:project_member, :developer, user: user, project: project) }
+ let(:reporter) { create(:project_member, :reporter, project: project) }
+ let(:guest) { create(:project_member, :guest, project: project) }
+ let!(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) }
+ let!(:build) { create(:ci_build, pipeline: pipeline) }
+
+ describe 'GET /projects/:id/jobs' do
+ let(:query) { Hash.new }
+
+ before do
+ get api("/projects/#{project.id}/jobs", api_user), query
+ end
+
+ context 'authorized user' do
+ it 'returns project jobs' do
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ end
+
+ it 'returns correct values' do
+ expect(json_response).not_to be_empty
+ expect(json_response.first['commit']['id']).to eq project.commit.id
+ end
+
+ it 'returns pipeline data' do
+ json_build = json_response.first
+
+ expect(json_build['pipeline']).not_to be_empty
+ expect(json_build['pipeline']['id']).to eq build.pipeline.id
+ expect(json_build['pipeline']['ref']).to eq build.pipeline.ref
+ expect(json_build['pipeline']['sha']).to eq build.pipeline.sha
+ expect(json_build['pipeline']['status']).to eq build.pipeline.status
+ end
+
+ context 'filter project with one scope element' do
+ let(:query) { { 'scope' => 'pending' } }
+
+ it do
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ end
+ end
+
+ context 'filter project with array of scope elements' do
+ let(:query) { { 'scope[0]' => 'pending', 'scope[1]' => 'running' } }
+
+ it do
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ end
+ end
+
+ context 'respond 400 when scope contains invalid state' do
+ let(:query) { { 'scope[0]' => 'unknown', 'scope[1]' => 'running' } }
+
+ it { expect(response).to have_http_status(400) }
+ end
+ end
+
+ context 'unauthorized user' do
+ let(:api_user) { nil }
+
+ it 'does not return project builds' do
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/jobs/:job_id' do
+ before do
+ get api("/projects/#{project.id}/jobs/#{build.id}", api_user)
+ end
+
+ context 'authorized user' do
+ it 'returns specific job data' do
+ expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq('test')
+ end
+
+ it 'returns pipeline data' do
+ json_build = json_response
+ expect(json_build['pipeline']).not_to be_empty
+ expect(json_build['pipeline']['id']).to eq build.pipeline.id
+ expect(json_build['pipeline']['ref']).to eq build.pipeline.ref
+ expect(json_build['pipeline']['sha']).to eq build.pipeline.sha
+ expect(json_build['pipeline']['status']).to eq build.pipeline.status
+ end
+ end
+
+ context 'unauthorized user' do
+ let(:api_user) { nil }
+
+ it 'does not return specific job data' do
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/jobs/:job_id/artifacts' do
+ before do
+ get api("/projects/#{project.id}/jobs/#{build.id}/artifacts", api_user)
+ end
+
+ context 'job with artifacts' do
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
+
+ context 'authorized user' do
+ let(:download_headers) do
+ { 'Content-Transfer-Encoding' => 'binary',
+ 'Content-Disposition' => 'attachment; filename=ci_build_artifacts.zip' }
+ end
+
+ it 'returns specific job artifacts' do
+ expect(response).to have_http_status(200)
+ expect(response.headers).to include(download_headers)
+ expect(response.body).to match_file(build.artifacts_file.file.file)
+ end
+ end
+
+ context 'unauthorized user' do
+ let(:api_user) { nil }
+
+ it 'does not return specific job artifacts' do
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ it 'does not return job artifacts if not uploaded' do
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do
+ let(:api_user) { reporter.user }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
+
+ before do
+ build.success
+ end
+
+ def get_for_ref(ref = pipeline.ref, job = build.name)
+ get api("/projects/#{project.id}/jobs/artifacts/#{ref}/download", api_user), job: job
+ end
+
+ context 'when not logged in' do
+ let(:api_user) { nil }
+
+ before do
+ get_for_ref
+ end
+
+ it 'gives 401' do
+ expect(response).to have_http_status(401)
+ end
+ end
+
+ context 'when logging as guest' do
+ let(:api_user) { guest.user }
+
+ before do
+ get_for_ref
+ end
+
+ it 'gives 403' do
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'non-existing job' do
+ shared_examples 'not found' do
+ it { expect(response).to have_http_status(:not_found) }
+ end
+
+ context 'has no such ref' do
+ before do
+ get_for_ref('TAIL')
+ end
+
+ it_behaves_like 'not found'
+ end
+
+ context 'has no such job' do
+ before do
+ get_for_ref(pipeline.ref, 'NOBUILD')
+ end
+
+ it_behaves_like 'not found'
+ end
+ end
+
+ context 'find proper job' do
+ shared_examples 'a valid file' do
+ let(:download_headers) do
+ { 'Content-Transfer-Encoding' => 'binary',
+ 'Content-Disposition' =>
+ "attachment; filename=#{build.artifacts_file.filename}" }
+ end
+
+ it { expect(response).to have_http_status(200) }
+ it { expect(response.headers).to include(download_headers) }
+ end
+
+ context 'with regular branch' do
+ before do
+ pipeline.reload
+ pipeline.update(ref: 'master',
+ sha: project.commit('master').sha)
+
+ get_for_ref('master')
+ end
+
+ it_behaves_like 'a valid file'
+ end
+
+ context 'with branch name containing slash' do
+ before do
+ pipeline.reload
+ pipeline.update(ref: 'improve/awesome',
+ sha: project.commit('improve/awesome').sha)
+ end
+
+ before do
+ get_for_ref('improve/awesome')
+ end
+
+ it_behaves_like 'a valid file'
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/jobs/:job_id/trace' do
+ let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
+
+ before do
+ get api("/projects/#{project.id}/jobs/#{build.id}/trace", api_user)
+ end
+
+ context 'authorized user' do
+ it 'returns specific job trace' do
+ expect(response).to have_http_status(200)
+ expect(response.body).to eq(build.trace)
+ end
+ end
+
+ context 'unauthorized user' do
+ let(:api_user) { nil }
+
+ it 'does not return specific job trace' do
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/jobs/:job_id/cancel' do
+ before do
+ post api("/projects/#{project.id}/jobs/#{build.id}/cancel", api_user)
+ end
+
+ context 'authorized user' do
+ context 'user with :update_build persmission' do
+ it 'cancels running or pending job' do
+ expect(response).to have_http_status(201)
+ expect(project.builds.first.status).to eq('canceled')
+ end
+ end
+
+ context 'user without :update_build permission' do
+ let(:api_user) { reporter.user }
+
+ it 'does not cancel job' do
+ expect(response).to have_http_status(403)
+ end
+ end
+ end
+
+ context 'unauthorized user' do
+ let(:api_user) { nil }
+
+ it 'does not cancel job' do
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/jobs/:job_id/retry' do
+ let(:build) { create(:ci_build, :canceled, pipeline: pipeline) }
+
+ before do
+ post api("/projects/#{project.id}/jobs/#{build.id}/retry", api_user)
+ end
+
+ context 'authorized user' do
+ context 'user with :update_build permission' do
+ it 'retries non-running job' do
+ expect(response).to have_http_status(201)
+ expect(project.builds.first.status).to eq('canceled')
+ expect(json_response['status']).to eq('pending')
+ end
+ end
+
+ context 'user without :update_build permission' do
+ let(:api_user) { reporter.user }
+
+ it 'does not retry job' do
+ expect(response).to have_http_status(403)
+ end
+ end
+ end
+
+ context 'unauthorized user' do
+ let(:api_user) { nil }
+
+ it 'does not retry job' do
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/jobs/:job_id/erase' do
+ before do
+ post api("/projects/#{project.id}/jobs/#{build.id}/erase", user)
+ end
+
+ context 'job is erasable' do
+ let(:build) { create(:ci_build, :trace, :artifacts, :success, project: project, pipeline: pipeline) }
+
+ it 'erases job content' do
+ expect(response).to have_http_status(201)
+ expect(build.trace).to be_empty
+ expect(build.artifacts_file.exists?).to be_falsy
+ expect(build.artifacts_metadata.exists?).to be_falsy
+ end
+
+ it 'updates job' do
+ build.reload
+ expect(build.erased_at).to be_truthy
+ expect(build.erased_by).to eq(user)
+ end
+ end
+
+ context 'job is not erasable' do
+ let(:build) { create(:ci_build, :trace, project: project, pipeline: pipeline) }
+
+ it 'responds with forbidden' do
+ expect(response).to have_http_status(403)
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/jobs/:build_id/artifacts/keep' do
+ before do
+ post api("/projects/#{project.id}/jobs/#{build.id}/artifacts/keep", user)
+ end
+
+ context 'artifacts did not expire' do
+ let(:build) do
+ create(:ci_build, :trace, :artifacts, :success,
+ project: project, pipeline: pipeline, artifacts_expire_at: Time.now + 7.days)
+ end
+
+ it 'keeps artifacts' do
+ expect(response).to have_http_status(200)
+ expect(build.reload.artifacts_expire_at).to be_nil
+ end
+ end
+
+ context 'no artifacts' do
+ let(:build) { create(:ci_build, project: project, pipeline: pipeline) }
+
+ it 'responds with not found' do
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/jobs/:job_id/play' do
+ before do
+ post api("/projects/#{project.id}/jobs/#{build.id}/play", user)
+ end
+
+ context 'on an playable job' do
+ let(:build) { create(:ci_build, :manual, project: project, pipeline: pipeline) }
+
+ it 'plays the job' do
+ expect(response).to have_http_status(200)
+ expect(json_response['user']['id']).to eq(user.id)
+ expect(json_response['id']).to eq(build.id)
+ end
+ end
+
+ context 'on a non-playable job' do
+ it 'returns a status code 400, Bad Request' do
+ expect(response).to have_http_status 400
+ expect(response.body).to match("Unplayable Job")
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index b3f0876c822..1083abf2ad3 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -93,6 +93,13 @@ describe API::MergeRequests, api: true do
expect(json_response.first['id']).to eq merge_request_closed.id
end
+ it 'matches V4 response schema' do
+ get api("/projects/#{project.id}/merge_requests", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/merge_requests')
+ end
+
context "with ordering" do
before do
@mr_later = mr_with_later_created_and_updated_at_time
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index 78c230117b8..3bb8b6fdbeb 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -227,6 +227,13 @@ describe API::Milestones, api: true do
expect(json_response.first['milestone']['title']).to eq(milestone.title)
end
+ it 'matches V4 response schema for a list of issues' do
+ get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/issues')
+ end
+
it 'returns a 401 error if user not authenticated' do
get api("/projects/#{project.id}/milestones/#{milestone.id}/issues")
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index f286568547d..b1f8c249092 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -33,7 +33,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true 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['build_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)
expect(json_response.first['enable_ssl_verification']).to eq(true)
@@ -59,7 +59,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true 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['build_events']).to eq(hook.build_events)
+ expect(json_response['job_events']).to eq(hook.build_events)
expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification)
@@ -98,7 +98,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true 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['build_events']).to eq(false)
+ expect(json_response['job_events']).to eq(false)
expect(json_response['pipeline_events']).to eq(false)
expect(json_response['wiki_page_events']).to eq(true)
expect(json_response['enable_ssl_verification']).to eq(true)
@@ -144,7 +144,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true 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['build_events']).to eq(hook.build_events)
+ expect(json_response['job_events']).to eq(hook.build_events)
expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification)
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 03cae074803..77f79cd5bc7 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -594,7 +594,7 @@ describe API::Projects, api: true do
expect(json_response['issues_enabled']).to be_present
expect(json_response['merge_requests_enabled']).to be_present
expect(json_response['wiki_enabled']).to be_present
- expect(json_response['builds_enabled']).to be_present
+ expect(json_response['jobs_enabled']).to be_present
expect(json_response['snippets_enabled']).to be_present
expect(json_response['container_registry_enabled']).to be_present
expect(json_response['created_at']).to be_present
@@ -605,7 +605,7 @@ describe API::Projects, api: true do
expect(json_response['avatar_url']).to be_nil
expect(json_response['star_count']).to be_present
expect(json_response['forks_count']).to be_present
- expect(json_response['public_builds']).to be_present
+ expect(json_response['public_jobs']).to be_present
expect(json_response['shared_with_groups']).to be_an Array
expect(json_response['shared_with_groups'].length).to eq(1)
expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id)
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index e5e4c84755f..881c48c75e0 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -728,7 +728,7 @@ describe API::Users, api: true do
get api("/user", user)
expect(response).to have_http_status(200)
- expect(response).to match_response_schema('user/public')
+ expect(response).to match_response_schema('public_api/v4/user/public')
expect(json_response['id']).to eq(user.id)
end
end
@@ -747,7 +747,7 @@ describe API::Users, api: true do
get api("/user?private_token=#{admin_personal_access_token}")
expect(response).to have_http_status(200)
- expect(response).to match_response_schema('user/public')
+ expect(response).to match_response_schema('public_api/v4/user/public')
expect(json_response['id']).to eq(admin.id)
end
end
@@ -757,7 +757,7 @@ describe API::Users, api: true do
get api("/user?private_token=#{admin.private_token}&sudo=#{user.id}")
expect(response).to have_http_status(200)
- expect(response).to match_response_schema('user/login')
+ expect(response).to match_response_schema('public_api/v4/user/login')
expect(json_response['id']).to eq(user.id)
end
@@ -765,7 +765,7 @@ describe API::Users, api: true do
get api("/user?private_token=#{admin.private_token}")
expect(response).to have_http_status(200)
- expect(response).to match_response_schema('user/public')
+ expect(response).to match_response_schema('public_api/v4/user/public')
expect(json_response['id']).to eq(admin.id)
end
end
diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/v3/builds_spec.rb
index 76a10a2374c..a50c22a6dd1 100644
--- a/spec/requests/api/builds_spec.rb
+++ b/spec/requests/api/v3/builds_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::Builds, api: true do
+describe API::V3::Builds, api: true do
include ApiHelpers
let(:user) { create(:user) }
@@ -18,7 +18,7 @@ describe API::Builds, api: true do
before do
create(:ci_build, :skipped, pipeline: pipeline)
- get api("/projects/#{project.id}/builds?#{query}", api_user)
+ get v3_api("/projects/#{project.id}/builds?#{query}", api_user)
end
context 'authorized user' do
@@ -91,7 +91,7 @@ describe API::Builds, api: true do
describe 'GET /projects/:id/repository/commits/:sha/builds' do
context 'when commit does not exist in repository' do
before do
- get api("/projects/#{project.id}/repository/commits/1a271fd1/builds", api_user)
+ get v3_api("/projects/#{project.id}/repository/commits/1a271fd1/builds", api_user)
end
it 'responds with 404' do
@@ -107,7 +107,7 @@ describe API::Builds, api: true do
create(:ci_build, pipeline: pipeline)
create(:ci_build)
- get api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", api_user)
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", api_user)
end
it 'returns project jobs for specific commit' do
@@ -130,7 +130,7 @@ describe API::Builds, api: true do
context 'when pipeline has no jobs' do
before do
branch_head = project.commit('feature').id
- get api("/projects/#{project.id}/repository/commits/#{branch_head}/builds", api_user)
+ get v3_api("/projects/#{project.id}/repository/commits/#{branch_head}/builds", api_user)
end
it 'returns an empty array' do
@@ -146,7 +146,7 @@ describe API::Builds, api: true do
create(:ci_pipeline, project: project, sha: project.commit.id)
create(:ci_build, pipeline: pipeline)
- get api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", nil)
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", nil)
end
it 'does not return project jobs' do
@@ -159,7 +159,7 @@ describe API::Builds, api: true do
describe 'GET /projects/:id/builds/:build_id' do
before do
- get api("/projects/#{project.id}/builds/#{build.id}", api_user)
+ get v3_api("/projects/#{project.id}/builds/#{build.id}", api_user)
end
context 'authorized user' do
@@ -189,7 +189,7 @@ describe API::Builds, api: true do
describe 'GET /projects/:id/builds/:build_id/artifacts' do
before do
- get api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
+ get v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
end
context 'job with artifacts' do
@@ -231,7 +231,7 @@ describe API::Builds, api: true do
end
def path_for_ref(ref = pipeline.ref, job = build.name)
- api("/projects/#{project.id}/builds/artifacts/#{ref}/download?job=#{job}", api_user)
+ v3_api("/projects/#{project.id}/builds/artifacts/#{ref}/download?job=#{job}", api_user)
end
context 'when not logged in' do
@@ -324,7 +324,7 @@ describe API::Builds, api: true do
let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
before do
- get api("/projects/#{project.id}/builds/#{build.id}/trace", api_user)
+ get v3_api("/projects/#{project.id}/builds/#{build.id}/trace", api_user)
end
context 'authorized user' do
@@ -345,7 +345,7 @@ describe API::Builds, api: true do
describe 'POST /projects/:id/builds/:build_id/cancel' do
before do
- post api("/projects/#{project.id}/builds/#{build.id}/cancel", api_user)
+ post v3_api("/projects/#{project.id}/builds/#{build.id}/cancel", api_user)
end
context 'authorized user' do
@@ -378,7 +378,7 @@ describe API::Builds, api: true do
let(:build) { create(:ci_build, :canceled, pipeline: pipeline) }
before do
- post api("/projects/#{project.id}/builds/#{build.id}/retry", api_user)
+ post v3_api("/projects/#{project.id}/builds/#{build.id}/retry", api_user)
end
context 'authorized user' do
@@ -410,7 +410,7 @@ describe API::Builds, api: true do
describe 'POST /projects/:id/builds/:build_id/erase' do
before do
- post api("/projects/#{project.id}/builds/#{build.id}/erase", user)
+ post v3_api("/projects/#{project.id}/builds/#{build.id}/erase", user)
end
context 'job is erasable' do
@@ -440,7 +440,7 @@ describe API::Builds, api: true do
describe 'POST /projects/:id/builds/:build_id/artifacts/keep' do
before do
- post api("/projects/#{project.id}/builds/#{build.id}/artifacts/keep", user)
+ post v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts/keep", user)
end
context 'artifacts did not expire' do
@@ -466,7 +466,7 @@ describe API::Builds, api: true do
describe 'POST /projects/:id/builds/:build_id/play' do
before do
- post api("/projects/#{project.id}/builds/#{build.id}/play", user)
+ post v3_api("/projects/#{project.id}/builds/#{build.id}/play", user)
end
context 'on an playable job' do
diff --git a/spec/requests/api/v3/deployments_spec.rb b/spec/requests/api/v3/deployments_spec.rb
new file mode 100644
index 00000000000..3c5ce407b32
--- /dev/null
+++ b/spec/requests/api/v3/deployments_spec.rb
@@ -0,0 +1,71 @@
+require 'spec_helper'
+
+describe API::Deployments, api: true do
+ include ApiHelpers
+
+ let(:user) { create(:user) }
+ let(:non_member) { create(:user) }
+ let(:project) { deployment.environment.project }
+ let!(:deployment) { create(:deployment) }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ shared_examples 'a paginated resources' do
+ before do
+ # Fires the request
+ request
+ end
+
+ it 'has pagination headers' do
+ expect(response).to include_pagination_headers
+ end
+ end
+
+ describe 'GET /projects/:id/deployments' do
+ context 'as member of the project' do
+ it_behaves_like 'a paginated resources' do
+ let(:request) { get api("/projects/#{project.id}/deployments", user) }
+ end
+
+ it 'returns projects deployments' do
+ get api("/projects/#{project.id}/deployments", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['iid']).to eq(deployment.iid)
+ expect(json_response.first['sha']).to match /\A\h{40}\z/
+ end
+ end
+
+ context 'as non member' do
+ it 'returns a 404 status code' do
+ get api("/projects/#{project.id}/deployments", non_member)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/deployments/:deployment_id' do
+ context 'as a member of the project' do
+ it 'returns the projects deployment' do
+ get api("/projects/#{project.id}/deployments/#{deployment.id}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['sha']).to match /\A\h{40}\z/
+ expect(json_response['id']).to eq(deployment.id)
+ end
+ end
+
+ context 'as non member' do
+ it 'returns a 404 status code' do
+ get api("/projects/#{project.id}/deployments/#{deployment.id}", non_member)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v3/issues_spec.rb b/spec/requests/api/v3/issues_spec.rb
index 803acd55470..2a8105d5a2b 100644
--- a/spec/requests/api/v3/issues_spec.rb
+++ b/spec/requests/api/v3/issues_spec.rb
@@ -232,6 +232,13 @@ describe API::V3::Issues, api: true do
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort)
end
+
+ it 'matches V3 response schema' do
+ get v3_api('/issues', user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to match_response_schema('public_api/v3/issues')
+ end
end
end
diff --git a/spec/requests/api/v3/merge_request_diffs_spec.rb b/spec/requests/api/v3/merge_request_diffs_spec.rb
new file mode 100644
index 00000000000..e1887138aab
--- /dev/null
+++ b/spec/requests/api/v3/merge_request_diffs_spec.rb
@@ -0,0 +1,49 @@
+require "spec_helper"
+
+describe API::MergeRequestDiffs, 'MergeRequestDiffs', api: true do
+ include ApiHelpers
+
+ let!(:user) { create(:user) }
+ let!(:merge_request) { create(:merge_request, importing: true) }
+ let!(:project) { merge_request.target_project }
+
+ before do
+ merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9')
+ merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e')
+ project.team << [user, :master]
+ end
+
+ describe 'GET /projects/:id/merge_requests/:merge_request_id/versions' do
+ it 'returns 200 for a valid merge request' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions", user)
+ merge_request_diff = merge_request.merge_request_diffs.first
+
+ expect(response.status).to eq 200
+ expect(json_response.size).to eq(merge_request.merge_request_diffs.size)
+ expect(json_response.first['id']).to eq(merge_request_diff.id)
+ expect(json_response.first['head_commit_sha']).to eq(merge_request_diff.head_commit_sha)
+ end
+
+ it 'returns a 404 when merge_request_id not found' do
+ get api("/projects/#{project.id}/merge_requests/999/versions", user)
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ describe 'GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id' do
+ it 'returns a 200 for a valid merge request' do
+ merge_request_diff = merge_request.merge_request_diffs.first
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/#{merge_request_diff.id}", user)
+
+ expect(response.status).to eq 200
+ expect(json_response['id']).to eq(merge_request_diff.id)
+ expect(json_response['head_commit_sha']).to eq(merge_request_diff.head_commit_sha)
+ expect(json_response['diffs'].size).to eq(merge_request_diff.diffs.size)
+ end
+
+ it 'returns a 404 when merge_request_id not found' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/999", user)
+ expect(response).to have_http_status(404)
+ end
+ end
+end
diff --git a/spec/requests/api/v3/merge_requests_spec.rb b/spec/requests/api/v3/merge_requests_spec.rb
index 51764d1000e..b7ed643bc21 100644
--- a/spec/requests/api/v3/merge_requests_spec.rb
+++ b/spec/requests/api/v3/merge_requests_spec.rb
@@ -73,6 +73,13 @@ describe API::MergeRequests, api: true do
expect(json_response.first['title']).to eq(merge_request_merged.title)
end
+ it 'matches V3 response schema' do
+ get v3_api("/projects/#{project.id}/merge_requests", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to match_response_schema('public_api/v3/merge_requests')
+ end
+
context "with ordering" do
before do
@mr_later = mr_with_later_created_and_updated_at_time
diff --git a/spec/requests/api/v3/milestones_spec.rb b/spec/requests/api/v3/milestones_spec.rb
index 77705d8c839..127c0eec881 100644
--- a/spec/requests/api/v3/milestones_spec.rb
+++ b/spec/requests/api/v3/milestones_spec.rb
@@ -181,6 +181,13 @@ describe API::V3::Milestones, api: true do
expect(json_response.first['milestone']['title']).to eq(milestone.title)
end
+ it 'matches V3 response schema for a list of issues' do
+ get v3_api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to match_response_schema('public_api/v3/issues')
+ end
+
it 'returns a 401 error if user not authenticated' do
get v3_api("/projects/#{project.id}/milestones/#{milestone.id}/issues")
diff --git a/spec/requests/api/v3/project_hooks_spec.rb b/spec/requests/api/v3/project_hooks_spec.rb
new file mode 100644
index 00000000000..a981119dc5a
--- /dev/null
+++ b/spec/requests/api/v3/project_hooks_spec.rb
@@ -0,0 +1,216 @@
+require 'spec_helper'
+
+describe API::ProjectHooks, 'ProjectHooks', api: true do
+ include ApiHelpers
+ let(:user) { create(:user) }
+ let(:user3) { create(:user) }
+ let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
+ let!(:hook) do
+ create(:project_hook,
+ :all_events_enabled,
+ project: project,
+ url: 'http://example.com',
+ enable_ssl_verification: true)
+ end
+
+ before do
+ project.team << [user, :master]
+ project.team << [user3, :developer]
+ end
+
+ describe "GET /projects/:id/hooks" do
+ context "authorized user" do
+ it "returns project hooks" do
+ get v3_api("/projects/#{project.id}/hooks", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.count).to eq(1)
+ expect(json_response.first['url']).to eq("http://example.com")
+ expect(json_response.first['issues_events']).to eq(true)
+ expect(json_response.first['push_events']).to eq(true)
+ 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['build_events']).to eq(true)
+ expect(json_response.first['pipeline_events']).to eq(true)
+ expect(json_response.first['wiki_page_events']).to eq(true)
+ expect(json_response.first['enable_ssl_verification']).to eq(true)
+ end
+ end
+
+ context "unauthorized user" do
+ it "does not access project hooks" do
+ get v3_api("/projects/#{project.id}/hooks", user3)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+ end
+
+ describe "GET /projects/:id/hooks/:hook_id" do
+ context "authorized user" do
+ it "returns a project hook" do
+ get v3_api("/projects/#{project.id}/hooks/#{hook.id}", user)
+ expect(response).to have_http_status(200)
+ expect(json_response['url']).to eq(hook.url)
+ expect(json_response['issues_events']).to eq(hook.issues_events)
+ expect(json_response['push_events']).to eq(hook.push_events)
+ 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['build_events']).to eq(hook.build_events)
+ expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
+ expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
+ expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification)
+ end
+
+ it "returns a 404 error if hook id is not available" do
+ get v3_api("/projects/#{project.id}/hooks/1234", user)
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context "unauthorized user" do
+ it "does not access an existing hook" do
+ get v3_api("/projects/#{project.id}/hooks/#{hook.id}", user3)
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ it "returns a 404 error if hook id is not available" do
+ get v3_api("/projects/#{project.id}/hooks/1234", user)
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ describe "POST /projects/:id/hooks" do
+ it "adds hook to project" do
+ expect do
+ post v3_api("/projects/#{project.id}/hooks", user),
+ url: "http://example.com", issues_events: true, wiki_page_events: true
+ end.to change {project.hooks.count}.by(1)
+
+ expect(response).to have_http_status(201)
+ expect(json_response['url']).to eq('http://example.com')
+ expect(json_response['issues_events']).to eq(true)
+ expect(json_response['push_events']).to eq(true)
+ 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['build_events']).to eq(false)
+ expect(json_response['pipeline_events']).to eq(false)
+ expect(json_response['wiki_page_events']).to eq(true)
+ expect(json_response['enable_ssl_verification']).to eq(true)
+ expect(json_response).not_to include('token')
+ end
+
+ it "adds the token without including it in the response" do
+ token = "secret token"
+
+ expect do
+ post v3_api("/projects/#{project.id}/hooks", user), url: "http://example.com", token: token
+ end.to change {project.hooks.count}.by(1)
+
+ expect(response).to have_http_status(201)
+ expect(json_response["url"]).to eq("http://example.com")
+ expect(json_response).not_to include("token")
+
+ hook = project.hooks.find(json_response["id"])
+
+ expect(hook.url).to eq("http://example.com")
+ expect(hook.token).to eq(token)
+ end
+
+ it "returns a 400 error if url not given" do
+ post v3_api("/projects/#{project.id}/hooks", user)
+ expect(response).to have_http_status(400)
+ end
+
+ it "returns a 422 error if url not valid" do
+ post v3_api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com"
+ expect(response).to have_http_status(422)
+ end
+ end
+
+ describe "PUT /projects/:id/hooks/:hook_id" do
+ it "updates an existing project hook" do
+ put v3_api("/projects/#{project.id}/hooks/#{hook.id}", user),
+ url: 'http://example.org', push_events: false
+ expect(response).to have_http_status(200)
+ expect(json_response['url']).to eq('http://example.org')
+ expect(json_response['issues_events']).to eq(hook.issues_events)
+ expect(json_response['push_events']).to eq(false)
+ 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['build_events']).to eq(hook.build_events)
+ expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
+ expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
+ expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification)
+ end
+
+ it "adds the token without including it in the response" do
+ token = "secret token"
+
+ put v3_api("/projects/#{project.id}/hooks/#{hook.id}", user), url: "http://example.org", token: token
+
+ expect(response).to have_http_status(200)
+ expect(json_response["url"]).to eq("http://example.org")
+ expect(json_response).not_to include("token")
+
+ expect(hook.reload.url).to eq("http://example.org")
+ expect(hook.reload.token).to eq(token)
+ end
+
+ it "returns 404 error if hook id not found" do
+ put v3_api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org'
+ expect(response).to have_http_status(404)
+ end
+
+ it "returns 400 error if url is not given" do
+ put v3_api("/projects/#{project.id}/hooks/#{hook.id}", user)
+ expect(response).to have_http_status(400)
+ end
+
+ it "returns a 422 error if url is not valid" do
+ put v3_api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com'
+ expect(response).to have_http_status(422)
+ end
+ end
+
+ describe "DELETE /projects/:id/hooks/:hook_id" do
+ it "deletes hook from project" do
+ expect do
+ delete v3_api("/projects/#{project.id}/hooks/#{hook.id}", user)
+ end.to change {project.hooks.count}.by(-1)
+ expect(response).to have_http_status(200)
+ end
+
+ it "returns success when deleting hook" do
+ delete v3_api("/projects/#{project.id}/hooks/#{hook.id}", user)
+ expect(response).to have_http_status(200)
+ end
+
+ it "returns a 404 error when deleting non existent hook" do
+ delete v3_api("/projects/#{project.id}/hooks/42", user)
+ expect(response).to have_http_status(404)
+ end
+
+ it "returns a 404 error if hook id not given" do
+ delete v3_api("/projects/#{project.id}/hooks", user)
+
+ expect(response).to have_http_status(404)
+ end
+
+ it "returns a 404 if a user attempts to delete project hooks he/she does not own" do
+ test_user = create(:user)
+ other_project = create(:project)
+ other_project.team << [test_user, :master]
+
+ delete v3_api("/projects/#{other_project.id}/hooks/#{hook.id}", test_user)
+ expect(response).to have_http_status(404)
+ expect(WebHook.exists?(hook.id)).to be_truthy
+ end
+ end
+end