From 845f02d8d9cb29aa308d3d17ef7430263e182dd8 Mon Sep 17 00:00:00 2001 From: carlad Date: Thu, 14 Apr 2016 10:14:20 +0200 Subject: [PATCH 01/11] add request endpoint --- lib/travis/api/v3/renderer/request.rb | 2 +- lib/travis/api/v3/routes.rb | 6 ++++++ lib/travis/api/v3/services.rb | 1 + lib/travis/api/v3/services/request/request.rb | 7 +++++++ 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 lib/travis/api/v3/services/request/request.rb diff --git a/lib/travis/api/v3/renderer/request.rb b/lib/travis/api/v3/renderer/request.rb index 356a74fe..2553b092 100644 --- a/lib/travis/api/v3/renderer/request.rb +++ b/lib/travis/api/v3/renderer/request.rb @@ -3,6 +3,6 @@ require 'travis/api/v3/renderer/model_renderer' module Travis::API::V3 class Renderer::Request < Renderer::ModelRenderer representation(:minimal, :id) - representation(:standard, :id, :repository, :commit, :owner, :created_at, :result, :message, :event_type) + representation(:standard, :id, :repository, :branch, :commit, :owner, :created_at, :result, :message, :event_type) end end diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb index 6d2eaa1b..b472af12 100644 --- a/lib/travis/api/v3/routes.rb +++ b/lib/travis/api/v3/routes.rb @@ -99,6 +99,12 @@ module Travis::API::V3 end end + resource :request do + capture id: :digit + route '/request/{request.id}' + get :find + end + resource :user do capture id: :digit route '/user' diff --git a/lib/travis/api/v3/services.rb b/lib/travis/api/v3/services.rb index 985e9d4e..c4ad6e7f 100644 --- a/lib/travis/api/v3/services.rb +++ b/lib/travis/api/v3/services.rb @@ -17,6 +17,7 @@ module Travis::API::V3 Owner = Module.new { extend Services } Repositories = Module.new { extend Services } Repository = Module.new { extend Services } + Request = Module.new { extend Services } Requests = Module.new { extend Services } User = Module.new { extend Services } diff --git a/lib/travis/api/v3/services/request/request.rb b/lib/travis/api/v3/services/request/request.rb new file mode 100644 index 00000000..b2eb6502 --- /dev/null +++ b/lib/travis/api/v3/services/request/request.rb @@ -0,0 +1,7 @@ +module Travis::API::V3 + class Services::Request::Find < Service + def run! + find + end + end +end From 6b7526dd7edcf8f2ebdbb7a15492b9474480a930 Mon Sep 17 00:00:00 2001 From: carlad Date: Thu, 14 Apr 2016 10:19:28 +0200 Subject: [PATCH 02/11] remove request endpoint --- lib/travis/api/v3/routes.rb | 6 ------ lib/travis/api/v3/services.rb | 1 - lib/travis/api/v3/services/request/request.rb | 7 ------- 3 files changed, 14 deletions(-) delete mode 100644 lib/travis/api/v3/services/request/request.rb diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb index b472af12..6d2eaa1b 100644 --- a/lib/travis/api/v3/routes.rb +++ b/lib/travis/api/v3/routes.rb @@ -99,12 +99,6 @@ module Travis::API::V3 end end - resource :request do - capture id: :digit - route '/request/{request.id}' - get :find - end - resource :user do capture id: :digit route '/user' diff --git a/lib/travis/api/v3/services.rb b/lib/travis/api/v3/services.rb index c4ad6e7f..985e9d4e 100644 --- a/lib/travis/api/v3/services.rb +++ b/lib/travis/api/v3/services.rb @@ -17,7 +17,6 @@ module Travis::API::V3 Owner = Module.new { extend Services } Repositories = Module.new { extend Services } Repository = Module.new { extend Services } - Request = Module.new { extend Services } Requests = Module.new { extend Services } User = Module.new { extend Services } diff --git a/lib/travis/api/v3/services/request/request.rb b/lib/travis/api/v3/services/request/request.rb deleted file mode 100644 index b2eb6502..00000000 --- a/lib/travis/api/v3/services/request/request.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Travis::API::V3 - class Services::Request::Find < Service - def run! - find - end - end -end From c22998fdcf709b46b3a67c1c25e7427e5bec2b75 Mon Sep 17 00:00:00 2001 From: carlad Date: Thu, 14 Apr 2016 10:39:59 +0200 Subject: [PATCH 03/11] add branch_name to request renderer --- lib/travis/api/v3/renderer/request.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/travis/api/v3/renderer/request.rb b/lib/travis/api/v3/renderer/request.rb index 2553b092..112315fc 100644 --- a/lib/travis/api/v3/renderer/request.rb +++ b/lib/travis/api/v3/renderer/request.rb @@ -3,6 +3,6 @@ require 'travis/api/v3/renderer/model_renderer' module Travis::API::V3 class Renderer::Request < Renderer::ModelRenderer representation(:minimal, :id) - representation(:standard, :id, :repository, :branch, :commit, :owner, :created_at, :result, :message, :event_type) + representation(:standard, :id, :repository, :branch_name, :commit, :owner, :created_at, :result, :message, :event_type) end end From 55f83789409bc876f61911581908c32175e721d7 Mon Sep 17 00:00:00 2001 From: carlad Date: Thu, 14 Apr 2016 11:15:17 +0200 Subject: [PATCH 04/11] add branch_name method --- Gemfile.lock | 3 --- lib/travis/api/v3/models/request.rb | 7 +++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f4305853..8aa7952c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -388,6 +388,3 @@ DEPENDENCIES travis-yaml! unicorn yard-sinatra! - -BUNDLED WITH - 1.11.2 diff --git a/lib/travis/api/v3/models/request.rb b/lib/travis/api/v3/models/request.rb index fd1387a8..a5df405f 100644 --- a/lib/travis/api/v3/models/request.rb +++ b/lib/travis/api/v3/models/request.rb @@ -6,5 +6,12 @@ module Travis::API::V3 has_many :builds serialize :config serialize :payload + + # has_one :branch_name, + # primary_key: [:id, :branch_name] + + def branch_name + read_attribute(:branch_name) + end end end From 27f18d77ac2148f5e3bba5ec1cee0c16d87034bd Mon Sep 17 00:00:00 2001 From: carlad Date: Thu, 14 Apr 2016 11:26:51 +0200 Subject: [PATCH 05/11] rename branch, add method to model --- lib/travis/api/v3/models/request.rb | 8 ++++---- lib/travis/api/v3/renderer/request.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/travis/api/v3/models/request.rb b/lib/travis/api/v3/models/request.rb index a5df405f..109d0b8b 100644 --- a/lib/travis/api/v3/models/request.rb +++ b/lib/travis/api/v3/models/request.rb @@ -7,11 +7,11 @@ module Travis::API::V3 serialize :config serialize :payload - # has_one :branch_name, - # primary_key: [:id, :branch_name] + has_one :branch, + primary_key: [:id, :branch_name] - def branch_name - read_attribute(:branch_name) + def branch + read_attribute(:branch) end end end diff --git a/lib/travis/api/v3/renderer/request.rb b/lib/travis/api/v3/renderer/request.rb index 112315fc..2553b092 100644 --- a/lib/travis/api/v3/renderer/request.rb +++ b/lib/travis/api/v3/renderer/request.rb @@ -3,6 +3,6 @@ require 'travis/api/v3/renderer/model_renderer' module Travis::API::V3 class Renderer::Request < Renderer::ModelRenderer representation(:minimal, :id) - representation(:standard, :id, :repository, :branch_name, :commit, :owner, :created_at, :result, :message, :event_type) + representation(:standard, :id, :repository, :branch, :commit, :owner, :created_at, :result, :message, :event_type) end end From 506e0f0f7aa4ad516446778301bb0e7d2880206e Mon Sep 17 00:00:00 2001 From: carlad Date: Tue, 19 Apr 2016 15:26:28 +0200 Subject: [PATCH 06/11] add check for state on job restart and cancel --- lib/travis/api/v3.rb | 2 ++ lib/travis/api/v3/queries/job.rb | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lib/travis/api/v3.rb b/lib/travis/api/v3.rb index dd8c2af6..8a7cb55f 100644 --- a/lib/travis/api/v3.rb +++ b/lib/travis/api/v3.rb @@ -35,6 +35,8 @@ module Travis NotImplemented = ServerError .create('request not (yet) implemented', status: 501) RequestLimitReached = ClientError .create('request limit reached for resource', status: 429) AlreadySyncing = ClientError .create('sync already in progress', status: 409) + AlreadyRunning = ClientError .create('job already running', status: 409) + NotCancelable = ClientError .create('job is not running, cannot canel', status: 409) MethodNotAllowed = ClientError .create('method not allowed', status: 405) end end diff --git a/lib/travis/api/v3/queries/job.rb b/lib/travis/api/v3/queries/job.rb index 79efdc87..a1b8fb4d 100644 --- a/lib/travis/api/v3/queries/job.rb +++ b/lib/travis/api/v3/queries/job.rb @@ -8,12 +8,17 @@ module Travis::API::V3 end def cancel(user) + puts find.state + raise NotCancelable if %w(passed failed cancelled errored).include? find.state payload = { id: id, user_id: user.id, source: 'api' } perform_async(:job_cancellation, payload) payload end def restart(user) + puts find.state + puts find.state.class + raise AlreadyRunning if %w(received queued started).include? find.state payload = { id: id, user_id: user.id, source: 'api' } perform_async(:job_restart, payload) payload From ec217a58f1d0853031d55350740ce8908d522cb2 Mon Sep 17 00:00:00 2001 From: carlad Date: Tue, 19 Apr 2016 18:29:46 +0200 Subject: [PATCH 07/11] correct typo --- lib/travis/api/v3.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/travis/api/v3.rb b/lib/travis/api/v3.rb index 8a7cb55f..59add8e6 100644 --- a/lib/travis/api/v3.rb +++ b/lib/travis/api/v3.rb @@ -36,7 +36,7 @@ module Travis RequestLimitReached = ClientError .create('request limit reached for resource', status: 429) AlreadySyncing = ClientError .create('sync already in progress', status: 409) AlreadyRunning = ClientError .create('job already running', status: 409) - NotCancelable = ClientError .create('job is not running, cannot canel', status: 409) + NotCancelable = ClientError .create('job is not running, cannot cancel', status: 409) MethodNotAllowed = ClientError .create('method not allowed', status: 405) end end From 379a63bf00fc5a9cd524033594259c640ff9c731 Mon Sep 17 00:00:00 2001 From: carlad Date: Wed, 20 Apr 2016 11:08:29 +0200 Subject: [PATCH 08/11] fix spelling of canceled, remove debug output --- lib/travis/api/v3/queries/job.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/travis/api/v3/queries/job.rb b/lib/travis/api/v3/queries/job.rb index a1b8fb4d..91ad3b84 100644 --- a/lib/travis/api/v3/queries/job.rb +++ b/lib/travis/api/v3/queries/job.rb @@ -8,16 +8,13 @@ module Travis::API::V3 end def cancel(user) - puts find.state - raise NotCancelable if %w(passed failed cancelled errored).include? find.state + raise NotCancelable if %w(passed failed canceled errored).include? find.state payload = { id: id, user_id: user.id, source: 'api' } perform_async(:job_cancellation, payload) payload end def restart(user) - puts find.state - puts find.state.class raise AlreadyRunning if %w(received queued started).include? find.state payload = { id: id, user_id: user.id, source: 'api' } perform_async(:job_restart, payload) From 30d73782c895bba171a600d15869809d48d1777b Mon Sep 17 00:00:00 2001 From: carlad Date: Wed, 20 Apr 2016 11:33:20 +0200 Subject: [PATCH 09/11] add error check to build restart and cancel --- lib/travis/api/v3.rb | 23 +++++++++++++---------- lib/travis/api/v3/queries/build.rb | 2 ++ lib/travis/api/v3/queries/job.rb | 4 ++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/travis/api/v3.rb b/lib/travis/api/v3.rb index 59add8e6..0c7c3ae7 100644 --- a/lib/travis/api/v3.rb +++ b/lib/travis/api/v3.rb @@ -25,19 +25,22 @@ module Travis load_dir("#{__dir__}/v3") ClientError = Error .create(status: 400) - NotFound = ClientError .create(:resource, status: 404, template: '%s not found (or insufficient access)') - EntityMissing = NotFound .create(type: 'not_found') - WrongCredentials = ClientError .create('access denied', status: 403) - LoginRequired = ClientError .create('login required', status: 403) - InsufficientAccess = ClientError .create(status: 403) - WrongParams = ClientError .create('wrong parameters') ServerError = Error .create(status: 500) + NotFound = ClientError .create(:resource, status: 404, template: '%s not found (or insufficient access)') + + AlreadySyncing = ClientError .create('sync already in progress', status: 409) + BuildAlreadyRunning = ClientError .create('build already running', status: 409) + BuildNotCancelable = ClientError .create('build is not running, cannot cancel', status: 409) + EntityMissing = NotFound .create(type: 'not_found') + InsufficientAccess = ClientError .create(status: 403) + JobAlreadyRunning = ClientError .create('job already running', status: 409) + JobNotCancelable = ClientError .create('job is not running, cannot cancel', status: 409) + LoginRequired = ClientError .create('login required', status: 403) + MethodNotAllowed = ClientError .create('method not allowed', status: 405) NotImplemented = ServerError .create('request not (yet) implemented', status: 501) RequestLimitReached = ClientError .create('request limit reached for resource', status: 429) - AlreadySyncing = ClientError .create('sync already in progress', status: 409) - AlreadyRunning = ClientError .create('job already running', status: 409) - NotCancelable = ClientError .create('job is not running, cannot cancel', status: 409) - MethodNotAllowed = ClientError .create('method not allowed', status: 405) + WrongCredentials = ClientError .create('access denied', status: 403) + WrongParams = ClientError .create('wrong parameters') end end end diff --git a/lib/travis/api/v3/queries/build.rb b/lib/travis/api/v3/queries/build.rb index 540837d7..5314a7c9 100644 --- a/lib/travis/api/v3/queries/build.rb +++ b/lib/travis/api/v3/queries/build.rb @@ -8,12 +8,14 @@ module Travis::API::V3 end def cancel(user) + raise BuildNotCancelable if %w(passed failed canceled errored).include? find.state payload = { id: id, user_id: user.id, source: 'api' } perform_async(:build_cancellation, payload) payload end def restart(user) + raise BuildAlreadyRunning if %w(received queued started).include? find.state payload = { id: id, user_id: user.id, source: 'api' } perform_async(:build_restart, payload) payload diff --git a/lib/travis/api/v3/queries/job.rb b/lib/travis/api/v3/queries/job.rb index 91ad3b84..ba824d4d 100644 --- a/lib/travis/api/v3/queries/job.rb +++ b/lib/travis/api/v3/queries/job.rb @@ -8,14 +8,14 @@ module Travis::API::V3 end def cancel(user) - raise NotCancelable if %w(passed failed canceled errored).include? find.state + raise JobNotCancelable if %w(passed failed canceled errored).include? find.state payload = { id: id, user_id: user.id, source: 'api' } perform_async(:job_cancellation, payload) payload end def restart(user) - raise AlreadyRunning if %w(received queued started).include? find.state + raise JobAlreadyRunning if %w(received queued started).include? find.state payload = { id: id, user_id: user.id, source: 'api' } perform_async(:job_restart, payload) payload From 63bef443e87c8c785390a3737b55c38815a0ffad Mon Sep 17 00:00:00 2001 From: carlad Date: Wed, 20 Apr 2016 11:55:03 +0200 Subject: [PATCH 10/11] update build_cancel spec --- spec/v3/services/build/cancel_spec.rb | 152 ++++++++++++++++++++++---- 1 file changed, 132 insertions(+), 20 deletions(-) diff --git a/spec/v3/services/build/cancel_spec.rb b/spec/v3/services/build/cancel_spec.rb index 6940d4a2..f49d27cd 100644 --- a/spec/v3/services/build/cancel_spec.rb +++ b/spec/v3/services/build/cancel_spec.rb @@ -77,36 +77,148 @@ describe Travis::API::V3::Services::Build::Cancel do }} end - describe "existing repository, push access" do + describe "existing repository, push access, not cancelable" do let(:params) {{}} let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } - before { post("/v3/build/#{build.id}/cancel", params, headers) } - example { expect(last_response.status).to be == 202 } - example { expect(JSON.load(body).to_s).to include( - "@type", - "build", - "@href", - "@representation", - "minimal", - "cancel", - "id", - "state_change") - } + describe "passed state" do + before { build.update_attribute(:state, "passed") } + before { post("/v3/build/#{build.id}/cancel", params, headers) } - example { expect(sidekiq_payload).to be == { - "id" => "#{build.id}", - "user_id"=> repo.owner_id, - "source" => "api"} - } + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "build_not_cancelable", + "error_message" => "build is not running, cannot cancel" + }} + end - example { expect(Sidekiq::Client.last['queue']).to be == 'build_cancellations' } - example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildCancellation' } + describe "errored state" do + before { build.update_attribute(:state, "errored") } + before { post("/v3/build/#{build.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "build_not_cancelable", + "error_message" => "build is not running, cannot cancel" + }} + end + + describe "failed state" do + before { build.update_attribute(:state, "failed") } + before { post("/v3/build/#{build.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "build_not_cancelable", + "error_message" => "build is not running, cannot cancel" + }} + end + + describe "canceled state" do + before { build.update_attribute(:state, "canceled") } + before { post("/v3/build/#{build.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "build_not_cancelable", + "error_message" => "build is not running, cannot cancel" + }} + end + end + + describe "existing repository, push access, cancelable" do + let(:params) {{}} + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } + + describe "started state" do + before { build.update_attribute(:state, "started") } + before { post("/v3/build/#{build.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "build", + "@href", + "@representation", + "minimal", + "cancel", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{build.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'build_cancellations' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildCancellation' } + end + + describe "started queued" do + before { build.update_attribute(:state, "queued") } + before { post("/v3/build/#{build.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "build", + "@href", + "@representation", + "minimal", + "cancel", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{build.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'build_cancellations' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildCancellation' } + end + + describe "received state" do + before { build.update_attribute(:state, "received") } + before { post("/v3/build/#{build.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "build", + "@href", + "@representation", + "minimal", + "cancel", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{build.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'build_cancellations' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildCancellation' } + end describe "setting id has no effect" do let(:params) {{ id: 42 }} + before { post("/v3/build/#{build.id}/cancel", params, headers) } example { expect(sidekiq_payload).to be == { "id" => "#{build.id}", "user_id"=> repo.owner_id, From 7b5c11fca6f0f46f4ac6743ca23abb270c4e5ddd Mon Sep 17 00:00:00 2001 From: carlad Date: Wed, 20 Apr 2016 14:31:08 +0200 Subject: [PATCH 11/11] add specs, update error names --- lib/travis/api/v3.rb | 4 +- spec/v3/services/build/cancel_spec.rb | 2 +- spec/v3/services/build/restart_spec.rb | 171 ++++++++++++++++++++++--- spec/v3/services/job/cancel_spec.rb | 153 +++++++++++++++++++--- spec/v3/services/job/restart_spec.rb | 168 +++++++++++++++++++++--- 5 files changed, 433 insertions(+), 65 deletions(-) diff --git a/lib/travis/api/v3.rb b/lib/travis/api/v3.rb index 0c7c3ae7..610de9cd 100644 --- a/lib/travis/api/v3.rb +++ b/lib/travis/api/v3.rb @@ -29,11 +29,11 @@ module Travis NotFound = ClientError .create(:resource, status: 404, template: '%s not found (or insufficient access)') AlreadySyncing = ClientError .create('sync already in progress', status: 409) - BuildAlreadyRunning = ClientError .create('build already running', status: 409) + BuildAlreadyRunning = ClientError .create('build already running, cannot restart', status: 409) BuildNotCancelable = ClientError .create('build is not running, cannot cancel', status: 409) EntityMissing = NotFound .create(type: 'not_found') InsufficientAccess = ClientError .create(status: 403) - JobAlreadyRunning = ClientError .create('job already running', status: 409) + JobAlreadyRunning = ClientError .create('job already running, cannot restart', status: 409) JobNotCancelable = ClientError .create('job is not running, cannot cancel', status: 409) LoginRequired = ClientError .create('login required', status: 403) MethodNotAllowed = ClientError .create('method not allowed', status: 405) diff --git a/spec/v3/services/build/cancel_spec.rb b/spec/v3/services/build/cancel_spec.rb index f49d27cd..90e9a107 100644 --- a/spec/v3/services/build/cancel_spec.rb +++ b/spec/v3/services/build/cancel_spec.rb @@ -164,7 +164,7 @@ describe Travis::API::V3::Services::Build::Cancel do example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildCancellation' } end - describe "started queued" do + describe "queued state" do before { build.update_attribute(:state, "queued") } before { post("/v3/build/#{build.id}/cancel", params, headers) } diff --git a/spec/v3/services/build/restart_spec.rb b/spec/v3/services/build/restart_spec.rb index 40e7ba5d..121c9f9b 100644 --- a/spec/v3/services/build/restart_spec.rb +++ b/spec/v3/services/build/restart_spec.rb @@ -77,36 +77,165 @@ describe Travis::API::V3::Services::Build::Restart do }} end - describe "existing repository, push access" do + describe "existing repository, push access, build already running" do let(:params) {{}} let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } - before { post("/v3/build/#{build.id}/restart", params, headers) } - example { expect(last_response.status).to be == 202 } - example { expect(JSON.load(body).to_s).to include( - "@type", - "pending", - "build", - "@href", - "@representation", - "minimal", - "restart", - "id", - "state_change") - } + describe "started state" do + before { build.update_attribute(:state, "started") } + before { post("/v3/build/#{build.id}/restart", params, headers) } - example { expect(sidekiq_payload).to be == { - "id" => "#{build.id}", - "user_id"=> repo.owner_id, - "source" => "api"} - } + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "build_already_running", + "error_message" => "build already running, cannot restart" + }} + end - example { expect(Sidekiq::Client.last['queue']).to be == 'build_restarts' } - example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildRestart' } + describe "queued state" do + before { build.update_attribute(:state, "queued") } + before { post("/v3/build/#{build.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "build_already_running", + "error_message" => "build already running, cannot restart" + }} + end + + describe "received state" do + before { build.update_attribute(:state, "received") } + before { post("/v3/build/#{build.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "build_already_running", + "error_message" => "build already running, cannot restart" + }} + end + end + + describe "existing repository, push access, build not already running" do + let(:params) {{}} + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } + + describe "errored state" do + before { build.update_attribute(:state, "errored") } + before { post("/v3/build/#{build.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "build", + "@href", + "@representation", + "minimal", + "restart", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{build.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'build_restarts' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildRestart' } + end + + describe "passed state" do + before { build.update_attribute(:state, "passed") } + before { post("/v3/build/#{build.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "build", + "@href", + "@representation", + "minimal", + "restart", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{build.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'build_restarts' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildRestart' } + end + + describe "failed state" do + before { build.update_attribute(:state, "failed") } + before { post("/v3/build/#{build.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "build", + "@href", + "@representation", + "minimal", + "restart", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{build.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'build_restarts' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildRestart' } + end + + describe "canceled state" do + before { build.update_attribute(:state, "canceled") } + before { post("/v3/build/#{build.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "build", + "@href", + "@representation", + "minimal", + "restart", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{build.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'build_restarts' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::BuildRestart' } + end describe "setting id has no effect" do + before { post("/v3/build/#{build.id}/restart", params, headers) } let(:params) {{ id: 42 }} example { expect(sidekiq_payload).to be == { "id" => "#{build.id}", diff --git a/spec/v3/services/job/cancel_spec.rb b/spec/v3/services/job/cancel_spec.rb index 6eb30301..48faac52 100644 --- a/spec/v3/services/job/cancel_spec.rb +++ b/spec/v3/services/job/cancel_spec.rb @@ -78,35 +78,94 @@ describe Travis::API::V3::Services::Job::Cancel do }} end - describe "existing repository, push access" do + describe "existing repository, push access, job cancelable" do let(:params) {{}} let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } - before { post("/v3/job/#{job.id}/cancel", params, headers) } - example { expect(last_response.status).to be == 202 } - example { expect(JSON.load(body).to_s).to include( - "@type", - "job", - "@href", - "@representation", - "minimal", - "cancel", - "id", - "state_change") - } + describe "started state" do + before { job.update_attribute(:state, "started") } + before { post("/v3/job/#{job.id}/cancel", params, headers) } - example { expect(sidekiq_payload).to be == { - "id" => "#{job.id}", - "user_id"=> repo.owner_id, - "source" => "api"} - } + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "job", + "@href", + "@representation", + "minimal", + "cancel", + "id", + "state_change") + } - example { expect(Sidekiq::Client.last['queue']).to be == 'job_cancellations' } - example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::JobCancellation' } + example { expect(sidekiq_payload).to be == { + "id" => "#{job.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'job_cancellations' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::JobCancellation' } + end + describe "queued state" do + before { job.update_attribute(:state, "queued") } + before { post("/v3/job/#{job.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "job", + "@href", + "@representation", + "minimal", + "cancel", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{job.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'job_cancellations' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::JobCancellation' } + end + + describe "received state" do + before { job.update_attribute(:state, "received") } + before { post("/v3/job/#{job.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "job", + "@href", + "@representation", + "minimal", + "cancel", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{job.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'job_cancellations' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::JobCancellation' } + end describe "setting id has no effect" do + before { post("/v3/job/#{job.id}/cancel", params, headers) } let(:params) {{ id: 42 }} example { expect(sidekiq_payload).to be == { "id" => "#{job.id}", @@ -115,6 +174,60 @@ describe Travis::API::V3::Services::Job::Cancel do } end end + describe "existing repository, push access, not cancelable" do + let(:params) {{}} + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } + + describe "passed state" do + before { job.update_attribute(:state, "passed") } + before { post("/v3/job/#{job.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "job_not_cancelable", + "error_message" => "job is not running, cannot cancel" + }} + end + + describe "errored state" do + before { job.update_attribute(:state, "errored") } + before { post("/v3/job/#{job.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "job_not_cancelable", + "error_message" => "job is not running, cannot cancel" + }} + end + + describe "failed state" do + before { job.update_attribute(:state, "failed") } + before { post("/v3/job/#{job.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "job_not_cancelable", + "error_message" => "job is not running, cannot cancel" + }} + end + + describe "canceled state" do + before { job.update_attribute(:state, "canceled") } + before { post("/v3/job/#{job.id}/cancel", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "job_not_cancelable", + "error_message" => "job is not running, cannot cancel" + }} + end + end # TODO decided to discuss further with rkh as this use case doesn't really exist at the moment # and 'fixing' the query requires modifying workers that v2 uses, thereby running the risk of breaking v2, diff --git a/spec/v3/services/job/restart_spec.rb b/spec/v3/services/job/restart_spec.rb index c4884f41..a07f0b82 100644 --- a/spec/v3/services/job/restart_spec.rb +++ b/spec/v3/services/job/restart_spec.rb @@ -78,36 +78,119 @@ describe Travis::API::V3::Services::Job::Restart do }} end - describe "existing repository, push access" do + describe "existing repository, push access, job not already running" do let(:params) {{}} let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } - before { post("/v3/job/#{job.id}/restart", params, headers) } - example { expect(last_response.status).to be == 202 } - example { expect(JSON.load(body).to_s).to include( - "@type", - "pending", - "job", - "@href", - "@representation", - "minimal", - "restart", - "id", - "state_change") - } + describe "canceled state" do + before { job.update_attribute(:state, "canceled") } + before { post("/v3/job/#{job.id}/restart", params, headers) } - example { expect(sidekiq_payload).to be == { - "id" => "#{job.id}", - "user_id"=> repo.owner_id, - "source" => "api"} - } + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "job", + "@href", + "@representation", + "minimal", + "restart", + "id", + "state_change") + } - example { expect(Sidekiq::Client.last['queue']).to be == 'job_restarts' } - example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::JobRestart' } + example { expect(sidekiq_payload).to be == { + "id" => "#{job.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'job_restarts' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::JobRestart' } + end + describe "errored state" do + before { job.update_attribute(:state, "errored") } + before { post("/v3/job/#{job.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "job", + "@href", + "@representation", + "minimal", + "restart", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{job.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'job_restarts' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::JobRestart' } + end + describe "failed state" do + before { job.update_attribute(:state, "failed") } + before { post("/v3/job/#{job.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "job", + "@href", + "@representation", + "minimal", + "restart", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{job.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'job_restarts' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::JobRestart' } + end + describe "passed state" do + before { job.update_attribute(:state, "passed") } + before { post("/v3/job/#{job.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 202 } + example { expect(JSON.load(body).to_s).to include( + "@type", + "pending", + "job", + "@href", + "@representation", + "minimal", + "restart", + "id", + "state_change") + } + + example { expect(sidekiq_payload).to be == { + "id" => "#{job.id}", + "user_id"=> repo.owner_id, + "source" => "api"} + } + + example { expect(Sidekiq::Client.last['queue']).to be == 'job_restarts' } + example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Sidekiq::JobRestart' } + end describe "setting id has no effect" do + before { post("/v3/job/#{job.id}/restart", params, headers) } let(:params) {{ id: 42 }} example { expect(sidekiq_payload).to be == { "id" => "#{job.id}", @@ -117,6 +200,49 @@ describe Travis::API::V3::Services::Job::Restart do end end + describe "existing repository, push access, job already running" do + let(:params) {{}} + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } + + describe "started state" do + before { job.update_attribute(:state, "started") } + before { post("/v3/job/#{job.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "job_already_running", + "error_message" => "job already running, cannot restart" + }} + end + + describe "queued state" do + before { job.update_attribute(:state, "queued") } + before { post("/v3/job/#{job.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "job_already_running", + "error_message" => "job already running, cannot restart" + }} + end + + describe "received state" do + before { job.update_attribute(:state, "received") } + before { post("/v3/job/#{job.id}/restart", params, headers) } + + example { expect(last_response.status).to be == 409 } + example { expect(JSON.load(body)).to be == { + "@type" => "error", + "error_type" => "job_already_running", + "error_message" => "job already running, cannot restart" + }} + end + end + # TODO decided to discuss further with rkh as this use case doesn't really exist at the moment # and 'fixing' the query requires modifying workers that v2 uses, thereby running the risk of breaking v2, # and also because in 6 months or so travis-hub will be able to cancel builds without using travis-core at all.