resque-scheduler-web 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/app/controllers/resque_web/plugins/resque_scheduler/delayed_controller.rb +25 -3
  4. data/app/views/resque_web/plugins/resque_scheduler/delayed/_search_form.erb +1 -1
  5. data/app/views/resque_web/plugins/resque_scheduler/delayed/index.erb +46 -41
  6. data/app/views/resque_web/plugins/resque_scheduler/delayed/jobs_klass.erb +5 -4
  7. data/app/views/resque_web/plugins/resque_scheduler/delayed/search.erb +1 -1
  8. data/lib/resque/scheduler/web/version.rb +1 -1
  9. data/spec/dummy/config/application.rb +2 -0
  10. data/spec/features/delayed/cancel_delayed_job_spec.rb +28 -0
  11. data/spec/features/delayed/clear_all_jobs_spec.rb +24 -0
  12. data/spec/features/delayed/delayed_jobs_index_page_spec.rb +10 -15
  13. data/spec/features/delayed/delayed_jobs_timestamp_page_spec.rb +40 -13
  14. data/spec/features/delayed/see_all_timestamps_for_a_class_spec.rb +55 -0
  15. data/spec/features/delayed/send_a_delayed_job_to_the_queue_spec.rb +29 -0
  16. data/spec/features/navigation_spec.rb +23 -2
  17. data/spec/features/schedules/cannot_delete_a_job_when_the_schedule_is_static.rb +14 -10
  18. data/spec/features/schedules/delete_a_job_from_the_dynamic_schedule_spec.rb +42 -31
  19. data/spec/features/schedules/requeuing_a_job_with_parameters_spec.rb +32 -16
  20. data/spec/features/schedules/requeuing_a_job_without_parameters_spec.rb +26 -22
  21. data/spec/features/schedules/scheduled_jobs_index_page_spec.rb +35 -24
  22. data/spec/spec_helper.rb +1 -0
  23. data/spec/support/shared_steps.rb +47 -0
  24. data/spec/support/test_jobs.rb +14 -0
  25. metadata +13 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cdaf732772b3cf1c129b8394190a3e3e2d991d01
4
- data.tar.gz: 932897408224f2238e1a5323c415fc26f08164b4
3
+ metadata.gz: 0e0d9ae424811136f0f35b1c596f174b5e452d56
4
+ data.tar.gz: 558a1cc70f5fb9262acc90eae0977f6e15917f88
5
5
  SHA512:
6
- metadata.gz: 9c9d83155665494ef45db59edb1ae4e61b3017ca46a17620f4ba748ec577d5c2088f944de2b3154dd27a60fc73d79a18ea6abfbbd1b3101f06a935b201b4ea6d
7
- data.tar.gz: 2cda060442328d84b6ffe8b01687bc665811e69ff0713fadf295160e889a3bd1913ecc089696828ff3778f2804b4ce3d2a8db63b10245990169c07ecb0243531
6
+ metadata.gz: 4a179c41dd6f5c3a9f8366e00adf05956006adcf0b1d9be60587b61607bf4c9da9deb435362d0903fb1ebf52c976003799b8b07f4ddd9ec9cc14ba523ce8ed80
7
+ data.tar.gz: 1a064fb3d53f6a127e95001a2284f165920a627b8b9d2d91ce69366afaa8030a252b8060e5d14e8f7b32eef300b99af7f8703f839c9a407dcf65c2ed10904fe1
data/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ ## 0.0.4
4
+ * More Rspec feature specs. All main functionality is now covered with
5
+ integration tests.
6
+ * Timestamps page for a job now correctly shows timestamps for jobs which
7
+ inherit from `ActiveJob::Base`.
8
+ * Timestamps page for a job shows timestamps as links.
9
+ * Some layout and styling improvements.
10
+
11
+ ## 0.0.3
12
+ * Fixed timestamps page.
13
+ * Added Rspec features to cover more functionality that was previously untested.
14
+
15
+ ## 0.0.2
16
+ * Add documentation for methods and classes.
17
+ * Clean up lots of Rubocop issues with the code style.
18
+ * Set up Travis CI.
19
+ * Add various badges to the README.
20
+ * Add runtime dependencies to prevent a bug with earlier versions of
21
+ resque-scheduler, which defined `Resque::Scheduler` as a class, rather than a
22
+ module.
23
+
24
+ ## 0.0.1
25
+ * Code ported over from the main resque-scheduler gem, extracted from the
26
+ Sinatra interface, and put into a rails engine.
27
+ * Test suite converted to use Rspec.
@@ -14,13 +14,32 @@ module ResqueWeb
14
14
  end
15
15
 
16
16
  # GET /delayed/jobs/:klass
17
- # Shows us all of the jobs of this type, with these args. Accessed by
17
+ # Shows us all of the timestamps where jobs of this type, with these
18
+ # args are currently scheduled as delayed jobs. Accessed by
18
19
  # clicking the 'All schedules' link next to a delayed job.
19
20
  def jobs_klass
20
21
  klass = Resque::Scheduler::Util.constantize(params[:klass])
21
- @args = JSON.load(URI.decode(params[:args]))
22
- @timestamps = Resque.scheduled_at(klass, *@args)
22
+ @args = params[:args] ? JSON.load(URI.decode(params[:args])) : []
23
+
24
+ # ActiveJob hack. The wrapper class does not know what queue the
25
+ # wrapped class wants to use, so we need to tell Resque Scheduler
26
+ # the queue, rather than have it use Resque's internal guessing
27
+ # mechanism.
28
+ if klass.to_s == 'ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper'
29
+ queue_name = @args.first['queue_name']
30
+ hashed_job = Resque.send :job_to_hash_with_queue, queue_name, klass, @args
31
+ search = Resque.send :encode, hashed_job
32
+ @timestamps = Resque.instance_eval do
33
+ redis.smembers("timestamps:#{search}").map do |key|
34
+ key.tr('delayed:', '').to_i
35
+ end
36
+ end
37
+ else
38
+ @timestamps = Resque.scheduled_at(klass, *@args)
39
+ end
23
40
  rescue
