47a0276e53
Added the needed keys and paths to a new entity, BuildDetailsEntity. Not renaming BuildEntity to BuildBasicEntity on explicit request. Most code now has test coverage, but not all. This will be added on later commits on this branch. Resolves gitlab-org/gitlab-ce#31397
445 lines
12 KiB
Ruby
445 lines
12 KiB
Ruby
require 'spec_helper'
|
|
|
|
describe Projects::JobsController do
|
|
include ApiHelpers
|
|
|
|
let(:project) { create(:empty_project, :public) }
|
|
let(:pipeline) { create(:ci_pipeline, project: project) }
|
|
let(:user) { create(:user) }
|
|
|
|
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
|
|
expect(response).to have_http_status(:ok)
|
|
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
|
|
|
|
it 'has only running builds' do
|
|
expect(response).to have_http_status(:ok)
|
|
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
|
|
|
|
it 'has only finished builds' do
|
|
expect(response).to have_http_status(:ok)
|
|
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
|
|
expect(response).to have_http_status(:ok)
|
|
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|
|
|
create_build(status, status)
|
|
end
|
|
|
|
RequestStore.begin!
|
|
end
|
|
|
|
after do
|
|
RequestStore.end!
|
|
RequestStore.clear!
|
|
end
|
|
|
|
it "verifies number of queries" do
|
|
recorded = ActiveRecord::QueryRecorder.new { get_index }
|
|
expect(recorded.count).to be_within(5).of(8)
|
|
end
|
|
|
|
def create_build(name, status)
|
|
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
|
|
let!(:build) { create(:ci_build, :failed, pipeline: pipeline) }
|
|
|
|
context 'when requesting HTML' do
|
|
context 'when build exists' do
|
|
before do
|
|
get_show(id: build.id)
|
|
end
|
|
|
|
it 'has a build' do
|
|
expect(response).to have_http_status(:ok)
|
|
expect(assigns(:build).id).to eq(build.id)
|
|
end
|
|
end
|
|
|
|
context 'when build does not exist' do
|
|
before do
|
|
get_show(id: 1234)
|
|
end
|
|
|
|
it 'renders not_found' do
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when requesting JSON' do
|
|
let(:merge_request) { create(:merge_request, source_project: project) }
|
|
|
|
before do
|
|
project.add_developer(user)
|
|
sign_in(user)
|
|
|
|
allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)
|
|
|
|
get_show(id: build.id, format: :json)
|
|
end
|
|
|
|
it 'exposes needed information' do
|
|
expect(response).to have_http_status(:ok)
|
|
expect(json_response['new_issue_path']).to end_with('/issues/new')
|
|
expect(json_response['raw_path']).to match(/builds\/\d+\/raw\z/)
|
|
expect(json_response['merge_request_path']).to match(/merge_requests\/\d+\z/)
|
|
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
|
|
|
|
context 'when build has a trace' do
|
|
let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
|
|
|
|
it 'returns a trace' do
|
|
expect(response).to have_http_status(:ok)
|
|
expect(json_response['id']).to eq build.id
|
|
expect(json_response['status']).to eq build.status
|
|
expect(json_response['html']).to eq('BUILD TRACE')
|
|
end
|
|
end
|
|
|
|
context 'when build has no traces' do
|
|
let(:build) { create(:ci_build, pipeline: pipeline) }
|
|
|
|
it 'returns no traces' do
|
|
expect(response).to have_http_status(:ok)
|
|
expect(json_response['id']).to eq build.id
|
|
expect(json_response['status']).to eq build.status
|
|
expect(json_response['html']).to be_nil
|
|
end
|
|
end
|
|
|
|
context 'when build has a trace with ANSI sequence and Unicode' do
|
|
let(:build) { create(:ci_build, :unicode_trace, pipeline: pipeline) }
|
|
|
|
it 'returns a trace with Unicode' do
|
|
expect(response).to have_http_status(:ok)
|
|
expect(json_response['id']).to eq build.id
|
|
expect(json_response['status']).to eq build.status
|
|
expect(json_response['html']).to include("ヾ(´༎ຶД༎ຶ`)ノ")
|
|
end
|
|
end
|
|
|
|
def get_trace
|
|
get :trace, namespace_id: project.namespace,
|
|
project_id: project,
|
|
id: build.id,
|
|
format: :json
|
|
end
|
|
end
|
|
|
|
describe 'GET status.json' do
|
|
let(:build) { create(:ci_build, pipeline: pipeline) }
|
|
let(:status) { build.detailed_status(double('user')) }
|
|
|
|
before do
|
|
get :status, namespace_id: project.namespace,
|
|
project_id: project,
|
|
id: build.id,
|
|
format: :json
|
|
end
|
|
|
|
it 'return a detailed build status in json' do
|
|
expect(response).to have_http_status(:ok)
|
|
expect(json_response['text']).to eq status.text
|
|
expect(json_response['label']).to eq status.label
|
|
expect(json_response['icon']).to eq status.icon
|
|
expect(json_response['favicon']).to eq "/assets/ci_favicons/#{status.favicon}.ico"
|
|
end
|
|
end
|
|
|
|
describe 'POST retry' do
|
|
before do
|
|
project.add_developer(user)
|
|
sign_in(user)
|
|
|
|
post_retry
|
|
end
|
|
|
|
context 'when build is retryable' do
|
|
let(:build) { create(:ci_build, :retryable, pipeline: pipeline) }
|
|
|
|
it 'redirects to the retried build page' do
|
|
expect(response).to have_http_status(:found)
|
|
expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id))
|
|
end
|
|
end
|
|
|
|
context 'when build is not retryable' do
|
|
let(:build) { create(:ci_build, pipeline: pipeline) }
|
|
|
|
it 'renders unprocessable_entity' do
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
end
|
|
end
|
|
|
|
def post_retry
|
|
post :retry, namespace_id: project.namespace,
|
|
project_id: project,
|
|
id: build.id
|
|
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
|
|
|
|
context 'when build is playable' do
|
|
let(:build) { create(:ci_build, :playable, pipeline: pipeline) }
|
|
|
|
it 'redirects to the played build page' do
|
|
expect(response).to have_http_status(:found)
|
|
expect(response).to redirect_to(namespace_project_job_path(id: build.id))
|
|
end
|
|
|
|
it 'transits to pending' do
|
|
expect(build.reload).to be_pending
|
|
end
|
|
end
|
|
|
|
context 'when build is not playable' do
|
|
let(:build) { create(:ci_build, pipeline: pipeline) }
|
|
|
|
it 'renders unprocessable_entity' do
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
end
|
|
end
|
|
|
|
def post_play
|
|
post :play, namespace_id: project.namespace,
|
|
project_id: project,
|
|
id: build.id
|
|
end
|
|
end
|
|
|
|
describe 'POST cancel' do
|
|
before do
|
|
project.add_developer(user)
|
|
sign_in(user)
|
|
|
|
post_cancel
|
|
end
|
|
|
|
context 'when build is cancelable' do
|
|
let(:build) { create(:ci_build, :cancelable, pipeline: pipeline) }
|
|
|
|
it 'redirects to the canceled build page' do
|
|
expect(response).to have_http_status(:found)
|
|
expect(response).to redirect_to(namespace_project_job_path(id: build.id))
|
|
end
|
|
|
|
it 'transits to canceled' do
|
|
expect(build.reload).to be_canceled
|
|
end
|
|
end
|
|
|
|
context 'when build is not cancelable' do
|
|
let(:build) { create(:ci_build, :canceled, pipeline: pipeline) }
|
|
|
|
it 'returns unprocessable_entity' do
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
end
|
|
end
|
|
|
|
def post_cancel
|
|
post :cancel, namespace_id: project.namespace,
|
|
project_id: project,
|
|
id: build.id
|
|
end
|
|
end
|
|
|
|
describe 'POST cancel_all' do
|
|
before do
|
|
project.add_developer(user)
|
|
sign_in(user)
|
|
end
|
|
|
|
context 'when builds are cancelable' do
|
|
before do
|
|
create_list(:ci_build, 2, :cancelable, pipeline: pipeline)
|
|
|
|
post_cancel_all
|
|
end
|
|
|
|
it 'redirects to a index page' do
|
|
expect(response).to have_http_status(:found)
|
|
expect(response).to redirect_to(namespace_project_jobs_path)
|
|
end
|
|
|
|
it 'transits to canceled' do
|
|
expect(Ci::Build.all).to all(be_canceled)
|
|
end
|
|
end
|
|
|
|
context 'when builds are not cancelable' do
|
|
before do
|
|
create_list(:ci_build, 2, :canceled, pipeline: pipeline)
|
|
|
|
post_cancel_all
|
|
end
|
|
|
|
it 'redirects to a index page' do
|
|
expect(response).to have_http_status(:found)
|
|
expect(response).to redirect_to(namespace_project_jobs_path)
|
|
end
|
|
end
|
|
|
|
def post_cancel_all
|
|
post :cancel_all, namespace_id: project.namespace,
|
|
project_id: project
|
|
end
|
|
end
|
|
|
|
describe 'POST erase' do
|
|
before do
|
|
project.add_developer(user)
|
|
sign_in(user)
|
|
|
|
post_erase
|
|
end
|
|
|
|
context 'when build is erasable' do
|
|
let(:build) { create(:ci_build, :erasable, :trace, pipeline: pipeline) }
|
|
|
|
it 'redirects to the erased build page' do
|
|
expect(response).to have_http_status(:found)
|
|
expect(response).to redirect_to(namespace_project_job_path(id: build.id))
|
|
end
|
|
|
|
it 'erases artifacts' do
|
|
expect(build.artifacts_file.exists?).to be_falsey
|
|
expect(build.artifacts_metadata.exists?).to be_falsey
|
|
end
|
|
|
|
it 'erases trace' do
|
|
expect(build.trace.exist?).to be_falsey
|
|
end
|
|
end
|
|
|
|
context 'when build is not erasable' do
|
|
let(:build) { create(:ci_build, :erased, pipeline: pipeline) }
|
|
|
|
it 'returns unprocessable_entity' do
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
end
|
|
end
|
|
|
|
def post_erase
|
|
post :erase, namespace_id: project.namespace,
|
|
project_id: project,
|
|
id: build.id
|
|
end
|
|
end
|
|
|
|
describe 'GET raw' do
|
|
before do
|
|
get_raw
|
|
end
|
|
|
|
context 'when build has a trace file' do
|
|
let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
|
|
|
|
it 'send a trace file' do
|
|
expect(response).to have_http_status(:ok)
|
|
expect(response.content_type).to eq 'text/plain; charset=utf-8'
|
|
expect(response.body).to eq 'BUILD TRACE'
|
|
end
|
|
end
|
|
|
|
context 'when build does not have a trace file' do
|
|
let(:build) { create(:ci_build, pipeline: pipeline) }
|
|
|
|
it 'returns not_found' do
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
end
|
|
|
|
def get_raw
|
|
post :raw, namespace_id: project.namespace,
|
|
project_id: project,
|
|
id: build.id
|
|
end
|
|
end
|
|
end
|