travis-api/spec/integration/v2/jobs_spec.rb
Tyranja a9c31fa5e9 Extract cancel and restart builds and jobs into sidekiq worker
See below for all the commit messages squashed into this one...
add a test

delete empty space

add job_cancellation worker

change id

change job_id param

add job restart worker

add require to sidekiq.rb

change params

add test for job restart and cancellation

add test for job restart

update build.rb improve build spec

update job restart with correct response, add test to chack for correct response when restarting job
2015-01-26 17:29:13 +01:00

299 lines
11 KiB
Ruby

require 'spec_helper'
describe 'Jobs' do
let!(:jobs) {[
FactoryGirl.create(:test, :number => '3.1', :queue => 'builds.common'),
FactoryGirl.create(:test, :number => '3.2', :queue => 'builds.common')
]}
let(:job) { jobs.first }
let(:headers) { { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json' } }
it '/jobs?queue=builds.common' do
response = get '/jobs', { queue: 'builds.common' }, headers
response.should deliver_json_for(Job.queued('builds.common'), version: 'v2')
end
it '/jobs/:id' do
response = get "/jobs/#{job.id}", {}, headers
response.should deliver_json_for(job, version: 'v2')
end
context 'GET /jobs/:job_id/log.txt' do
it 'returns log for a job' do
job.log.update_attributes!(content: 'the log')
response = get "/jobs/#{job.id}/log.txt", {}, headers
response.should deliver_as_txt('the log', version: 'v2')
end
context 'when log is archived' do
it 'redirects to archive' do
job.log.update_attributes!(content: 'the log', archived_at: Time.now, archive_verified: true)
headers = { 'HTTP_ACCEPT' => 'text/plain; version=2' }
response = get "/jobs/#{job.id}/log.txt", {}, headers
response.should redirect_to("https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt")
end
end
context 'when log is missing' do
it 'redirects to archive' do
job.log.destroy
headers = { 'HTTP_ACCEPT' => 'text/plain; version=2' }
response = get "/jobs/#{job.id}/log.txt", {}, headers
response.should redirect_to("https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt")
end
end
context 'with cors_hax param' do
it 'renders No Content response with location of the archived log' do
job.log.destroy
headers = { 'HTTP_ACCEPT' => 'text/plain; version=2' }
response = get "/jobs/#{job.id}/log.txt?cors_hax=true", {}, headers
response.status.should == 204
response.headers['Location'].should == "https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt"
end
end
context 'with chunked log requested' do
it 'responds with only selected chunks if after is specified' do
job.log.parts << Log::Part.new(content: 'foo', number: 1, final: false)
job.log.parts << Log::Part.new(content: 'bar', number: 2, final: true)
job.log.parts << Log::Part.new(content: 'bar', number: 3, final: true)
headers = { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json; chunked=true' }
response = get "/jobs/#{job.id}/log", { after: 1 }, headers
body = JSON.parse(response.body)
body['log']['parts'].map { |p| p['number'] }.sort.should == [2, 3]
end
it 'responds with only selected chunks if part_numbers are requested' do
job.log.parts << Log::Part.new(content: 'foo', number: 1, final: false)
job.log.parts << Log::Part.new(content: 'bar', number: 2, final: true)
job.log.parts << Log::Part.new(content: 'bar', number: 3, final: true)
headers = { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json; chunked=true' }
response = get "/jobs/#{job.id}/log", { part_numbers: '1,3,4' }, headers
body = JSON.parse(response.body)
body['log']['parts'].map { |p| p['number'] }.sort.should == [1, 3]
end
it 'responds with 406 when log is already aggregated' do
job.log.update_attributes(aggregated_at: Time.now, archived_at: Time.now, archive_verified: true)
job.log.should be_archived
headers = { 'HTTP_ACCEPT' => 'application/json; version=2; chunked=true' }
response = get "/jobs/#{job.id}/log", {}, headers
response.status.should == 406
end
it 'responds with chunks instead of full log' do
job.log.parts << Log::Part.new(content: 'foo', number: 1, final: false)
job.log.parts << Log::Part.new(content: 'bar', number: 2, final: true)
headers = { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json; chunked=true' }
response = get "/jobs/#{job.id}/log", {}, headers
response.should deliver_json_for(job.log, version: 'v2', params: { chunked: true})
end
it 'responds with full log if chunks are not available and full log is accepted' do
job.log.update_attributes(aggregated_at: Time.now)
headers = { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json; chunked=true, application/vnd.travis-ci.2+json' }
response = get "/jobs/#{job.id}/log", {}, headers
response.should deliver_json_for(job.log, version: 'v2')
end
end
it 'adds removed info if the log is removed' do
time = Time.utc(2015, 1, 9, 12, 57, 31)
job.log.update_attributes(removed_at: time, removed_by: User.first)
headers = { 'HTTP_ACCEPT' => 'application/json; chunked=true; version=2' }
response = get "/jobs/#{job.id}/log", {}, headers
body = JSON.parse(response.body)
body['log']['removed_by'].should == 'Sven Fuchs'
body['log']['removed_at'].should == "2015-01-09T12:57:31Z"
body['log']['id'].should == job.log.id
# make sure we return parts as chunked=true
body['log']['parts'].length.should == 1
end
end
describe 'PATCH /jobs/:job_id/log' do
let(:user) { User.where(login: 'svenfuchs').first }
let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: -1) }
before :each do
headers.merge! 'HTTP_AUTHORIZATION' => "token #{token}"
end
context 'when user does not have push permissions' do
before :each do
user.permissions.create!(repository_id: job.repository.id, :push => false)
end
it 'returns status 401' do
response = patch "/jobs/#{job.id}/log", { reason: 'Because reason!' }, headers
response.status.should == 401
end
end
context 'when user has push permission' do
context 'when job is not finished' do
before :each do
job.stubs(:finished?).returns false
user.permissions.create!(repository_id: job.repository.id, :push => true)
end
it 'returns status 409' do
response = patch "/jobs/#{job.id}/log", { reason: 'Because reason!' }, headers
response.status.should == 409
end
end
context 'when job is finished' do
let(:finished_job) { Factory(:test, state: 'passed') }
before :each do
user.permissions.create!(repository_id: finished_job.repository.id, :push => true)
end
it 'returns status 200' do
response = patch "/jobs/#{finished_job.id}/log", { reason: 'Because reason!' }, headers
response.status.should == 200
end
end
end
context 'when job is not found' do
# TODO
end
end
it "GET /jobs/:id/annotations" do
annotation_provider = Factory(:annotation_provider)
annotation = annotation_provider.annotations.create(job_id: job.id, status: "passed", description: "Foobar")
response = get "/jobs/#{job.id}/annotations", {}, headers
response.should deliver_json_for(Annotation.where(id: annotation.id), version: 'v2')
end
describe "POST /jobs/:id/annotations" do
context "with valid credentials" do
it "responds with a 204" do
Travis::Services::UpdateAnnotation.any_instance.stubs(:annotations_enabled?).returns(true)
annotation_provider = Factory(:annotation_provider)
response = post "/jobs/#{job.id}/annotations", { username: annotation_provider.api_username, key: annotation_provider.api_key, status: "passed", description: "Foobar" }, headers
response.status.should eq(204)
end
end
context "without a description" do
it "responds with a 422" do
annotation_provider = Factory(:annotation_provider)
response = post "/jobs/#{job.id}/annotations", { username: annotation_provider.api_username, key: annotation_provider.api_key, status: "errored" }, headers
response.status.should eq(422)
end
end
context "without a status" do
it "responds with a 422" do
annotation_provider = Factory(:annotation_provider)
response = post "/jobs/#{job.id}/annotations", { username: annotation_provider.api_username, key: annotation_provider.api_key, description: "Foobar" }, headers
response.status.should eq(422)
end
end
context "with invalid credentials" do
it "responds with a 401" do
response = post "/jobs/#{job.id}/annotations", { username: "invalid-username", key: "invalid-key", status: "passed", description: "Foobar" }, headers
response.status.should eq(401)
end
end
end
describe 'POST /jobs/:id/cancel' do
let(:user) { User.where(login: 'svenfuchs').first }
let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: -1) }
before {
headers.merge! 'HTTP_AUTHORIZATION' => "token #{token}"
user.permissions.create!(repository_id: job.repository.id, :push => true, :pull => true)
}
context 'when user does not have rights to cancel the job' do
before { user.permissions.destroy_all }
it 'responds with 403' do
response = post "/jobs/#{job.id}/cancel", {}, headers
response.status.should == 403
end
end
context 'when job is not cancelable' do
before { job.update_attribute(:state, 'passed') }
it 'responds with 422' do
response = post "/jobs/#{job.id}/cancel", {}, headers
response.status.should == 422
end
end
context 'when job can be canceled' do
before do
job.update_attribute(:state, 'created')
end
it 'cancels the job' do
Travis::Sidekiq::JobCancellation.expects(:perform_async).with( id: job.id.to_s, user_id: user.id, source: 'api')
post "/jobs/#{job.id}/cancel", {}, headers
end
it 'responds with 204' do
response = post "/jobs/#{job.id}/cancel", {}, headers
response.status.should == 204
end
end
end
describe 'POST /jobs/:id/restart' do
let(:user) { User.where(login: 'svenfuchs').first }
let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: -1) }
before {
headers.merge! 'HTTP_AUTHORIZATION' => "token #{token}"
user.permissions.create!(repository_id: job.repository.id, :pull => true, :push => true)
}
context 'when restart is not acceptable' do
before { user.permissions.destroy_all }
it 'responds with 400' do
response = post "/jobs/#{job.id}/restart", {}, headers
response.status.should == 400
end
end
context 'when job passed' do
before do
Travis::Sidekiq::JobCancellation.stubs(:perform_async)
job.update_attribute(:state, 'passed')
end
it 'restarts the job' do
Travis::Sidekiq::JobRestart.expects(:perform_async).with(id: job.id.to_s, user_id: user.id)
response = post "/jobs/#{job.id}/restart", {}, headers
response.status.should == 200
end
it 'sends the correct response body' do
Travis::Sidekiq::JobRestart.expects(:perform_async).with(id: job.id.to_s, user_id: user.id)
response = post "/jobs/#{job.id}/restart", {}, headers
body = JSON.parse(response.body)
body.should == {"result"=>true, "flash"=>[{"notice"=>"The job was successfully restarted."}]}
end
end
end
end