41
+ # Should this be a rescue? Seems to cover the case of the params
42
+ # not validating or something.
24
43
  @timestamps = []
25
44
  end
26
45
 
@@ -30,6 +49,7 @@ module ResqueWeb
30
49
  end
31
50
 
32
51
  # POST /delayed/cancel_now
52
+ # cancels a specific job based on klass, timestamp and args.
33
53
  def cancel_now
34
54
  klass = Resque::Scheduler::Util.constantize(params['klass'])
35
55
  timestamp = params['timestamp']
@@ -45,6 +65,8 @@ module ResqueWeb
45
65
  end
46
66
 
47
67
  # POST /delayed/queue_now
68
+ # Sends ALL of the delayed jobs at a particular timestamp to the queue,
69
+ # regardless of their details.
48
70
  def queue_now
49
71
  timestamp = params['timestamp'].to_i
50
72
  if timestamp > 0
@@ -1,6 +1,6 @@
1
1
  <form method="POST" action="<%= delayed_search_path %>">
2
2
  <input type='input' name='search' value="<%= params[:search] %>"/>
3
- <input type='submit' value='Search'/>
3
+ <input type='submit' value='Search' class="btn btn-default"/>
4
4
  </form>
5
5
 
6
6
 
@@ -7,53 +7,58 @@
7
7
  Server local time: <%= Time.now %>
8
8
  </p>
9
9
 
10
- <p class='sub'>
11
- <% finish = [@start + @number_to_show, @total_number_of_delayed_jobs].min %>
12
- Showing <%= @start %> to <%= finish %> of
13
- <b><%= @total_number_of_delayed_jobs %></b> timestamps
14
- </p>
10
+ <% if @timestamps.any? %>
11
+
12
+ <p class='sub'>
13
+ <% finish = [@start + @number_to_show, @total_number_of_delayed_jobs].min %>
14
+ Showing <%= @start %> to <%= finish %> of
15
+ <b><%= @total_number_of_delayed_jobs %></b> timestamps
16
+ </p>
15
17
 
16
- <table class="table table-bordered">
17
- <tr>
18
- <th></th>
19
- <th>Timestamp</th>
20
- <th>Job count</th>
21
- <th>Class</th>
22
- <th>Args</th>
23
- <th>All schedules</th>
24
- </tr>
25
- <% @timestamps.each do |timestamp| %>
26
- <tr class="delayed-job">
27
- <td>
28
- <form action="<%= queue_now_path %>" method="post">
29
- <input type="hidden" name="timestamp" value="<%= timestamp.to_i %>">
30
- <input type="submit" value="Queue now" class="btn btn-default">
31
- </form>
32
- </td>
33
- <td><a href="<%= delayed_path timestamp: timestamp %>"><%= format_time(Time.at(timestamp)) %></a></td>
34
- <td class="job-count"><%= delayed_timestamp_size = Resque.delayed_timestamp_size(timestamp) %></td>
35
- <% job = Resque.delayed_timestamp_peek(timestamp, 0, 1).first %>
36
- <td>
37
- <% if job && delayed_timestamp_size == 1 %>
38
- <%= h(job['class']) %>
39
- <% else %>
40
- <a href="<%= timestamp_path timestamp: timestamp %>">see details</a>
41
- <% end %>
42
- </td>
43
- <td><%= h(job['args'].inspect) if job && delayed_timestamp_size == 1 %></td>
44
- <td>
45
- <% if job %>
46
- <a href="<%= delayed_job_class_path klass: job['class'], args: URI.encode(job['args'].to_json) %>">All schedules</a>
47
- <% end %>
48
- </td>
18
+ <table class="table table-bordered">
19
+ <tr>
20
+ <th></th>
21
+ <th>Timestamp</th>
22
+ <th>Job count</th>
23
+ <th>Class</th>
24
+ <th>Args</th>
25
+ <th>All schedules</th>
49
26
  </tr>
50
- <% end %>
51
- </table>
27
+ <% @timestamps.each do |timestamp| %>
28
+ <tr class="delayed-job">
29
+ <td>
30
+ <form action="<%= queue_now_path %>" method="post">
31
+ <input type="hidden" name="timestamp" value="<%= timestamp.to_i %>">
32
+ <input type="submit" value="Queue now" class="btn btn-default">
33
+ </form>
34
+ </td>
35
+ <td class="timestamp-link"><a href="<%= timestamp_path timestamp: timestamp %>"><%= format_time(Time.at(timestamp)) %></a></td>
36
+ <td class="job-count"><%= delayed_timestamp_size = Resque.delayed_timestamp_size(timestamp) %></td>
37
+ <% job = Resque.delayed_timestamp_peek(timestamp, 0, 1).first %>
38
+ <td>
39
+ <% if job && delayed_timestamp_size == 1 %>
40
+ <%= h(job['class']) %>
41
+ <% else %>
42
+ <a href="<%= timestamp_path timestamp: timestamp %>">see details</a>
43
+ <% end %>
44
+ </td>
45
+ <td><%= h(job['args'].inspect) if job && delayed_timestamp_size == 1 %></td>
46
+ <td>
47
+ <% if job %>
48
+ <a href="<%= delayed_job_class_path klass: job['class'], args: URI.encode(job['args'].to_json) %>">All schedules</a>
49
+ <% end %>
50
+ </td>
51
+ </tr>
52
+ <% end %>
53
+ </table>
54
+ <% else %>
55
+ <h2>There are no delayed jobs</h2>
56
+ <% end %>
52
57
 
53
58
  <% if @total_number_of_delayed_jobs > 0 %>
54
59
  <br>
55
60
  <form method="POST" action="<%= clear_path %>" class='clear-delayed'>
