debian-mirror-gitlab/spec/controllers/projects/jobs_controller_spec.rb

669 lines
18 KiB
Ruby
Raw Normal View History

2018-05-09 12:01:36 +05:30
# coding: utf-8
2017-08-17 22:00:37 +05:30
require 'spec_helper'
2018-10-15 14:42:47 +05:30
describe Projects::JobsController, :clean_gitlab_redis_shared_state do
2017-08-17 22:00:37 +05:30
include ApiHelpers
2018-05-09 12:01:36 +05:30
include HttpIOHelpers
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, :public) }
2017-08-17 22:00:37 +05:30
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:user) { create(:user) }
2017-09-10 17:25:29 +05:30
before do
2018-10-15 14:42:47 +05:30
stub_feature_flags(ci_enable_live_trace: true)
2017-09-10 17:25:29 +05:30
stub_not_protect_default_branch
end
2017-08-17 22:00:37 +05:30
describe 'GET index' do
context 'when scope is pending' do
before do
create(:ci_build, :pending, pipeline: pipeline)
get_index(scope: 'pending')
end
it 'has only pending builds' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(assigns(:builds).first.status).to eq('pending')
end
end
context 'when scope is running' do
before do
create(:ci_build, :running, pipeline: pipeline)
get_index(scope: 'running')
end
2017-09-10 17:25:29 +05:30
it 'has only running jobs' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(assigns(:builds).first.status).to eq('running')
end
end
context 'when scope is finished' do
before do
create(:ci_build, :success, pipeline: pipeline)
get_index(scope: 'finished')
end
2017-09-10 17:25:29 +05:30
it 'has only finished jobs' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(assigns(:builds).first.status).to eq('success')
end
end
context 'when page is specified' do
let(:last_page) { project.builds.page.total_pages }
context 'when page number is eligible' do
before do
create_list(:ci_build, 2, pipeline: pipeline)
get_index(page: last_page.to_param)
end
it 'redirects to the page' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(assigns(:builds).current_page).to eq(last_page)
end
end
end
context 'number of queries' do
before do
Ci::Build::AVAILABLE_STATUSES.each do |status|
2017-09-10 17:25:29 +05:30
create_job(status, status)
2017-08-17 22:00:37 +05:30
end
end
2017-09-10 17:25:29 +05:30
it 'verifies number of queries', :request_store do
2017-08-17 22:00:37 +05:30
recorded = ActiveRecord::QueryRecorder.new { get_index }
2017-09-10 17:25:29 +05:30
expect(recorded.count).to be_within(5).of(7)
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
def create_job(name, status)
2017-08-17 22:00:37 +05:30
pipeline = create(:ci_pipeline, project: project)
create(:ci_build, :tags, :triggered, :artifacts,
pipeline: pipeline, name: name, status: status)
end
end
def get_index(**extra_params)
params = {
namespace_id: project.namespace.to_param,
project_id: project
}
get :index, params.merge(extra_params)
end
end
describe 'GET show' do
2017-09-10 17:25:29 +05:30
let!(:job) { create(:ci_build, :failed, pipeline: pipeline) }
2018-11-08 19:23:39 +05:30
let!(:second_job) { create(:ci_build, :failed, pipeline: pipeline) }
let!(:third_job) { create(:ci_build, :failed) }
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
context 'when requesting HTML' do
context 'when job exists' do
before do
get_show(id: job.id)
end
it 'has a job' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-09-10 17:25:29 +05:30
expect(assigns(:build).id).to eq(job.id)
end
2018-11-08 19:23:39 +05:30
it 'has the correct build collection' do
builds = assigns(:builds).map(&:id)
expect(builds).to include(job.id, second_job.id)
expect(builds).not_to include(third_job.id)
end
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
context 'when job does not exist' do
before do
get_show(id: 1234)
end
it 'renders not_found' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:not_found)
2017-09-10 17:25:29 +05:30
end
2017-08-17 22:00:37 +05:30
end
end
2017-09-10 17:25:29 +05:30
context 'when requesting JSON' do
let(:merge_request) { create(:merge_request, source_project: project) }
2017-08-17 22:00:37 +05:30
before do
2017-09-10 17:25:29 +05:30
project.add_developer(user)
sign_in(user)
allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)
get_show(id: job.id, format: :json)
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
it 'exposes needed information' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z})
expect(json_response.dig('merge_request', 'path')).to match(%r{merge_requests/\d+\z})
2017-09-10 17:25:29 +05:30
expect(json_response['new_issue_path'])
.to include('/issues/new')
2017-08-17 22:00:37 +05:30
end
end
def get_show(**extra_params)
params = {
namespace_id: project.namespace.to_param,
project_id: project
}
get :show, params.merge(extra_params)
end
end
describe 'GET trace.json' do
before do
get_trace
end
2018-03-17 18:26:18 +05:30
context 'when job has a trace artifact' do
let(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
it 'returns a trace' do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['id']).to eq job.id
expect(json_response['status']).to eq job.status
expect(json_response['html']).to eq(job.trace.html)
end
end
2017-09-10 17:25:29 +05:30
context 'when job has a trace' do
2018-03-17 18:26:18 +05:30
let(:job) { create(:ci_build, :trace_live, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
it 'returns a trace' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-09-10 17:25:29 +05:30
expect(json_response['id']).to eq job.id
expect(json_response['status']).to eq job.status
2017-08-17 22:00:37 +05:30
expect(json_response['html']).to eq('BUILD TRACE')
end
end
2017-09-10 17:25:29 +05:30
context 'when job has no traces' do
let(:job) { create(:ci_build, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
it 'returns no traces' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-09-10 17:25:29 +05:30
expect(json_response['id']).to eq job.id
expect(json_response['status']).to eq job.status
2017-08-17 22:00:37 +05:30
expect(json_response['html']).to be_nil
end
end
2017-09-10 17:25:29 +05:30
context 'when job has a trace with ANSI sequence and Unicode' do
2018-03-17 18:26:18 +05:30
let(:job) { create(:ci_build, :unicode_trace_live, pipeline: pipeline) }
2017-09-10 17:25:29 +05:30
it 'returns a trace with Unicode' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-09-10 17:25:29 +05:30
expect(json_response['id']).to eq job.id
expect(json_response['status']).to eq job.status
expect(json_response['html']).to include("ヾ(´༎ຶД༎ຶ`)ノ")
end
end
2018-05-09 12:01:36 +05:30
context 'when trace artifact is in ObjectStorage' do
2018-11-18 11:00:15 +05:30
let(:url) { 'http://object-storage/trace' }
let(:file_path) { expand_fixture_path('trace/sample_trace') }
2018-05-09 12:01:36 +05:30
let!(:job) { create(:ci_build, :success, :trace_artifact, pipeline: pipeline) }
before do
allow_any_instance_of(JobArtifactUploader).to receive(:file_storage?) { false }
2018-11-18 11:00:15 +05:30
allow_any_instance_of(JobArtifactUploader).to receive(:url) { url }
allow_any_instance_of(JobArtifactUploader).to receive(:size) { File.size(file_path) }
2018-05-09 12:01:36 +05:30
end
context 'when there are no network issues' do
before do
2018-11-18 11:00:15 +05:30
stub_remote_url_206(url, file_path)
2018-05-09 12:01:36 +05:30
get_trace
end
it 'returns a trace' do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['id']).to eq job.id
expect(json_response['status']).to eq job.status
expect(json_response['html']).to eq(job.trace.html)
end
end
context 'when there is a network issue' do
before do
2018-11-18 11:00:15 +05:30
stub_remote_url_500(url)
2018-05-09 12:01:36 +05:30
end
it 'returns a trace' do
2018-11-18 11:00:15 +05:30
expect { get_trace }.to raise_error(Gitlab::HttpIO::FailedToGetChunkError)
2018-05-09 12:01:36 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
def get_trace
get :trace, namespace_id: project.namespace,
project_id: project,
2017-09-10 17:25:29 +05:30
id: job.id,
2017-08-17 22:00:37 +05:30
format: :json
end
end
describe 'GET status.json' do
2017-09-10 17:25:29 +05:30
let(:job) { create(:ci_build, pipeline: pipeline) }
let(:status) { job.detailed_status(double('user')) }
2017-08-17 22:00:37 +05:30
before do
get :status, namespace_id: project.namespace,
project_id: project,
2017-09-10 17:25:29 +05:30
id: job.id,
2017-08-17 22:00:37 +05:30
format: :json
end
2017-09-10 17:25:29 +05:30
it 'return a detailed job status in json' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2017-08-17 22:00:37 +05:30
expect(json_response['text']).to eq status.text
expect(json_response['label']).to eq status.label
expect(json_response['icon']).to eq status.icon
2018-11-08 19:23:39 +05:30
expect(json_response['favicon']).to match_asset_path "/assets/ci_favicons/#{status.favicon}.png"
2017-08-17 22:00:37 +05:30
end
end
describe 'POST retry' do
before do
project.add_developer(user)
sign_in(user)
post_retry
end
2017-09-10 17:25:29 +05:30
context 'when job is retryable' do
let(:job) { create(:ci_build, :retryable, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
it 'redirects to the retried job page' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:found)
2017-09-10 17:25:29 +05:30
expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id))
2017-08-17 22:00:37 +05:30
end
end
2017-09-10 17:25:29 +05:30
context 'when job is not retryable' do
let(:job) { create(:ci_build, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
it 'renders unprocessable_entity' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:unprocessable_entity)
2017-08-17 22:00:37 +05:30
end
end
def post_retry
post :retry, namespace_id: project.namespace,
project_id: project,
2017-09-10 17:25:29 +05:30
id: job.id
2017-08-17 22:00:37 +05:30
end
end
describe 'POST play' do
before do
project.add_developer(user)
create(:protected_branch, :developers_can_merge,
name: 'master', project: project)
sign_in(user)
post_play
end
2017-09-10 17:25:29 +05:30
context 'when job is playable' do
let(:job) { create(:ci_build, :playable, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
it 'redirects to the played job page' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:found)
2017-09-10 17:25:29 +05:30
expect(response).to redirect_to(namespace_project_job_path(id: job.id))
2017-08-17 22:00:37 +05:30
end
it 'transits to pending' do
2017-09-10 17:25:29 +05:30
expect(job.reload).to be_pending
2017-08-17 22:00:37 +05:30
end
end
2017-09-10 17:25:29 +05:30
context 'when job is not playable' do
let(:job) { create(:ci_build, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
it 'renders unprocessable_entity' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:unprocessable_entity)
2017-08-17 22:00:37 +05:30
end
end
def post_play
post :play, namespace_id: project.namespace,
project_id: project,
2017-09-10 17:25:29 +05:30
id: job.id
2017-08-17 22:00:37 +05:30
end
end
describe 'POST cancel' do
before do
project.add_developer(user)
sign_in(user)
post_cancel
end
2017-09-10 17:25:29 +05:30
context 'when job is cancelable' do
let(:job) { create(:ci_build, :cancelable, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
it 'redirects to the canceled job page' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:found)
2017-09-10 17:25:29 +05:30
expect(response).to redirect_to(namespace_project_job_path(id: job.id))
2017-08-17 22:00:37 +05:30
end
it 'transits to canceled' do
2017-09-10 17:25:29 +05:30
expect(job.reload).to be_canceled
2017-08-17 22:00:37 +05:30
end
end
2017-09-10 17:25:29 +05:30
context 'when job is not cancelable' do
let(:job) { create(:ci_build, :canceled, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
it 'returns unprocessable_entity' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:unprocessable_entity)
2017-08-17 22:00:37 +05:30
end
end
def post_cancel
post :cancel, namespace_id: project.namespace,
project_id: project,
2017-09-10 17:25:29 +05:30
id: job.id
2017-08-17 22:00:37 +05:30
end
end
describe 'POST cancel_all' do
before do
project.add_developer(user)
sign_in(user)
end
2017-09-10 17:25:29 +05:30
context 'when jobs are cancelable' do
2017-08-17 22:00:37 +05:30
before do
create_list(:ci_build, 2, :cancelable, pipeline: pipeline)
post_cancel_all
end
it 'redirects to a index page' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:found)
2017-09-10 17:25:29 +05:30
expect(response).to redirect_to(namespace_project_jobs_path)
2017-08-17 22:00:37 +05:30
end
it 'transits to canceled' do
expect(Ci::Build.all).to all(be_canceled)
end
end
2017-09-10 17:25:29 +05:30
context 'when jobs are not cancelable' do
2017-08-17 22:00:37 +05:30
before do
create_list(:ci_build, 2, :canceled, pipeline: pipeline)
post_cancel_all
end
it 'redirects to a index page' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:found)
2017-09-10 17:25:29 +05:30
expect(response).to redirect_to(namespace_project_jobs_path)
2017-08-17 22:00:37 +05:30
end
end
def post_cancel_all
post :cancel_all, namespace_id: project.namespace,
project_id: project
end
end
describe 'POST erase' do
2018-11-18 11:00:15 +05:30
let(:role) { :maintainer }
2018-03-17 18:26:18 +05:30
2017-08-17 22:00:37 +05:30
before do
2018-03-17 18:26:18 +05:30
project.add_role(user, role)
2017-08-17 22:00:37 +05:30
sign_in(user)
post_erase
end
2017-09-10 17:25:29 +05:30
context 'when job is erasable' do
2018-03-17 18:26:18 +05:30
let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
it 'redirects to the erased job page' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:found)
2017-09-10 17:25:29 +05:30
expect(response).to redirect_to(namespace_project_job_path(id: job.id))
2017-08-17 22:00:37 +05:30
end
it 'erases artifacts' do
2017-09-10 17:25:29 +05:30
expect(job.artifacts_file.exists?).to be_falsey
expect(job.artifacts_metadata.exists?).to be_falsey
2017-08-17 22:00:37 +05:30
end
it 'erases trace' do
2017-09-10 17:25:29 +05:30
expect(job.trace.exist?).to be_falsey
2017-08-17 22:00:37 +05:30
end
end
2017-09-10 17:25:29 +05:30
context 'when job is not erasable' do
let(:job) { create(:ci_build, :erased, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
it 'returns unprocessable_entity' do
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
context 'when user is developer' do
let(:role) { :developer }
let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline, user: triggered_by) }
context 'when triggered by same user' do
let(:triggered_by) { user }
it 'has successful status' do
expect(response).to have_gitlab_http_status(:found)
end
end
context 'when triggered by different user' do
let(:triggered_by) { create(:user) }
it 'does not have successful status' do
expect(response).not_to have_gitlab_http_status(:found)
end
2017-08-17 22:00:37 +05:30
end
end
def post_erase
post :erase, namespace_id: project.namespace,
project_id: project,
2017-09-10 17:25:29 +05:30
id: job.id
2017-08-17 22:00:37 +05:30
end
end
describe 'GET raw' do
2018-05-09 12:01:36 +05:30
subject do
post :raw, namespace_id: project.namespace,
project_id: project,
id: job.id
2017-08-17 22:00:37 +05:30
end
2018-11-08 19:23:39 +05:30
context "when job has a trace artifact" do
2018-03-17 18:26:18 +05:30
let(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
it 'returns a trace' do
2018-05-09 12:01:36 +05:30
response = subject
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-11-08 19:23:39 +05:30
expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8")
expect(response.body).to eq(job.job_artifacts_trace.open.read)
2018-03-17 18:26:18 +05:30
end
end
2018-11-08 19:23:39 +05:30
context "when job has a trace file" do
2018-03-17 18:26:18 +05:30
let(:job) { create(:ci_build, :trace_live, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
2018-11-08 19:23:39 +05:30
it "send a trace file" do
2018-05-09 12:01:36 +05:30
response = subject
2018-03-17 18:26:18 +05:30
expect(response).to have_gitlab_http_status(:ok)
2018-11-08 19:23:39 +05:30
expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8")
expect(response.body).to eq("BUILD TRACE")
2017-08-17 22:00:37 +05:30
end
end
2018-11-08 19:23:39 +05:30
context "when job has a trace in database" do
2018-05-09 12:01:36 +05:30
let(:job) { create(:ci_build, pipeline: pipeline) }
before do
2018-11-08 19:23:39 +05:30
job.update_column(:trace, "Sample trace")
2018-05-09 12:01:36 +05:30
end
2018-11-08 19:23:39 +05:30
it "send a trace file" do
2018-05-09 12:01:36 +05:30
response = subject
expect(response).to have_gitlab_http_status(:ok)
2018-11-08 19:23:39 +05:30
expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8")
expect(response.body).to eq("Sample trace")
2018-05-09 12:01:36 +05:30
end
end
2017-09-10 17:25:29 +05:30
context 'when job does not have a trace file' do
let(:job) { create(:ci_build, pipeline: pipeline) }
2017-08-17 22:00:37 +05:30
it 'returns not_found' do
2018-05-09 12:01:36 +05:30
response = subject
expect(response).to have_gitlab_http_status(:ok)
expect(response.body).to eq ''
2017-08-17 22:00:37 +05:30
end
end
2018-05-09 12:01:36 +05:30
context 'when the trace artifact is in ObjectStorage' do
let!(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
before do
allow_any_instance_of(JobArtifactUploader).to receive(:file_storage?) { false }
end
it 'redirect to the trace file url' do
expect(subject).to redirect_to(job.job_artifacts_trace.file.url)
end
2017-08-17 22:00:37 +05:30
end
end
2018-11-08 19:23:39 +05:30
describe 'GET #terminal' do
before do
project.add_developer(user)
sign_in(user)
end
context 'when job exists' do
context 'and it has a terminal' do
let!(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline) }
it 'has a job' do
get_terminal(id: job.id)
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:build).id).to eq(job.id)
end
end
context 'and does not have a terminal' do
let!(:job) { create(:ci_build, :running, pipeline: pipeline) }
it 'returns not_found' do
get_terminal(id: job.id)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'when job does not exist' do
it 'renders not_found' do
get_terminal(id: 1234)
expect(response).to have_gitlab_http_status(:not_found)
end
end
def get_terminal(**extra_params)
params = {
namespace_id: project.namespace.to_param,
project_id: project
}
get :terminal, params.merge(extra_params)
end
end
describe 'GET #terminal_websocket_authorize' do
let!(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline) }
before do
project.add_developer(user)
sign_in(user)
end
context 'with valid workhorse signature' do
before do
allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_return(nil)
end
context 'and valid id' do
it 'returns the terminal for the job' do
expect(Gitlab::Workhorse)
.to receive(:terminal_websocket)
.and_return(workhorse: :response)
get_terminal_websocket(id: job.id)
expect(response).to have_gitlab_http_status(200)
expect(response.headers["Content-Type"]).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
expect(response.body).to eq('{"workhorse":"response"}')
end
end
context 'and invalid id' do
it 'returns 404' do
get_terminal_websocket(id: 1234)
expect(response).to have_gitlab_http_status(404)
end
end
end
context 'with invalid workhorse signature' do
it 'aborts with an exception' do
allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_raise(JWT::DecodeError)
expect { get_terminal_websocket(id: job.id) }.to raise_error(JWT::DecodeError)
end
end
def get_terminal_websocket(**extra_params)
params = {
namespace_id: project.namespace.to_param,
project_id: project
}
get :terminal_websocket_authorize, params.merge(extra_params)
end
end
2017-08-17 22:00:37 +05:30
end