rocketjob_mission_control 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +26 -0
- data/app/assets/javascripts/rocket_job_mission_control/application.js +18 -0
- data/app/assets/javascripts/rocket_job_mission_control/base.js.coffee +24 -0
- data/app/assets/javascripts/rocket_job_mission_control/jobs.js.coffee +11 -0
- data/app/assets/stylesheets/rocket_job_mission_control/application.scss +18 -0
- data/app/assets/stylesheets/rocket_job_mission_control/base.scss +468 -0
- data/app/assets/stylesheets/rocket_job_mission_control/bootstrap_and_overrides.scss +6 -0
- data/app/assets/stylesheets/rocket_job_mission_control/callout.scss +40 -0
- data/app/assets/stylesheets/rocket_job_mission_control/jobs.scss +16 -0
- data/app/assets/stylesheets/rocket_job_mission_control/jquery.bootstrap-touchspin.scss +45 -0
- data/app/controllers/rocket_job_mission_control/application_controller.rb +15 -0
- data/app/controllers/rocket_job_mission_control/jobs/inputs_controller.rb +9 -0
- data/app/controllers/rocket_job_mission_control/jobs/slices_controller.rb +10 -0
- data/app/controllers/rocket_job_mission_control/jobs_controller.rb +97 -0
- data/app/controllers/rocket_job_mission_control/workers_controller.rb +79 -0
- data/app/helpers/rocket_job_mission_control/application_helper.rb +16 -0
- data/app/helpers/rocket_job_mission_control/jobs_helper.rb +57 -0
- data/app/helpers/rocket_job_mission_control/workers_helper.rb +14 -0
- data/app/views/layouts/rocket_job_mission_control/application.html.haml +43 -0
- data/app/views/layouts/rocket_job_mission_control/partials/_header.html.haml +16 -0
- data/app/views/layouts/rocket_job_mission_control/partials/_sidebar.html.haml +20 -0
- data/app/views/rocket_job_mission_control/jobs/_list.html.haml +33 -0
- data/app/views/rocket_job_mission_control/jobs/_status.html.haml +39 -0
- data/app/views/rocket_job_mission_control/jobs/index.html.haml +8 -0
- data/app/views/rocket_job_mission_control/jobs/running.html.haml +37 -0
- data/app/views/rocket_job_mission_control/jobs/show.html.haml +50 -0
- data/app/views/rocket_job_mission_control/workers/_actions.html.haml +9 -0
- data/app/views/rocket_job_mission_control/workers/index.html.haml +51 -0
- data/config/locales/en.yml +57 -0
- data/config/routes.rb +28 -0
- data/lib/rocket_job_mission_control/engine.rb +15 -0
- data/lib/rocket_job_mission_control/version.rb +3 -0
- data/lib/rocketjob_mission_control.rb +4 -0
- data/lib/tasks/rocket_job_mission_control_tasks.rake +4 -0
- data/spec/controllers/application_controller_spec.rb +47 -0
- data/spec/controllers/jobs_controller_spec.rb +217 -0
- data/spec/controllers/workers_controller_spec.rb +125 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +25 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +34 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/log/test.log +2459 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/helpers/jobs_helper_spec.rb +100 -0
- data/spec/rails_helper.rb +47 -0
- data/spec/spec_helper.rb +81 -0
- data/spec/views/workers/index.html.haml_spec.rb +17 -0
- data/vendor/assets/javascripts/jquery.bootstrap-touchspin.js +686 -0
- data/vendor/assets/javascripts/prism.js +6 -0
- data/vendor/assets/stylesheets/jquery.bootstrap-touchspin.css +45 -0
- data/vendor/assets/stylesheets/prism.scss +160 -0
- metadata +319 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
#header
|
2
|
+
%a#menu-toggle.btn.btn-default.btn-blank.first{href: ""}
|
3
|
+
%i.fa.fa-bars
|
4
|
+
Menu
|
5
|
+
|
6
|
+
= link_to main_app.root_path, class: 'btn btn-default btn-blank last' do
|
7
|
+
%i.fa.fa-reply
|
8
|
+
Back Home
|
9
|
+
|
10
|
+
.clearfix
|
11
|
+
|
12
|
+
.brand
|
13
|
+
= link_to root_path, class: 'text-center' do
|
14
|
+
%i.fa.fa-rocket
|
15
|
+
rocket
|
16
|
+
.color job
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#sidebar-wrapper
|
2
|
+
%ul.sidebar-nav
|
3
|
+
%li.sidebar-brand
|
4
|
+
%a#menu-close.menu-close
|
5
|
+
%i.fa.fa-times
|
6
|
+
|
7
|
+
.clearfix
|
8
|
+
|
9
|
+
%li
|
10
|
+
= link_to jobs_path, class: active_page(jobs_path) do
|
11
|
+
%i.fa.fa-home
|
12
|
+
Jobs
|
13
|
+
%li
|
14
|
+
= link_to workers_path, class: active_page(workers_path) do
|
15
|
+
%i.fa.fa-database
|
16
|
+
Workers
|
17
|
+
%li
|
18
|
+
= link_to running_jobs_path, class: active_page(running_jobs_path) do
|
19
|
+
%i.fa.fa-circle-o-notch
|
20
|
+
Running
|
@@ -0,0 +1,33 @@
|
|
1
|
+
.col-md-4.job-list
|
2
|
+
.filter.btn-group.btn-group-justified{ style: 'padding: 1px 1px 1px 1px;', data: { toggle: 'buttons' } }
|
3
|
+
- %w( queued running failed completed ).each do |state|
|
4
|
+
%label.btn.btn-default.state-toggle{ class: ('active' if @states.include?(state.to_s) || @states.empty?), title: state.capitalize}
|
5
|
+
= check_box_tag(state, state, (@states.include?(state.to_s) || @states.empty?))
|
6
|
+
%i.fa{class: job_state_icon(state.to_sym)}
|
7
|
+
.clearfix
|
8
|
+
.list
|
9
|
+
- if jobs.empty?
|
10
|
+
.card.inner
|
11
|
+
.title
|
12
|
+
.lead.text-center No Jobs Found.
|
13
|
+
- else
|
14
|
+
- jobs.each do |job|
|
15
|
+
= link_to job_path(id: job.id, states: @states), class: job_card_class(job) do
|
16
|
+
.inner
|
17
|
+
.title
|
18
|
+
.lead{class: job_selected_class(job, @job)}
|
19
|
+
%i.fa{class: job_state_icon(job.state), style: 'font-size: 75%;', title: job.state}
|
20
|
+
= job_title(job)
|
21
|
+
|
22
|
+
.description= job.description.try(:truncate, 50)
|
23
|
+
.info
|
24
|
+
.duration.pull-left
|
25
|
+
- if job.failed?
|
26
|
+
%i.fa.fa-bomb
|
27
|
+
failed
|
28
|
+
- else
|
29
|
+
%i.fa.fa-clock-o
|
30
|
+
= job.duration
|
31
|
+
- if job.running?
|
32
|
+
.progress.pull-right
|
33
|
+
.progress-bar{ style: "width: #{job.percent_complete}%;", title: "#{job.percent_complete}% percent complete."}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
- status = job.status(Time.zone)
|
2
|
+
.id
|
3
|
+
%label ID:
|
4
|
+
= status.delete('id')
|
5
|
+
.status-message
|
6
|
+
%label Description:
|
7
|
+
= status.delete('description')
|
8
|
+
.status-message
|
9
|
+
%label Duration:
|
10
|
+
= status.delete('duration')
|
11
|
+
.status-message
|
12
|
+
%label Record Count:
|
13
|
+
= status.delete('record_count')
|
14
|
+
.created_at
|
15
|
+
%label Created At:
|
16
|
+
= status.delete('created_at')
|
17
|
+
.status-message
|
18
|
+
%label Started At:
|
19
|
+
= status.delete('started_at')
|
20
|
+
.status-message
|
21
|
+
%label % Complete:
|
22
|
+
= status.delete('percent_complete')
|
23
|
+
|
24
|
+
- remaining = {}
|
25
|
+
- status.each_pair do |key, value|
|
26
|
+
.status-message
|
27
|
+
- if ['state', '_type'].include?(key)
|
28
|
+
- elsif value.kind_of?(Hash) || value.kind_of?(Array)
|
29
|
+
- remaining[key] = value
|
30
|
+
- else
|
31
|
+
%label= "#{key.to_s.titleize}:"
|
32
|
+
= value
|
33
|
+
.clearfix
|
34
|
+
|
35
|
+
- remaining.each_pair do |key, value|
|
36
|
+
.status-message
|
37
|
+
%label= "#{key.to_s.titleize}:"
|
38
|
+
%pre
|
39
|
+
%code= pretty_print_array_or_hash(value)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
.col-md-10.col-md-offset-1
|
2
|
+
.jumbotron
|
3
|
+
%h3 There are currently #{@jobs.count} jobs running.
|
4
|
+
#accordion.panel-group
|
5
|
+
- @jobs.each do |job|
|
6
|
+
.panel.panel-default
|
7
|
+
.panel-heading
|
8
|
+
%h4.panel-title
|
9
|
+
%a.collapsed{href: "##{job.id}", data: {toggle: 'collapse', parent: '#accordion'} }
|
10
|
+
%i.fa.fa-plus-square-o{ style: 'font-size: 80%;'}
|
11
|
+
= job_title(job)
|
12
|
+
.panel-collapse.collapse{ id: job.id }
|
13
|
+
.panel-body
|
14
|
+
.info
|
15
|
+
.progress
|
16
|
+
.progress-bar{ style: "width: #{job.percent_complete}%; min-width: 1em;", title: "#{job.percent_complete}% percent complete."}
|
17
|
+
- if job.kind_of?(RocketJob::SlicedJob)
|
18
|
+
.slice_count
|
19
|
+
%label Slices Running:
|
20
|
+
= job.input.find_all { |s| s.state == :running }.count
|
21
|
+
- else
|
22
|
+
.worker
|
23
|
+
%label Worker:
|
24
|
+
= job.worker_name
|
25
|
+
|
26
|
+
= render partial: 'status', locals: { job: job }
|
27
|
+
- if job.kind_of?(RocketJob::SlicedJob)
|
28
|
+
%table.table
|
29
|
+
%tr
|
30
|
+
%th worker
|
31
|
+
%th parameters
|
32
|
+
- job.input.each('state' => 'running') do |slice|
|
33
|
+
%tr
|
34
|
+
%td= slice.worker_name
|
35
|
+
%td
|
36
|
+
%pre
|
37
|
+
%code= pretty_print_array_or_hash(slice.to_a)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#queue
|
2
|
+
= render partial: 'list', locals: { jobs: @jobs }
|
3
|
+
|
4
|
+
.col-md-8.job-status
|
5
|
+
#job
|
6
|
+
.lead= job_title(@job)
|
7
|
+
|
8
|
+
.job-state.inline-block
|
9
|
+
.left state
|
10
|
+
.right{ class: job_class(@job) }
|
11
|
+
= @job.state
|
12
|
+
|
13
|
+
.priority.pull-right
|
14
|
+
= form_for(@job, as: :job, url: job_path(@job), html: {method: :patch}) do |f|
|
15
|
+
|
16
|
+
.input-group.spinner{ "data-id" => @job.id }
|
17
|
+
= f.text_field(:priority, class: 'form-control')
|
18
|
+
|
19
|
+
.input-group-btn-vertical
|
20
|
+
%button#increase_priority.btn.btn-default.up{ type: 'button' }
|
21
|
+
%i.fa.fa-caret-up
|
22
|
+
|
23
|
+
%button#decrease_priority.btn.btn-default.down{ type: 'button' }
|
24
|
+
%i.fa.fa-caret-down
|
25
|
+
|
26
|
+
= submit_tag "set", class: "btn btn-sm btn-primary priority-set"
|
27
|
+
|
28
|
+
.job-retry.btn-group.pull-right{ style: 'margin-right: 1em;' }
|
29
|
+
- valid_events = @job.aasm.events.collect{ |e| e.name }
|
30
|
+
- if valid_events.include?(:abort)
|
31
|
+
= link_to "abort", abort_job_path(@job), method: :patch, class: 'btn btn-default'
|
32
|
+
|
33
|
+
- if @job.completed? || @job.aborted?
|
34
|
+
= link_to "destroy", job_path(@job), method: :delete, class: 'btn btn-default'
|
35
|
+
|
36
|
+
- if valid_events.include?(:fail)
|
37
|
+
= link_to "fail", fail_job_path(@job), method: :patch, class: 'btn btn-default'
|
38
|
+
|
39
|
+
- if valid_events.include?(:pause)
|
40
|
+
= link_to "pause", pause_job_path(@job), method: :patch, class: 'btn btn-default'
|
41
|
+
|
42
|
+
- if valid_events.include?(:resume)
|
43
|
+
= link_to "resume", resume_job_path(@job), method: :patch, class: 'btn btn-default'
|
44
|
+
|
45
|
+
- if valid_events.include?(:retry)
|
46
|
+
= link_to "retry", retry_job_path(@job), method: :patch, class: 'btn btn-default'
|
47
|
+
|
48
|
+
.clearfix
|
49
|
+
|
50
|
+
= render partial: 'status', locals: { job: @job }
|
@@ -0,0 +1,9 @@
|
|
1
|
+
- if worker.stopping?
|
2
|
+
%p Worker is stopping...
|
3
|
+
= link_to "destroy", worker_path(worker), method: :delete, class: 'btn btn-danger'
|
4
|
+
-else
|
5
|
+
= link_to "stop", stop_worker_path(worker), method: :patch, class: 'btn btn-danger'
|
6
|
+
- if worker.paused?
|
7
|
+
= link_to "resume", resume_worker_path(worker), method: :patch, class: 'btn btn-default'
|
8
|
+
- else
|
9
|
+
= link_to "pause", pause_worker_path(worker), method: :patch, class: 'btn btn-default'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#workers
|
2
|
+
- if @workers.present?
|
3
|
+
.col-lg-1
|
4
|
+
.dropdown
|
5
|
+
%button.btn.btn-primary.dropdown-toggle{ data: {toggle: 'dropdown'} }
|
6
|
+
Actions
|
7
|
+
%span.caret
|
8
|
+
%ul.dropdown-menu
|
9
|
+
%li= link_to("Stop All", update_all_workers_path(worker_action: :stop), method: :patch)
|
10
|
+
%li= link_to("Pause All", update_all_workers_path(worker_action: :pause), method: :patch)
|
11
|
+
%li= link_to("Resume All", update_all_workers_path(worker_action: :resume), method: :patch)
|
12
|
+
|
13
|
+
.grid
|
14
|
+
- @workers.each do |worker|
|
15
|
+
.card.col-xs-12.col-sm-6.col-md-3.col-lg-3
|
16
|
+
.inner.callout-top{ class: worker_card_class(worker) }
|
17
|
+
.icon
|
18
|
+
%i.fa.fa-database
|
19
|
+
|
20
|
+
.title
|
21
|
+
%h3
|
22
|
+
= worker.name
|
23
|
+
|
24
|
+
.state
|
25
|
+
%b State:
|
26
|
+
= worker.state
|
27
|
+
|
28
|
+
.threads.max_threads
|
29
|
+
%b Max Threads:
|
30
|
+
= worker.max_threads
|
31
|
+
|
32
|
+
.threads.current_threads
|
33
|
+
%b Current Threads:
|
34
|
+
= worker.heartbeat.current_threads.present? ? worker.heartbeat.current_threads : 0
|
35
|
+
|
36
|
+
.time
|
37
|
+
%b Started:
|
38
|
+
= worker.started_at.strftime("%b, %d %Y at %l:%M %p")
|
39
|
+
|
40
|
+
.actions
|
41
|
+
= render partial: 'actions', locals: { worker: worker }
|
42
|
+
|
43
|
+
- else
|
44
|
+
.no-workers
|
45
|
+
There are currently no workers.
|
46
|
+
%br
|
47
|
+
You can start a worker with the following command:
|
48
|
+
|
49
|
+
.code-block.col-md-6.col-md-offset-3
|
50
|
+
%pre
|
51
|
+
%code.language-bash bin/rocketjob
|
@@ -0,0 +1,57 @@
|
|
1
|
+
en:
|
2
|
+
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
3
|
+
datetime:
|
4
|
+
distance_in_words:
|
5
|
+
half_a_minute: "half a minute"
|
6
|
+
less_than_x_seconds:
|
7
|
+
one: "1 second" # default was: "less than 1 second"
|
8
|
+
other: "%{count} seconds" # default was: "less than %{count} seconds"
|
9
|
+
x_seconds:
|
10
|
+
one: "1 second"
|
11
|
+
other: "%{count} seconds"
|
12
|
+
less_than_x_minutes:
|
13
|
+
one: "a minute" # default was: "less than a minute"
|
14
|
+
other: "%{count} minutes" # default was: "less than %{count} minutes"
|
15
|
+
x_minutes:
|
16
|
+
one: "1 minute"
|
17
|
+
other: "%{count} minutes"
|
18
|
+
about_x_hours:
|
19
|
+
one: "1 hour" # default was: "about 1 hour"
|
20
|
+
other: "%{count} hours" # default was: "about %{count} hours"
|
21
|
+
x_days:
|
22
|
+
one: "1 day"
|
23
|
+
other: "%{count} days"
|
24
|
+
about_x_months:
|
25
|
+
one: "1 month" # default was: "about 1 month"
|
26
|
+
other: "%{count} months" # default was: "about %{count} months"
|
27
|
+
x_months:
|
28
|
+
one: "1 month"
|
29
|
+
other: "%{count} months"
|
30
|
+
about_x_years:
|
31
|
+
one: "1 year" # default was: "about 1 year"
|
32
|
+
other: "%{count} years" # default was: "about %{count} years"
|
33
|
+
over_x_years:
|
34
|
+
one: "1 year" # default was: "over 1 year"
|
35
|
+
other: "%{count} years" # default was: "over %{count} years"
|
36
|
+
almost_x_years:
|
37
|
+
one: "1 year" # default was: "almost 1 year"
|
38
|
+
other: "%{count} years" # default was: "almost %{count} years"
|
39
|
+
worker:
|
40
|
+
stop:
|
41
|
+
success: "Worker successfully stopped."
|
42
|
+
failure: "Error attempting to stop worker."
|
43
|
+
destroy:
|
44
|
+
success: "Worker successfully destroyed."
|
45
|
+
failure: "Error attempting to destroy worker."
|
46
|
+
pause:
|
47
|
+
success: "Worker successfully paused."
|
48
|
+
failure: "Error attempting to pause worker."
|
49
|
+
resume:
|
50
|
+
success: "Worker successfully resumed."
|
51
|
+
failure: "Error attempting to resume worker."
|
52
|
+
update_all:
|
53
|
+
success: "Workers have been %{worker_action}."
|
54
|
+
invalid: "Action not allowed."
|
55
|
+
job:
|
56
|
+
find:
|
57
|
+
:failure: "Could not find job with id: %{id}!"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
RocketJobMissionControl::Engine.routes.draw do
|
2
|
+
|
3
|
+
resources :jobs, only: [:index, :show, :update, :destroy] do
|
4
|
+
member do
|
5
|
+
patch :abort
|
6
|
+
patch :fail
|
7
|
+
patch :pause
|
8
|
+
patch :resume
|
9
|
+
patch :retry
|
10
|
+
end
|
11
|
+
collection do
|
12
|
+
get :running
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
resources :workers, only: [:index, :destroy] do
|
17
|
+
member do
|
18
|
+
patch :stop
|
19
|
+
patch :pause
|
20
|
+
patch :resume
|
21
|
+
end
|
22
|
+
collection do
|
23
|
+
patch :update_all
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
root to: "jobs#index"
|
28
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace RocketJobMissionControl
|
4
|
+
|
5
|
+
require 'rocketjob'
|
6
|
+
require 'jquery-rails'
|
7
|
+
require 'haml'
|
8
|
+
require 'mongo'
|
9
|
+
require 'mongo_mapper'
|
10
|
+
require 'mongo_ha'
|
11
|
+
require 'bootstrap-sass'
|
12
|
+
require 'sass-rails'
|
13
|
+
require 'coffee-rails'
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
module RocketJobMissionControl
|
4
|
+
RSpec.describe ApplicationController, type: :controller do
|
5
|
+
controller do
|
6
|
+
def index
|
7
|
+
@time_zone = Time.zone
|
8
|
+
|
9
|
+
render text: 'Time Zoned'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#with_time_zone" do
|
14
|
+
let(:session_params) { {} }
|
15
|
+
let(:expected_time_zone) { 'UTC' }
|
16
|
+
|
17
|
+
before do
|
18
|
+
get :index, {}, session_params
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with a session present" do
|
22
|
+
context "that contains a time zone" do
|
23
|
+
let(:expected_time_zone) { 'America/Los_Angeles' }
|
24
|
+
let(:session_params) { {'time_zone' => expected_time_zone} }
|
25
|
+
|
26
|
+
it "sets the time zone correctly" do
|
27
|
+
expect(assigns(:time_zone).name).to eq(expected_time_zone)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'that does not contain a time zone' do
|
32
|
+
let(:session_params) { { 'user_id' => '42' } }
|
33
|
+
|
34
|
+
it 'sets the time zone correctly' do
|
35
|
+
expect(assigns(:time_zone).name).to eq(expected_time_zone)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with no session present" do
|
41
|
+
it "sets the time zone correctly" do
|
42
|
+
expect(assigns(:time_zone).name).to eq(expected_time_zone)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
module RocketJobMissionControl
|
4
|
+
RSpec.shared_examples "a jobs update controller" do
|
5
|
+
describe "with an invalid job id" do
|
6
|
+
before do
|
7
|
+
allow(RocketJob::Job).to receive(:find).and_return(nil)
|
8
|
+
do_action
|
9
|
+
end
|
10
|
+
|
11
|
+
it "redirects" do
|
12
|
+
expect(response).to redirect_to(jobs_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "adds a flash alert message" do
|
16
|
+
expect(flash[:alert]).to eq(I18n.t(:failure, scope: [:job, :find], id: 42))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec.describe JobsController do
|
22
|
+
routes { Engine.routes }
|
23
|
+
|
24
|
+
[:pause, :resume, :abort, :retry, :fail].each do |state|
|
25
|
+
describe "PATCH ##{state}" do
|
26
|
+
it_behaves_like "a jobs update controller" do
|
27
|
+
let(:do_action) { patch state, id: 42, job: {id: 42, priority: 12} }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "with a valid job id" do
|
31
|
+
let(:job) { spy(id: 42, to_param: 42) }
|
32
|
+
|
33
|
+
before do
|
34
|
+
allow(RocketJob::Job).to receive(:find).and_return(job)
|
35
|
+
patch state, id: 42, job: {id: 42, priority: 12}
|
36
|
+
end
|
37
|
+
|
38
|
+
it "redirects to the job" do
|
39
|
+
expect(response).to redirect_to(job_path(42))
|
40
|
+
end
|
41
|
+
|
42
|
+
it "transitions the job" do
|
43
|
+
expect(job).to have_received("#{state}!".to_sym)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "PATCH #update" do
|
50
|
+
it_behaves_like "a jobs update controller" do
|
51
|
+
let(:do_action) { patch :update, id: 42, job: {id: 42, priority: 12} }
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "with a valid job id" do
|
55
|
+
let(:job) { spy(id: 42, to_param: 42) }
|
56
|
+
|
57
|
+
before do
|
58
|
+
allow(RocketJob::Job).to receive(:find).and_return(job)
|
59
|
+
patch :update, id: 42, job: {id: 42, priority: 12}
|
60
|
+
end
|
61
|
+
|
62
|
+
it "redirects to the job" do
|
63
|
+
expect(response).to redirect_to(job_path(42))
|
64
|
+
end
|
65
|
+
|
66
|
+
it "updates the job correctly" do
|
67
|
+
expect(job).to have_received(:update_attributes!).with('priority' => '12')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "GET #show" do
|
73
|
+
let(:result) { spy(sort: []) }
|
74
|
+
|
75
|
+
before do
|
76
|
+
allow(RocketJob::Job).to receive(:limit).and_return(result)
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "with an invalid job id" do
|
80
|
+
before do
|
81
|
+
allow(RocketJob::Job).to receive(:find).and_return(nil)
|
82
|
+
get :show, id: 42
|
83
|
+
end
|
84
|
+
|
85
|
+
it "redirects" do
|
86
|
+
expect(response).to redirect_to(jobs_path)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "adds a flash alert message" do
|
90
|
+
expect(flash[:alert]).to eq(I18n.t(:failure, scope: [:job, :find], id: 42))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "with a valid job id" do
|
95
|
+
before do
|
96
|
+
allow(RocketJob::Job).to receive(:find).and_return('job')
|
97
|
+
get :show, id: 42
|
98
|
+
end
|
99
|
+
|
100
|
+
it "succeeds" do
|
101
|
+
expect(response.status).to be(200)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "assigns the job" do
|
105
|
+
expect(assigns(:job)).to be_present
|
106
|
+
end
|
107
|
+
|
108
|
+
it "assigns the jobs" do
|
109
|
+
expect(assigns(:jobs)).to eq([])
|
110
|
+
end
|
111
|
+
|
112
|
+
it "grabs a sorted list of rocket jobs" do
|
113
|
+
expect(result).to have_received(:sort).with(created_at: :desc)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "GET #running" do
|
119
|
+
before do
|
120
|
+
allow(RocketJob::Job).to receive(:where).and_return([])
|
121
|
+
get :running
|
122
|
+
end
|
123
|
+
|
124
|
+
it { expect(response.status).to be(200) }
|
125
|
+
|
126
|
+
it "queries for running jobs" do
|
127
|
+
expect(RocketJob::Job).to have_received(:where).with(state: 'running')
|
128
|
+
end
|
129
|
+
|
130
|
+
it "returns expected jobs" do
|
131
|
+
expect(assigns[:jobs]).to eq([])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "GET #index" do
|
136
|
+
describe "with no jobs" do
|
137
|
+
let(:result) { spy(sort: []) }
|
138
|
+
|
139
|
+
before do
|
140
|
+
allow(RocketJob::Job).to receive(:limit).and_return(result)
|
141
|
+
get :index
|
142
|
+
end
|
143
|
+
|
144
|
+
it "succeeds" do
|
145
|
+
expect(response.status).to be(200)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "grabs a sorted list of rocket jobs" do
|
149
|
+
expect(result).to have_received(:sort).with(created_at: :desc)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "returns no jobs" do
|
153
|
+
expect(assigns(:jobs)).to eq([])
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "with jobs" do
|
158
|
+
let(:result) { spy(sort: jobs) }
|
159
|
+
let(:jobs) { ['fake_job1', 'fake_job2'] }
|
160
|
+
|
161
|
+
before do
|
162
|
+
allow(RocketJob::Job).to receive(:limit).and_return(result)
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "with no parameters" do
|
166
|
+
before { get :index }
|
167
|
+
|
168
|
+
it "succeeds" do
|
169
|
+
expect(response.status).to be(200)
|
170
|
+
end
|
171
|
+
|
172
|
+
it "grabs a sorted list of rocket jobs" do
|
173
|
+
expect(result).to have_received(:sort).with(created_at: :desc)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "returns the jobs" do
|
177
|
+
expect(assigns(:jobs)).to match_array(jobs)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "with a state filter" do
|
182
|
+
before { get :index, states: states}
|
183
|
+
|
184
|
+
context "that is empty" do
|
185
|
+
let(:states) { [] }
|
186
|
+
|
187
|
+
it { expect(response.status).to be(200) }
|
188
|
+
|
189
|
+
it "grabs a sorted list of rocket jobs" do
|
190
|
+
expect(result).to have_received(:sort).with(created_at: :desc)
|
191
|
+
end
|
192
|
+
|
193
|
+
it "returns the jobs" do
|
194
|
+
expect(assigns(:jobs)).to match_array(jobs)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context "with a state" do
|
199
|
+
let(:query_spy) { spy(where: jobs) }
|
200
|
+
let(:result) { spy(sort: query_spy) }
|
201
|
+
let(:states) { ['completed', 'running'] }
|
202
|
+
|
203
|
+
it { expect(response.status).to be(200) }
|
204
|
+
|
205
|
+
it "grabs a filtered list of rocket jobs" do
|
206
|
+
expect(query_spy).to have_received(:where).with(state: states)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "returns the jobs" do
|
210
|
+
expect(assigns(:jobs)).to match_array(jobs)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|