56
- <input type='submit' name='' value='Clear Delayed Jobs' />
61
+ <input type='submit' name='' value='Clear All Delayed Jobs' class="btn btn-default"/>
57
62
  </form>
58
63
  <% end %>
59
64
 
@@ -1,14 +1,15 @@
1
- <h1>Delayed jobs scheduled for <%= params[:klass] %> (<%= @args %>)</h1>
1
+ <h1>Timestamps where delayed jobs are scheduled for class:<br> <%= params[:klass] %></h1>
2
+ <h2>With params: <%= @args %></h2>
2
3
 
3
- <table class='jobs'>
4
+ <table class='jobs table table-bordered'>
4
5
  <tr>
5
- <th>Timestamp</th>
6
+ <th><%= "Timestamp".pluralize(@timestamps.size) %></th>
6
7
  </tr>
7
8
 
8
9
  <% @timestamps.each do |t| %>
9
10
  <tr>
10
11
  <td>
11
- <%= Time.at(t) %>
12
+ <%= link_to Time.at(t), timestamp_path(timestamp: t.to_i), class: 'timestamp-link' %>
12
13
  </td>
13
14
  </tr>
14
15
  <% end %>
@@ -24,7 +24,7 @@
24
24
  <input type="hidden" name="timestamp" value="<%= job['timestamp'].to_i %>">
25
25
  <input type="hidden" name="klass" value="<%= job['class'] %>">
26
26
  <input type="hidden" name="args" value="<%= Resque.encode job['args'] %>">
27
- <input type="submit" value="Cancel Job">
27
+ <input type="submit" value="Cancel Job" class="btn btn-default">
28
28
  </form>
29
29
  </td>
30
30
  <td class='args'><%= format_time(Time.at(job['timestamp'])) %></td>
@@ -1,7 +1,7 @@
1
1
  module Resque
2
2
  module Scheduler
3
3
  module Web
4
- VERSION = '0.0.3'
4
+ VERSION = '0.0.4'
5
5
  end
6
6
  end
7
7
  end
@@ -28,5 +28,7 @@ module Dummy
28
28
 
29
29
  # Do not swallow errors in after_commit/after_rollback callbacks.
30
30
  config.active_record.raise_in_transactional_callbacks = true
31
+
32
+ config.active_job.queue_adapter = :resque
31
33
  end
32
34
  end
@@ -0,0 +1,28 @@
1
+ require 'rails_helper'
2
+
3
+ feature 'cancelling a delayed job' do
4
+
5
+ include SharedFunctionsForFeatures
6
+
7
+ scenario 'cancelling the job from the search page' do
8
+ given_there_is_a_delayed_job
9
+ when_i_search_for_the_delayed_job
10
+ and_i_cancel_the_job
11
+ then_i_should_be_on_the_delayed_jobs_page
12
+ and_the_job_should_not_be_present_on_the_page
13
+ end
14
+
15
+ def and_i_cancel_the_job
16
+ click_button 'Cancel'
17
+ end
18
+
19
+ def when_i_search_for_the_delayed_job
20
+ visit resque_scheduler_engine_routes.delayed_path
21
+ fill_in 'search', with: 'some'
22
+ click_button 'Search'
23
+ end
24
+
25
+ def and_the_job_should_not_be_present_on_the_page
26
+ expect(page).to_not have_content 'SomeIvarJob'
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ require 'rails_helper'
2
+
3
+ feature 'clearing all of the delayed jobs' do
4
+
5
+ include SharedFunctionsForFeatures
6
+
7
+ scenario 'clearing the jobs from the delayed index' do
8
+ given_there_are_two_delayed_jobs_enqueued_at_different_times
9
+ when_i_visit_the_delayed_jobs_page
10
+ and_i_click_the_clear_all_jobs_button
11
+ then_i_should_be_on_the_delayed_jobs_page
12
+ and_i_should_not_see_any_jobs_on_the_page
13
+ end
14
+
15
+ def and_i_should_not_see_any_jobs_on_the_page
16
+ expect(page).to_not have_content 'SomeIvarJob'
17
+ expect(page).to_not have_content 'JobWithoutParams'
18
+ end
19
+
20
+ def and_i_click_the_clear_all_jobs_button
21
+ click_button 'Clear All Delayed Jobs'
22
+ end
23
+
24
+ end
@@ -2,23 +2,18 @@ require 'rails_helper'
2
2
 
3
3
  feature 'seeing all the delayed jobs on the index page' do
4
4
 
5
- after do
6
- reset_the_resque_schedule
7
- end
8
-
9
- let(:some_time_in_the_future) { Time.now + 3600 }
10
- let(:some_other_time_in_the_future) { Time.now + 4600 }
5
+ include SharedFunctionsForFeatures
11
6
 
12
- # Given there is a delayed job
13
- # And another delayed job enqueued at a later time
14
- # When I visit the delayed jobs index page
15
- # Then I should see the job on the page
16
7
  scenario 'delayed jobs show up on the page when at different times' do
17
- Resque.enqueue_at(some_time_in_the_future, SomeIvarJob)
18
- Resque.enqueue_at(some_other_time_in_the_future, JobWithoutParams)
19
- visit resque_scheduler_engine_routes.delayed_path
8
+ given_there_are_two_delayed_jobs_enqueued_at_different_times
9
+ when_i_visit_the_delayed_jobs_page
10
+ then_i_should_see_the_details_of_both_jobs_on_the_page
11
+ end
12
+
13
+ def then_i_should_see_the_details_of_both_jobs_on_the_page
20
14
  expect(page).to have_content 'SomeIvarJob'
21
15
  expect(page).to have_content 'JobWithoutParams'
16
+ expect(page).to have_content some_time_in_the_future
17
+ expect(page).to have_content some_other_time_in_the_future
22
18
  end
23
-
24
- end
19
+ end
@@ -2,28 +2,55 @@ require 'rails_helper'
2
2
 
3
3
  feature 'seeing a summary of the delayed jobs for a timestamp on the index' do
4
4
 
5
- after do
6
- reset_the_resque_schedule
5
+ include SharedFunctionsForFeatures
6
+
7
+ scenario 'delayed jobs show up on the page when at the same times' do
8
+ given_there_are_two_delayed_jobs_enqueued_at_the_same_time
9
+ when_i_visit_the_delayed_jobs_page
10
+ then_i_should_see_the_delayed_jobs_on_the_page_as_summary
11
+ when_i_click_through_to_the_details_page
12
+ then_i_should_see_the_details_of_the_jobs
7
13
  end
8
14
 
9
- let(:some_time_in_the_future) { Time.now + 3600 }
10
- let(:some_other_time_in_the_future) { Time.now + 4600 }
15
+ scenario 'jobs on the delayed page all have a link to their timestamp page' do
16
+ given_there_is_a_delayed_job
17
+ when_i_visit_the_delayed_jobs_page
18
+ when_i_click_on_the_timestamp_next_to_the_job
19
+ then_i_should_be_on_the_timestamps_page
20
+ end
11
21
 
12
- # Given there is a delayed job
13
- # And another delayed job enqueued at the same time
14
- # When I visit the delayed jobs index page
15
- # Then I should see the jobs on the page as a summary
16
- # When I click through to the details page
17
- # Then I should see the details of the jobs
18
- scenario 'delayed jobs show up on the page when at the same times' do
19
- Resque.enqueue_at(some_time_in_the_future, JobWithParams, { argument: 'thingy' })
22
+ def then_i_should_be_on_the_timestamps_page
23
+ expected_path = resque_scheduler_engine_routes.timestamp_path(
24
+ timestamp: some_time_in_the_future.to_i
25
+ )
26
+ expect(current_path).to eq expected_path
27
+ end
28
+
29
+ def when_i_click_on_the_timestamp_next_to_the_job
30
+ all('.timestamp-link a').first.click
31
+ end
32
+
33
+ def given_there_are_two_delayed_jobs_enqueued_at_the_same_time
34
+ Resque.enqueue_at(some_time_in_the_future, JobWithParams, argument: 'thingy')
20
35
  Resque.enqueue_at(some_time_in_the_future, JobWithoutParams)
36
+ end
37
+
38
+ def when_i_visit_the_delayed_jobs_page
21
39
  visit resque_scheduler_engine_routes.delayed_path
40
+ end
41
+
42
+ def then_i_should_see_the_delayed_jobs_on_the_page_as_summary
22
43
  expect(page).to have_css '.job-count', text: '2'
44
+ end
45
+
46
+ def when_i_click_through_to_the_details_page
23
47
  click_link 'see details'
48
+ end
49
+
50
+ def then_i_should_see_the_details_of_the_jobs
24
51
  expect(page).to have_content 'JobWithParams'
25
52
  expect(page).to have_content '"argument"=>"thingy"'
26
53
  expect(page).to have_content 'JobWithoutParams'
54
+ expect(page).to have_content some_time_in_the_future
27
55
  end
28
-
29
56
  end
@@ -0,0 +1,55 @@
1
+ require 'rails_helper'
2
+
3
+ feature 'seeing all of the timestamps where a class is delayed' do
4
+
5
+ include SharedFunctionsForFeatures
6
+
7
+ scenario 'viewing the timestamps page with no params' do
8
+ given_there_is_a_delayed_job
9
+ when_i_visit_the_delayed_jobs_page
10
+ and_i_click_on_the_link_to_see_all_the_timestamps_for_that_job
11
+ then_i_should_be_on_the_delayed_class_page
12
+ and_i_should_see_the_timestamp_on_the_page
13
+ end
14
+
15
+ scenario 'viewing the timestamps page with activejob' do
16
+ given_there_is_a_delayed_job_with_active_job
17
+ when_i_visit_the_delayed_jobs_page
18
+ and_i_click_on_the_link_to_see_all_the_timestamps_for_that_job
19
+ and_i_should_see_the_timestamp_on_the_page
20
+ when_i_click_on_the_timestap
21
+ then_i_should_be_on_the_timestamp_page
22
+ end
23
+
24
+ def and_i_click_on_the_link_to_see_all_the_timestamps_for_that_job
25
+ click_link 'All schedules'
26
+ end
27
+
28
+ def then_i_should_be_on_the_delayed_class_page
29
+ expect(current_path).to eq resque_scheduler_engine_routes.delayed_job_class_path klass: 'SomeIvarJob'
30
+ end
31
+
32
+ def then_i_should_be_on_the_delayed_class_page_with_params
33
+ expect(current_path).to eq resque_scheduler_engine_routes.delayed_job_class_path klass: 'JobWithParams'
34
+ end
35
+
36
+ def and_i_should_see_the_timestamp_on_the_page
37
+ expect(page).to have_content some_time_in_the_future
38
+ end
39
+
40
+ def given_there_is_a_delayed_job_with_params
41
+ Resque.enqueue_at(some_time_in_the_future, JobWithParams, argument: 'thingy')
42
+ end
43
+
44
+ def given_there_is_a_delayed_job_with_active_job
45
+ ActiveJobTest.set(wait_until: some_time_in_the_future).perform_later
46
+ end
47
+
48
+ def when_i_click_on_the_timestap
49
+ all('.timestamp-link').first.click
50
+ end
51
+
52
+ def then_i_should_be_on_the_timestamp_page
53
+ expect(current_path).to eq resque_scheduler_engine_routes.timestamp_path timestamp: some_time_in_the_future.to_i
54
+ end
55
+ end
@@ -0,0 +1,29 @@
1
+ require 'rails_helper'
2
+
3
+ feature 'Sending a delayed job to the queue for immediate execution' do
4
+
5
+ include SharedFunctionsForFeatures
6
+
7
+ let(:queue_name) { 'ivar' }
8
+ let(:job_class) { 'SomeIvarJob' }
9
+
10
+ scenario 'Pressing the queue button sends the job to the queue immediately' do
11
+ given_there_is_a_delayed_job
12
+ when_i_visit_the_delayed_jobs_page
13
+ and_i_press_the_queue_now_button
14
+ then_i_should_be_on_the_overview_page
15
+ and_i_should_see_the_job_in_the_queue
16
+ when_i_click_through_to_the_queue_page
17
+ then_i_should_see_the_details_of_the_job_on_the_page
18
+ when_i_visit_the_delayed_jobs_page
19
+ then_i_should_not_see_any_delayed_jobs
20
+ end
21
+
22
+ def and_i_press_the_queue_now_button
23
+ click_button 'Queue now'
24
+ end
25
+
26
+ def then_i_should_not_see_any_delayed_jobs
27
+ expect(page).to have_content 'There are no delayed jobs'
28
+ end
29
+ end
@@ -2,14 +2,35 @@ require 'rails_helper'
2
2
 
3
3
  feature 'the tabs added to the resque web interface work correctly' do
4
4
  scenario 'the Schedule tab works' do
5
+ when_i_visit_the_resque_web_overview_page
6
+ and_i_follow_the_schedule_link
7
+ then_i_should_be_on_the_schedules_page
8
+ end
9
+
10
+ scenario 'the Delayed tab works' do
11
+ when_i_visit_the_resque_web_overview_page
12
+ when_i_follow_the_delayed_link
13
+ then_i_should_be_on_the_delayed_page
14
+ end
15
+
16
+ def when_i_visit_the_resque_web_overview_page
5
17
  visit ResqueWeb::Engine.app.url_helpers.overview_path
18
+ end
19
+
20
+ def and_i_follow_the_schedule_link
6
21
  click_link 'Schedule'
22
+ end
23
+
24
+ def then_i_should_be_on_the_schedules_page
7
25
  expect(current_path).to eq resque_scheduler_engine_routes.schedules_path
8
26
  end
9
27
 
10
- scenario 'the Delayed tab works' do
11
- visit ResqueWeb::Engine.app.url_helpers.overview_path
28
+ def when_i_follow_the_delayed_link
12
29
  click_link 'Delayed'
30
+ end
31
+
32
+ def then_i_should_be_on_the_delayed_page
13
33
  expect(current_path).to eq resque_scheduler_engine_routes.delayed_path
14
34
  end
35
+
15
36
  end
@@ -1,12 +1,16 @@
1
1
  require 'rails_helper'
2
-
3
2
  feature 'deleting a job from the dynamic schedule' do
4
3
 
5
- def visit_scheduler_page
6
- visit resque_scheduler_engine_routes.schedules_path
4
+ include SharedFunctionsForFeatures
5
+
6
+ scenario 'the delete button is not present when the schedule is static' do
7
+ given_there_are_some_jobs_in_the_schedule
8
+ and_the_schedule_is_set_to_be_static
9
+ when_i_visit_the_scheduler_page
10
+ then_there_should_not_be_a_delete_button_for_the_job
7
11
  end
8
12
 
9
- before do
13
+ def given_there_are_some_jobs_in_the_schedule
10
14
  Resque.schedule = {
11
15
  'some_ivar_job' => {
12
16
  'cron' => '* * * * *',
@@ -24,18 +28,18 @@ feature 'deleting a job from the dynamic schedule' do
24
28
  }
25
29
  }
26
30
  }
27
- allow(Resque::Scheduler).to receive(:dynamic).and_return(false)
28
31
  Resque::Scheduler.load_schedule!
29
- visit_scheduler_page
30
32
  end
31
33
 
32
- after do
33
- reset_the_resque_schedule
34
+ def and_the_schedule_is_set_to_be_static
35
+ allow(Resque::Scheduler).to receive(:dynamic).and_return(false)
34
36
  end
35
37
 
36
- scenario 'the delete button is not present when the schedule is static' do
37
- visit resque_scheduler_engine_routes.schedules_path
38
+ def then_there_should_not_be_a_delete_button_for_the_job
38
39
  expect(page).to_not have_css '#job_some_ivar_job .delete-button'
39
40
  end
40
41
 
42
+ def when_i_visit_the_scheduler_page
43
+ visit resque_scheduler_engine_routes.schedules_path
44
+ end
41
45
  end
@@ -2,11 +2,37 @@ require 'rails_helper'
2
2
 
3
3
  feature 'deleting a job from the dynamic schedule' do
4
4
 
5
- def visit_scheduler_page
6
- visit resque_scheduler_engine_routes.schedules_path
7
- end
5
+ include SharedFunctionsForFeatures
8
6
 
9
7
  before do
8
+ given_there_are_two_jobs_in_the_scheduler
9
+ and_the_schedule_is_set_up_to_be_dyamic
10
+ when_i_visit_the_scheduler_page
11
+ end
12
+
13
+ scenario 'the job disappears from the UI' do
14
+ when_i_delete_the_job_from_the_ui
15
+ then_i_should_be_on_the_scheduler_page
16
+ and_the_job_should_not_be_present_in_the_ui
17
+ end
18
+
19
+ scenario 'the other job remains in the UI' do
20
+ when_i_delete_the_job_from_the_ui
21
+ then_i_should_be_on_the_scheduler_page
22
+ and_the_other_job_should_still_be_present_in_the_ui
23
+ end
24
+
25
+ scenario 'the job is removed from the resque backend' do
26
+ when_i_delete_the_job_from_the_ui
27
+ then_i_should_be_on_the_scheduler_page
28
+ and_the_job_should_no_longer_be_present_in_the_resque_schedule
29
+ end
30
+
31
+ def and_the_schedule_is_set_up_to_be_dyamic
32
+ allow(Resque::Scheduler).to receive(:dynamic).and_return(true)
33
+ end
34
+
35
+ def given_there_are_two_jobs_in_the_scheduler
10
36
  Resque.schedule = {
11
37
  'some_ivar_job' => {
12
38
  'cron' => '* * * * *',
@@ -24,45 +50,30 @@ feature 'deleting a job from the dynamic schedule' do
24
50
  }
25
51
  }
26
52
  }
27
- allow(Resque::Scheduler).to receive(:dynamic).and_return(true)
28
53
  Resque::Scheduler.load_schedule!
29
- visit_scheduler_page
30
54
  end
31
55
 
32
- after do
33
- reset_the_resque_schedule
56
+ def when_i_visit_the_scheduler_page
57
+ visit resque_scheduler_engine_routes.schedules_path
34
58
  end
35
59
 
36
- # Given there is a job in the scheduler
37
- # And the schedule is set up to be dynamic
38
- # When I delete the job from the UI
39
- # Then I should be on the schedule page
40
- # And the job should no longer be present
41
- scenario 'the job disappears from the UI' do
60
+ def when_i_delete_the_job_from_the_ui
42
61
  find('#job_some_ivar_job .delete-button').click
43
- expect(current_path).to eq resque_scheduler_engine_routes.schedules_path
44
- expect(page).to_not have_css '#job_some_ivar_job'
45
62
  end
46
63
 
47
- # Given there are two jobs in the scheduler
48
- # And the schedule is set up to be dynamic
49
- # When I delete the job from the UI
50
- # Then I should be on the schedule page
51
- # And the other job should still be present
52
- scenario 'the other job remains in the UI' do
53
- find('#job_some_ivar_job .delete-button').click
64
+ def then_i_should_be_on_the_scheduler_page
54
65
  expect(current_path).to eq resque_scheduler_engine_routes.schedules_path
55
- expect(page).to have_css '#job_some_other_job'
56
66
  end
57
67
 
58
- # Given there is a job in the scheduler
59
- # And the schedule is set up to be dynamic
60
- # When I delete the job from the UI
61
- # Then I should be on the schedule page
62
- # And the job should no longer be present in the Resque schedule
63
- scenario 'the job is removed from the resque backend' do
64
- find('#job_some_ivar_job .delete-button').click
65
- expect(current_path).to eq resque_scheduler_engine_routes.schedules_path
68
+ def and_the_job_should_no_longer_be_present_in_the_resque_schedule
66
69
  expect(Resque.schedule).to_not have_key 'some_ivar_job'
67
70
  end
71
+
72
+ def and_the_other_job_should_still_be_present_in_the_ui
73
+ expect(page).to have_css '#job_some_other_job'
74
+ end
75
+
76
+ def and_the_job_should_not_be_present_in_the_ui
77
+ expect(page).to_not have_css '#job_some_ivar_job'
78
+ end
68
79
  end
@@ -1,39 +1,55 @@
1
1
  require 'rails_helper'
2
2
 
3
3
  feature 'requeuing a job that has defined params' do
4
+
5
+ include SharedFunctionsForFeatures
6
+
4
7
  before do
5
- Resque.schedule = Test::RESQUE_SCHEDULE
6
- Resque::Scheduler.load_schedule!
8
+ given_i_have_a_job_which_requires_params_in_the_schedule
7
9
  end
8
10
 
9
- after do
10
- reset_the_resque_schedule
11
+ scenario 'I am prompted to enter the params required for the requeued job' do
12
+ when_i_visit_the_schedules_page
13
+ and_i_requeue_the_job_with_new_params
14
+ then_i_should_be_on_the_overview_page
15
+ and_i_should_see_the_job_in_the_queue
16
+ when_i_click_on_the_link_to_the_queue
17
+ then_i_should_see_details_of_the_job_on_the_page
11
18
  end
12
19
 
13
- # Given I have a job which requires params in the schedule
14
- # When I press the requeue button
15
- # Then I should be presented with a form that prompts me for the params
16
- # When I enter the params and submit the form
17
- # Then I should be on the overview page
18
- # And I should see the job in the queue
19
- # When I visit the queue page
20
- # Then I should see the job on the page with the new params
21
- scenario 'I am prompted to enter the params required for the requeued job' do
22
- job_name = 'job_with_params'
23
- queue_name = 'quick'
24
- job_class = 'JobWithParams'
20
+ let(:job_name) { 'job_with_params' }
21
+ let(:queue_name) { 'quick' }
22
+ let(:job_class) { 'JobWithParams' }
25
23
 
24
+ def given_i_have_a_job_which_requires_params_in_the_schedule
25
+ Resque.schedule = Test::RESQUE_SCHEDULE
26
+ Resque::Scheduler.load_schedule!
27
+ end
28
+
29
+ def when_i_visit_the_schedules_page
26
30
  visit resque_scheduler_engine_routes.schedules_path
31
+ end
32
+
33
+ def and_i_requeue_the_job_with_new_params
27
34
  click_button "requeue_job_#{job_name}"
28
35
 
29
36
  fill_in 'log_level', with: 'info'
30
37
  click_button 'Queue now'
38
+ end
31
39
 
40
+ def then_i_should_be_on_the_overview_page
32
41
  expect(current_path).to eq ResqueWeb::Engine.app.url_helpers.overview_path
42
+ end
43
+
44
+ def and_i_should_see_the_job_in_the_queue
33
45
  expect(page).to have_content "#{queue_name} 1"
46
+ end
34
47
 
48
+ def when_i_click_on_the_link_to_the_queue
35
49
  find('.queues .queue a', text: queue_name).click
50
+ end
36
51
 
52
+ def then_i_should_see_details_of_the_job_on_the_page
37
53
  expect(page).to have_content job_class
38
54
  expect(page).to have_css 'td.args', text: /"log_level"=>"info"/
39
55
  end
@@ -1,7 +1,31 @@
1
1
  require 'rails_helper'
2
2
 
3
3
  feature 'requeuing a job that has no params' do
4
+
5
+ include SharedFunctionsForFeatures
6
+
4
7
  before do
8
+ given_i_have_a_job_which_requires_params_in_the_schedule
9
+ end
10
+
11
+ scenario 'I am prompted to enter the params required for the requeued job' do
12
+ when_i_visit_the_schedules_page
13
+ and_i_requeue_the_job
14
+ then_i_should_be_on_the_overview_page
15
+ and_i_should_see_the_job_in_the_queue
16
+ when_i_click_through_to_the_queue_page
17
+ then_i_should_see_the_details_of_the_job_on_the_page
18
+ end
19
+
20
+ let(:queue_name) { 'quick' }
21
+ let(:job_name) { 'job_without_params' }
22
+ let(:job_class) { 'JobWithoutParams' }
23
+
24
+ def when_i_visit_the_schedules_page
25
+ visit resque_scheduler_engine_routes.schedules_path
26
+ end
27
+
28
+ def given_i_have_a_job_which_requires_params_in_the_schedule
5
29
  Resque.schedule = {
6
30
  'job_without_params' => {
7
31
  'cron' => '* * * * *',
@@ -15,29 +39,9 @@ feature 'requeuing a job that has no params' do
15
39
  Resque::Scheduler.load_schedule!
16
40
  end
17
41
 
18
- after do
19
- reset_the_resque_schedule
20
- end
21
-
22
- # Given I have a job which requires params in the schedule
23
- # When I press the requeue button
24
- # Then I should be on the overview page
25
- # And I should see the job in the queue
26
- # When I visit the queue page
27
- # Then I should see the job on the page with the new params
28
- scenario 'I am prompted to enter the params required for the requeued job' do
29
- job_name = 'job_without_params'
30
- queue_name = 'quick'
31
- job_class = 'JobWithoutParams'
32
-
33
- visit resque_scheduler_engine_routes.schedules_path
42
+ def and_i_requeue_the_job
34
43
  click_button "requeue_job_#{job_name}"
44
+ end
35
45
 
36
- expect(current_path).to eq ResqueWeb::Engine.app.url_helpers.overview_path
37
- expect(page).to have_content "#{queue_name} 1"
38
-
39
- find('.queues .queue a', text: queue_name).click
40
46
 
41
- expect(page).to have_content job_class
42
- end
43
47
  end
@@ -1,13 +1,36 @@
1
1
  require 'rails_helper'
2
2
 
3
3
  feature 'Viewing the schedule page and interacting with it' do
4
- def visit_scheduler_page
5
- visit resque_scheduler_engine_routes.schedules_path
6
- end
4
+
5
+ include SharedFunctionsForFeatures
7
6
 
8
7
  before do
8
+ given_the_resque_scheduler_is_using_the_production_environment
9
+ and_there_are_several_jobs_in_the_schedule
10
+ when_i_visit_the_scheduler_page
11
+ end
12
+
13
+ scenario 'the page has the correct title' do
14
+ then_the_page_should_have_the_correct_title
15
+ end
16
+
17
+ scenario 'the index shows the scheduled job' do
18
+ then_the_page_should_have_the_class_name_of_the_job_in_this_env
19
+ end
20
+
21
+ scenario 'the index excludes jobs for other envs' do
22
+ then_the_page_should_not_have_the_name_of_jobs_from_other_envs
23
+ end
24
+
25
+ scenario 'the index includes job used in multiple environments' do
26
+ then_the_page_should_have_the_name_of_jobs_in_both_this_and_other_envs
27
+ end
28
+
29
+ def given_the_resque_scheduler_is_using_the_production_environment
9
30
  Resque::Scheduler.env = 'production'
31
+ end
10
32
 
33
+ def and_there_are_several_jobs_in_the_schedule
11
34
  Resque.schedule = {
12
35
  'some_ivar_job' => {
13
36
  'cron' => '* * * * *',
@@ -38,46 +61,34 @@ feature 'Viewing the schedule page and interacting with it' do
38
61
  }
39
62
  }
40
63
  Resque::Scheduler.load_schedule!
41
- visit_scheduler_page
42
64
  end
43
65
 
44
- after do
45
- reset_the_resque_schedule
66
+ def when_i_visit_the_resque_web_home_page
67
+ visit '/resque_web'
46
68
  end
47
69
 
48
- it 'Link to Schedule page in navigation works' do
49
- visit '/resque_web'
70
+ def and_i_click_the_schedule_link
50
71
  click_link 'Schedule'
51
- assert page.has_css? 'h1', 'Schedule'
52
72
  end
53
73
 
54
- it 'has the correct title' do
74
+ def then_the_page_should_have_the_correct_title
55
75
  assert page.has_css?('h1', 'Schedule')
56
76
  end
57
77
 
58
- it 'shows the scheduled job' do
78
+ def then_the_page_should_have_the_class_name_of_the_job_in_this_env
59
79
  assert page.body.include?('SomeIvarJob')
60
80
  end
61
81
 
62
- it 'excludes jobs for other envs' do
82
+ def then_the_page_should_not_have_the_name_of_jobs_from_other_envs
63
83
  refute page.body.include?('SomeFancyJob')
64
84
  end
65
85
 
66
- it 'includes job used in multiple environments' do
86
+ def then_the_page_should_have_the_name_of_jobs_in_both_this_and_other_envs
67
87
  assert page.body.include?('SomeSharedEnvJob')
68
88
  end
69
89
 
70
- it 'allows delete when dynamic' do
71
- allow(Resque::Scheduler).to receive(:dynamic).and_return(true)
72
- visit_scheduler_page
73
-
74
- assert page.body.include?('Delete')
90
+ def when_i_visit_the_scheduler_page
91
+ visit resque_scheduler_engine_routes.schedules_path
75
92
  end
76
93
 
77
- it "doesn't allow delete when static" do
78
- allow(Resque::Scheduler).to receive(:dynamic).and_return(false)
79
- visit_scheduler_page
80
-
81
- refute page.body.include?('Delete')
82
- end
83
94
  end
data/spec/spec_helper.rb CHANGED
@@ -6,6 +6,7 @@ ENV['RAILS_ENV'] = 'test'
6
6
  require 'resque'
7
7
  require 'resque-scheduler'
8
8
  require_relative 'support/functions'
9
+ require_relative 'support/shared_steps'
9
10
 
10
11
 
11
12
  Resque::Scheduler.configure do |c|
@@ -0,0 +1,47 @@
1
+ module SharedFunctionsForFeatures
2
+
3
+ def self.included(base)
4
+ base.instance_eval do
5
+ let(:some_time_in_the_future) { Time.now + 3600 }
6
+ let(:some_other_time_in_the_future) { Time.now + 4600 }
7
+
8
+ after do
9
+ reset_the_resque_schedule
10
+ end
11
+ end
12
+ end
13
+
14
+ def when_i_visit_the_delayed_jobs_page
15
+ visit resque_scheduler_engine_routes.delayed_path
16
+ end
17
+
18
+ def then_i_should_be_on_the_delayed_jobs_page
19
+ expect(current_path).to eq resque_scheduler_engine_routes.delayed_path
20
+ end
21
+
22
+ def given_there_are_two_delayed_jobs_enqueued_at_different_times
23
+ Resque.enqueue_at(some_time_in_the_future, SomeIvarJob)
24
+ Resque.enqueue_at(some_other_time_in_the_future, JobWithoutParams)
25
+ end
26
+
27
+ def given_there_is_a_delayed_job
28
+ Resque.enqueue_at(some_time_in_the_future, SomeIvarJob)
29
+ end
30
+
31
+ def then_i_should_be_on_the_overview_page
32
+ expect(current_path).to eq ResqueWeb::Engine.app.url_helpers.overview_path
33
+ end
34
+
35
+ def and_i_should_see_the_job_in_the_queue
36
+ expect(page).to have_content "#{queue_name} 1"
37
+ end
38
+
39
+ def when_i_click_through_to_the_queue_page
40
+ find('.queues .queue a', text: queue_name).click
41
+ end
42
+
43
+ def then_i_should_see_the_details_of_the_job_on_the_page
44
+ expect(page).to have_content job_class
45
+ end
46
+ end
47
+
@@ -1,3 +1,5 @@
1
+ require 'active_job'
2
+
1
3
  # Allows us to test that we can find working jobs
2
4
  class OngoingJob
3
5
  def self.queue
@@ -46,6 +48,18 @@ JobWithoutParams = Class.new(JobWithParams) do
46
48
  @queue = :quick
47
49
  end
48
50
 
51
+ class ActiveJobTest < ActiveJob::Base
52
+ queue_as :test_queue
53
+
54
+ def self.queue
55
+ queue_name
56
+ end
57
+
58
+ def perform
59
+
60
+ end
61
+ end
62
+
49
63
  # Test module
50
64
  module Foo
51
65
  # Test class
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque-scheduler-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Gibson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-28 00:00:00.000000000 Z
11
+ date: 2015-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: resque-web
@@ -205,6 +205,7 @@ files:
205
205
  - ".rspec"
206
206
  - ".rubocop.yml"
207
207
  - ".travis.yml"
208
+ - CHANGELOG.md
208
209
  - Gemfile
209
210
  - LICENSE.txt
210
211
  - README.md
@@ -275,8 +276,12 @@ files:
275
276
  - spec/dummy/public/422.html
276
277
  - spec/dummy/public/500.html
277
278
  - spec/dummy/public/favicon.ico
279
+ - spec/features/delayed/cancel_delayed_job_spec.rb
280
+ - spec/features/delayed/clear_all_jobs_spec.rb
278
281
  - spec/features/delayed/delayed_jobs_index_page_spec.rb
279
282
  - spec/features/delayed/delayed_jobs_timestamp_page_spec.rb
283
+ - spec/features/delayed/see_all_timestamps_for_a_class_spec.rb
284
+ - spec/features/delayed/send_a_delayed_job_to_the_queue_spec.rb
280
285
  - spec/features/navigation_spec.rb
281
286
  - spec/features/schedules/cannot_delete_a_job_when_the_schedule_is_static.rb
282
287
  - spec/features/schedules/delete_a_job_from_the_dynamic_schedule_spec.rb
@@ -290,6 +295,7 @@ files:
290
295
  - spec/spec_helper.rb
291
296
  - spec/support/functions.rb
292
297
  - spec/support/redis_instance.rb
298
+ - spec/support/shared_steps.rb
293
299
  - spec/support/test_jobs.rb
294
300
  homepage: https://github.com/mattgibson/resque-scheduler-web
295
301
  licenses:
@@ -362,8 +368,12 @@ test_files:
362
368
  - spec/dummy/public/422.html
363
369
  - spec/dummy/public/500.html
364
370
  - spec/dummy/public/favicon.ico
371
+ - spec/features/delayed/cancel_delayed_job_spec.rb
372
+ - spec/features/delayed/clear_all_jobs_spec.rb
365
373
  - spec/features/delayed/delayed_jobs_index_page_spec.rb
366
374
  - spec/features/delayed/delayed_jobs_timestamp_page_spec.rb
375
+ - spec/features/delayed/see_all_timestamps_for_a_class_spec.rb
376
+ - spec/features/delayed/send_a_delayed_job_to_the_queue_spec.rb
367
377
  - spec/features/navigation_spec.rb
368
378
  - spec/features/schedules/cannot_delete_a_job_when_the_schedule_is_static.rb
369
379
  - spec/features/schedules/delete_a_job_from_the_dynamic_schedule_spec.rb
@@ -377,4 +387,5 @@ test_files:
377
387
  - spec/spec_helper.rb
378
388
  - spec/support/functions.rb
379
389
  - spec/support/redis_instance.rb
390
+ - spec/support/shared_steps.rb
380
391
  - spec/support/test_jobs.rb