creeper 1.0.9 → 2.0.0

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.
Files changed (145) hide show
  1. data/.gitignore +1 -0
  2. data/.rvmrc +48 -0
  3. data/Gemfile +17 -1
  4. data/Guardfile +32 -0
  5. data/Rakefile +9 -1
  6. data/bin/creeper +10 -58
  7. data/bin/creeperctl +74 -0
  8. data/config.ru +18 -0
  9. data/creeper.gemspec +19 -9
  10. data/lib/creeper.rb +108 -413
  11. data/lib/creeper/beanstalk_connection.rb +35 -0
  12. data/lib/creeper/cli.rb +225 -0
  13. data/lib/creeper/client.rb +93 -0
  14. data/lib/creeper/core_ext.rb +54 -0
  15. data/lib/creeper/exception_handler.rb +30 -0
  16. data/lib/creeper/extensions/action_mailer.rb +33 -0
  17. data/lib/creeper/extensions/active_record.rb +30 -0
  18. data/lib/creeper/extensions/generic_proxy.rb +26 -0
  19. data/lib/creeper/fetch.rb +94 -0
  20. data/lib/creeper/legacy.rb +46 -0
  21. data/lib/creeper/logging.rb +46 -0
  22. data/lib/creeper/manager.rb +164 -0
  23. data/lib/creeper/middleware/chain.rb +100 -0
  24. data/lib/creeper/middleware/server/active_record.rb +13 -0
  25. data/lib/creeper/middleware/server/logging.rb +31 -0
  26. data/lib/creeper/middleware/server/retry_jobs.rb +79 -0
  27. data/lib/creeper/middleware/server/timeout.rb +21 -0
  28. data/lib/creeper/paginator.rb +31 -0
  29. data/lib/creeper/processor.rb +116 -0
  30. data/lib/creeper/rails.rb +21 -0
  31. data/lib/creeper/redis_connection.rb +28 -0
  32. data/lib/creeper/testing.rb +44 -0
  33. data/lib/creeper/util.rb +45 -0
  34. data/lib/creeper/version.rb +1 -1
  35. data/lib/creeper/web.rb +248 -0
  36. data/lib/creeper/worker.rb +62 -313
  37. data/spec/dummy/.gitignore +15 -0
  38. data/spec/dummy/Gemfile +51 -0
  39. data/spec/dummy/README.rdoc +261 -0
  40. data/spec/dummy/Rakefile +7 -0
  41. data/spec/dummy/app/assets/images/rails.png +0 -0
  42. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  43. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  44. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  45. data/spec/dummy/app/controllers/work_controller.rb +71 -0
  46. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  47. data/spec/dummy/app/mailers/.gitkeep +0 -0
  48. data/spec/dummy/app/mailers/user_mailer.rb +9 -0
  49. data/spec/dummy/app/models/.gitkeep +0 -0
  50. data/spec/dummy/app/models/post.rb +8 -0
  51. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  52. data/spec/dummy/app/views/user_mailer/greetings.html.erb +3 -0
  53. data/spec/dummy/app/views/work/index.html.erb +1 -0
  54. data/spec/dummy/app/workers/fast_worker.rb +10 -0
  55. data/spec/dummy/app/workers/hard_worker.rb +11 -0
  56. data/spec/dummy/app/workers/lazy_worker.rb +12 -0
  57. data/spec/dummy/app/workers/suicidal_worker.rb +33 -0
  58. data/spec/dummy/config.ru +4 -0
  59. data/spec/dummy/config/application.rb +68 -0
  60. data/spec/dummy/config/boot.rb +6 -0
  61. data/spec/dummy/config/creeper.yml +9 -0
  62. data/spec/dummy/config/database.yml +25 -0
  63. data/spec/dummy/config/environment.rb +5 -0
  64. data/spec/dummy/config/environments/development.rb +37 -0
  65. data/spec/dummy/config/environments/production.rb +67 -0
  66. data/spec/dummy/config/environments/test.rb +37 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/creeper.rb +8 -0
  69. data/spec/dummy/config/initializers/inflections.rb +15 -0
  70. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  71. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  72. data/spec/dummy/config/initializers/session_store.rb +8 -0
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  74. data/spec/dummy/config/locales/en.yml +5 -0
  75. data/spec/dummy/config/routes.rb +13 -0
  76. data/spec/dummy/db/migrate/20120123214055_create_posts.rb +10 -0
  77. data/spec/dummy/db/schema.rb +23 -0
  78. data/spec/dummy/db/seeds.rb +7 -0
  79. data/spec/dummy/lib/assets/.gitkeep +0 -0
  80. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  81. data/spec/dummy/log/.gitkeep +0 -0
  82. data/spec/dummy/public/404.html +26 -0
  83. data/spec/dummy/public/422.html +26 -0
  84. data/spec/dummy/public/500.html +25 -0
  85. data/spec/dummy/public/favicon.ico +0 -0
  86. data/spec/dummy/public/index.html +241 -0
  87. data/spec/dummy/public/robots.txt +5 -0
  88. data/spec/dummy/script/rails +6 -0
  89. data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
  90. data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
  91. data/spec/dummy/vendor/plugins/.gitkeep +0 -0
  92. data/spec/lib/creeper/cli_spec.rb +208 -0
  93. data/spec/lib/creeper/client_spec.rb +110 -0
  94. data/spec/lib/creeper/exception_handler_spec.rb +110 -0
  95. data/spec/lib/creeper/processor_spec.rb +92 -0
  96. data/spec/lib/creeper/testing_spec.rb +105 -0
  97. data/spec/lib/creeper_spec.rb +54 -120
  98. data/spec/spec_helper.rb +81 -7
  99. data/spec/support/config.yml +9 -0
  100. data/spec/support/fake_env.rb +0 -0
  101. data/spec/support/workers/base_worker.rb +11 -0
  102. data/spec/support/workers/my_worker.rb +4 -0
  103. data/spec/support/workers/queued_worker.rb +5 -0
  104. data/spec/support/workers/real_worker.rb +10 -0
  105. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  106. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  107. data/web/assets/javascripts/application.js +49 -0
  108. data/web/assets/javascripts/vendor/bootstrap.js +12 -0
  109. data/web/assets/javascripts/vendor/bootstrap/bootstrap-alert.js +91 -0
  110. data/web/assets/javascripts/vendor/bootstrap/bootstrap-button.js +98 -0
  111. data/web/assets/javascripts/vendor/bootstrap/bootstrap-carousel.js +154 -0
  112. data/web/assets/javascripts/vendor/bootstrap/bootstrap-collapse.js +136 -0
  113. data/web/assets/javascripts/vendor/bootstrap/bootstrap-dropdown.js +92 -0
  114. data/web/assets/javascripts/vendor/bootstrap/bootstrap-modal.js +210 -0
  115. data/web/assets/javascripts/vendor/bootstrap/bootstrap-popover.js +95 -0
  116. data/web/assets/javascripts/vendor/bootstrap/bootstrap-scrollspy.js +125 -0
  117. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tab.js +130 -0
  118. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tooltip.js +270 -0
  119. data/web/assets/javascripts/vendor/bootstrap/bootstrap-transition.js +51 -0
  120. data/web/assets/javascripts/vendor/bootstrap/bootstrap-typeahead.js +271 -0
  121. data/web/assets/javascripts/vendor/jquery.js +9266 -0
  122. data/web/assets/javascripts/vendor/jquery.timeago.js +148 -0
  123. data/web/assets/stylesheets/application.css +6 -0
  124. data/web/assets/stylesheets/layout.css +26 -0
  125. data/web/assets/stylesheets/vendor/bootstrap-responsive.css +567 -0
  126. data/web/assets/stylesheets/vendor/bootstrap.css +3365 -0
  127. data/web/views/_paging.slim +15 -0
  128. data/web/views/_summary.slim +9 -0
  129. data/web/views/_workers.slim +14 -0
  130. data/web/views/index.slim +10 -0
  131. data/web/views/layout.slim +37 -0
  132. data/web/views/poll.slim +3 -0
  133. data/web/views/queue.slim +15 -0
  134. data/web/views/queues.slim +19 -0
  135. data/web/views/retries.slim +31 -0
  136. data/web/views/retry.slim +52 -0
  137. data/web/views/scheduled.slim +27 -0
  138. metadata +341 -23
  139. data/lib/creeper/celluloid_ext.rb +0 -42
  140. data/lib/creeper/creep.rb +0 -25
  141. data/lib/creeper/err_logger.rb +0 -37
  142. data/lib/creeper/launcher.rb +0 -44
  143. data/lib/creeper/out_logger.rb +0 -39
  144. data/spec/lib/creeper/session_spec.rb +0 -15
  145. data/spec/lib/creeper/worker_spec.rb +0 -21
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+ require 'creeper/client'
3
+ require 'creeper/worker'
4
+
5
+ describe Creeper::Client do
6
+
7
+ context 'with mock beanstalk and redis' do
8
+ before do
9
+ @beanstalk = double('beanstalk')
10
+ @connection = double('connection')
11
+ def @beanstalk.on_tube(tube); yield @connection if block_given?; end
12
+ Creeper.instance_variable_set(:@beanstalk, @beanstalk)
13
+ @redis = double('redis')
14
+ def @redis.multi; [yield] * 2 if block_given?; end
15
+ def @redis.set(*); true; end
16
+ def @redis.sadd(*); true; end
17
+ def @redis.srem(*); true; end
18
+ def @redis.get(*); nil; end
19
+ def @redis.del(*); nil; end
20
+ def @redis.incrby(*); nil; end
21
+ def @redis.setex(*); true; end
22
+ def @redis.expire(*); true; end
23
+ def @redis.watch(*); true; end
24
+ def @redis.with_connection; yield self; end
25
+ def @redis.with; yield self; end
26
+ def @redis.exec; true; end
27
+ Creeper.instance_variable_set(:@redis, @redis)
28
+ end
29
+
30
+ after do
31
+ Creeper.instance_variable_set(:@beanstalk, nil)
32
+ Creeper.instance_variable_set(:@redis, nil)
33
+ end
34
+
35
+ it 'raises ArgumentError with invalid params' do
36
+ expect do
37
+ Creeper::Client.push('foo', 1)
38
+ end.to raise_error(ArgumentError)
39
+
40
+ expect do
41
+ Creeper::Client.push('foo', :class => 'Foo', :noargs => [1, 2])
42
+ end.to raise_error(ArgumentError)
43
+ end
44
+
45
+ it 'pushes messages to beanstalk' do
46
+ @beanstalk.should_receive(:on_tube).with('foo').and_yield(@connection)
47
+ @connection.should_receive(:put).with(%q(["foo",{"retry":true,"queue":"foo","class":"MyWorker","args":[1,2]}])).and_return(24)
48
+ pushed = Creeper::Client.push('queue' => 'foo', 'class' => MyWorker, 'args' => [1, 2])
49
+ expect(pushed).to eq(24)
50
+ end
51
+
52
+ it 'has default options' do
53
+ expect(Creeper::Worker::ClassMethods::DEFAULT_OPTIONS).to eq(MyWorker.get_creeper_options)
54
+ end
55
+
56
+ it 'handles perform_async' do
57
+ @beanstalk.should_receive(:on_tube).with('default').and_yield(@connection)
58
+ @connection.should_receive(:put).with(%q(["default",{"retry":true,"queue":"default","class":"MyWorker","args":[1,2]}])).and_return(24)
59
+ pushed = MyWorker.perform_async(1, 2)
60
+ expect(pushed).to eq(24)
61
+ end
62
+
63
+ it 'handles perform_async on failure' do
64
+ @beanstalk.should_receive(:on_tube).with('default').and_yield(@connection)
65
+ @connection.should_receive(:put).with(%q(["default",{"retry":true,"queue":"default","class":"MyWorker","args":[1,2]}])).and_return(nil)
66
+ pushed = MyWorker.perform_async(1, 2)
67
+ expect(pushed).to be_nil
68
+ end
69
+
70
+ it 'enqueues messages to beanstalk' do
71
+ @beanstalk.should_receive(:on_tube).with('default').and_yield(@connection)
72
+ @connection.should_receive(:put).with(%q(["default",{"retry":true,"queue":"default","class":"MyWorker","args":[1,2]}])).and_return(24)
73
+ pushed = Creeper::Client.enqueue(MyWorker, 1, 2)
74
+ expect(pushed).to eq(24)
75
+ end
76
+
77
+ it 'enqueues messages to beanstalk using legacy method' do
78
+ @beanstalk.should_receive(:on_tube).with('my.worker').and_yield(@connection)
79
+ @connection.should_receive(:put).with(%q(["my.worker",{"retry":true,"queue":"my.worker","args":[1,2],"class":"MyWorker","delay":0,"priority":65536,"time_to_run":120}]), 65536, 0, 120).and_return(24)
80
+ pushed = Creeper.enqueue('my.worker', 1, 2)
81
+ expect(pushed).to eq(24)
82
+ end
83
+
84
+ it 'enqueues to the named queue' do
85
+ @beanstalk.should_receive(:on_tube).with(:flimflam).and_yield(@connection)
86
+ @connection.should_receive(:put).with(%q(["flimflam",{"retry":true,"queue":"flimflam","timeout":1,"class":"QueuedWorker","args":[1,2]}])).and_return(24)
87
+ pushed = QueuedWorker.perform_async(1, 2)
88
+ expect(pushed).to eq(24)
89
+ end
90
+
91
+ it 'retrieves queues' do
92
+ @redis.should_receive(:smembers).with('queues').and_return(['bob'])
93
+ expect(Creeper::Client.registered_queues).to eq(['bob'])
94
+ end
95
+
96
+ it 'retrieves workers' do
97
+ @redis.should_receive(:smembers).with('workers').and_return(['bob'])
98
+ expect(Creeper::Client.registered_workers).to eq(['bob'])
99
+ end
100
+
101
+ end
102
+
103
+ describe 'inheritance' do
104
+ it 'should inherit creeper options' do
105
+ expect(AWorker.get_creeper_options['retry']).to eq('base')
106
+ expect(BWorker.get_creeper_options['retry']).to eq('b')
107
+ end
108
+ end
109
+
110
+ end
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+ require 'creeper'
3
+ require 'creeper/exception_handler'
4
+ require 'stringio'
5
+ require 'logger'
6
+
7
+ describe Creeper::ExceptionHandler do
8
+
9
+ before do
10
+ stub_const('ExceptionHandlerTestException', Class.new(StandardError))
11
+ stub_const('TEST_EXCEPTION', ExceptionHandlerTestException.new("Something didn't work!"))
12
+ end
13
+
14
+ class Component
15
+ include Creeper::Util
16
+
17
+ def invoke_exception(args)
18
+ raise TEST_EXCEPTION
19
+ rescue ExceptionHandlerTestException => e
20
+ handle_exception(e,args)
21
+ end
22
+ end
23
+
24
+ describe "with mock logger" do
25
+ before do
26
+ @old_logger = Creeper.logger
27
+ @str_logger = StringIO.new
28
+ Creeper.logger = Logger.new(@str_logger)
29
+ end
30
+
31
+ after do
32
+ Creeper.logger = @old_logger
33
+ end
34
+
35
+ it "logs the exception to Creeper.logger" do
36
+ Component.new.invoke_exception(:a => 1)
37
+ @str_logger.rewind
38
+ log = @str_logger.readlines
39
+ expect(log[0]).to match(/a=>1/) # didn't include the context
40
+ expect(log[1]).to match(/Something didn't work!/) # didn't include the exception message
41
+ expect(log[2]).to match(/spec\/lib\/creeper\/exception_handler_spec\.rb/) # didn't include the backtrace
42
+ end
43
+ end
44
+
45
+ describe "with fake Airbrake" do
46
+ before do
47
+ ::Airbrake = double('Airbrake')
48
+ end
49
+
50
+ after do
51
+ Object.send(:remove_const, "Airbrake") # HACK should probably inject Airbrake etc into this class in the future
52
+ end
53
+
54
+ it "notifies Airbrake" do
55
+ ::Airbrake.should_receive(:notify).with(TEST_EXCEPTION,:parameters => { :a => 1 }).and_return(nil)
56
+ Component.new.invoke_exception(:a => 1)
57
+ end
58
+ end
59
+
60
+ describe "with fake ExceptionNotifier" do
61
+ before do
62
+ ::ExceptionNotifier = Module.new
63
+ ::ExceptionNotifier::Notifier = double('ExceptionNotifier::Notifier')
64
+ end
65
+
66
+ after do
67
+ Object.send(:remove_const, "ExceptionNotifier")
68
+ end
69
+
70
+ it "notifies ExceptionNotifier" do
71
+ mail = double('mail')
72
+ mail.should_receive(:deliver).and_return(nil)
73
+ ::ExceptionNotifier::Notifier.should_receive(:background_exception_notification).with(TEST_EXCEPTION, :data => { :message => { :b => 2 } }).and_return(mail)
74
+ Component.new.invoke_exception(:b => 2)
75
+ end
76
+ end
77
+
78
+ describe "with fake Exceptional" do
79
+ before do
80
+ ::Exceptional = Class.new do
81
+
82
+ def self.context(msg)
83
+ @msg = msg
84
+ end
85
+
86
+ def self.check_context
87
+ @msg
88
+ end
89
+ end
90
+
91
+ ::Exceptional::Config = double('Exceptional::Config')
92
+ ::Exceptional::Remote = double('Exceptional::Remote')
93
+ ::Exceptional::ExceptionData = double('Exceptional::ExceptionData')
94
+ end
95
+
96
+ after do
97
+ Object.send(:remove_const, "Exceptional")
98
+ end
99
+
100
+ it "notifies Exceptional" do
101
+ ::Exceptional::Config.should_receive(:should_send_to_api?).and_return(true)
102
+ exception_data = double('exception_data')
103
+ ::Exceptional::Remote.should_receive(:error).with(exception_data).and_return(nil)
104
+ ::Exceptional::ExceptionData.should_receive(:new).with(TEST_EXCEPTION).and_return(exception_data)
105
+ Component.new.invoke_exception(:c => 3)
106
+ expect(::Exceptional.check_context).to eq({:c => 3}) # did not record arguments properly
107
+ end
108
+ end
109
+
110
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+ require 'creeper/processor'
3
+
4
+ describe Creeper::Processor do
5
+
6
+ context 'with mock setup' do
7
+
8
+ before do
9
+ stub_const('TestException', Class.new(StandardError))
10
+ stub_const('TEST_EXCEPTION', TestException.new("kerboom!"))
11
+ end
12
+
13
+ let(:boss) { double('boss') }
14
+ let(:processor) { ::Creeper::Processor.new(boss) }
15
+
16
+ let(:job) { double('job') }
17
+ let(:conn) { double('conn') }
18
+
19
+ before do
20
+ $invokes = 0
21
+ Celluloid.logger = nil
22
+ Creeper.redis = REDIS
23
+ end
24
+
25
+ class MockWorker
26
+ include Creeper::Worker
27
+ def perform(args)
28
+ raise TEST_EXCEPTION if args == 'boom'
29
+ args.pop if args.is_a? Array
30
+ $invokes += 1
31
+ end
32
+ end
33
+
34
+ it 'processes as expected' do
35
+ msg = Creeper.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
36
+
37
+ conn.should_receive(:close).and_return(true)
38
+ job.should_receive(:id).and_return(1)
39
+ job.should_receive(:delete).and_return(true)
40
+ boss.should_receive(:processor_done!).with(processor).and_return(nil)
41
+
42
+ processor.process(msg, 'default', job, conn)
43
+ expect($invokes).to eq(1)
44
+ end
45
+
46
+ it 'passes exceptions to ExceptionHandler' do
47
+ msg = Creeper.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
48
+
49
+ conn.should_receive(:close).and_return(true)
50
+ job.should_receive(:id).and_return(1)
51
+ job.should_receive(:bury).and_return(true)
52
+
53
+ expect do
54
+ processor.process(msg, 'default', job, conn)
55
+ end.to raise_error(TestException)
56
+
57
+ expect($invokes).to eq(0)
58
+ end
59
+
60
+ it 're-raises exceptions after handling' do
61
+ msg = Creeper.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
62
+ re_raise = false
63
+
64
+ conn.should_receive(:close).and_return(true)
65
+ job.should_receive(:id).and_return(1)
66
+ job.should_receive(:bury).and_return(true)
67
+
68
+ begin
69
+ processor.process(msg, 'default', job, conn)
70
+ rescue TestException
71
+ re_raise = true
72
+ end
73
+
74
+ expect(re_raise).to be_true # does not re-raise exceptions after handling
75
+ end
76
+
77
+ it 'does not modify original arguments' do
78
+ msg = { 'class' => MockWorker.to_s, 'args' => [['myarg']] }
79
+ msgstr = Creeper.dump_json(msg)
80
+
81
+ conn.should_receive(:close).and_return(true)
82
+ job.should_receive(:id).and_return(1)
83
+ job.should_receive(:delete).and_return(true)
84
+ boss.should_receive(:processor_done!).with(processor).and_return(nil)
85
+
86
+ processor.process(msgstr, 'default', job, conn)
87
+ expect(msg['args']).to eq([['myarg']])
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+ require 'creeper'
3
+ require 'creeper/worker'
4
+ require 'active_record'
5
+ require 'action_mailer'
6
+ require 'creeper/rails'
7
+ require 'creeper/extensions/action_mailer'
8
+ require 'creeper/extensions/active_record'
9
+
10
+ Creeper.hook_rails!
11
+
12
+ describe Creeper::Worker do
13
+
14
+ context 'creeper testing' do
15
+ class PerformError < RuntimeError; end
16
+
17
+ class DirectWorker
18
+ include Creeper::Worker
19
+ def perform(a, b)
20
+ a + b
21
+ end
22
+ end
23
+
24
+ class EnqueuedWorker
25
+ include Creeper::Worker
26
+ def perform(a, b)
27
+ a + b
28
+ end
29
+ end
30
+
31
+ class StoredWorker
32
+ include Creeper::Worker
33
+ def perform(error)
34
+ raise PerformError if error
35
+ end
36
+ end
37
+
38
+ class FooMailer < ActionMailer::Base
39
+ def bar(str)
40
+ str
41
+ end
42
+ end
43
+
44
+ class FooModel < ActiveRecord::Base
45
+ def bar(str)
46
+ str
47
+ end
48
+ end
49
+
50
+ before do
51
+ load 'creeper/testing.rb'
52
+ end
53
+
54
+ after do
55
+ # Undo override
56
+ Creeper::Worker::ClassMethods.class_eval do
57
+ remove_method :client_push
58
+ alias_method :client_push, :client_push_old
59
+ remove_method :client_push_old
60
+ end
61
+ end
62
+
63
+ it 'stubs the async call' do
64
+ expect(DirectWorker.jobs.size).to eq(0)
65
+ expect(DirectWorker.perform_async(1, 2)).to be_true
66
+ expect(DirectWorker.jobs.size).to eq(1)
67
+ expect(DirectWorker.perform_in(10, 1, 2)).to be_true
68
+ expect(DirectWorker.jobs.size).to eq(2)
69
+ expect(DirectWorker.perform_at(10, 1, 2)).to be_true
70
+ expect(DirectWorker.jobs.size).to eq(3)
71
+ expect(DirectWorker.jobs.last['at']).to be_within(0.1).of(10.seconds.from_now.to_f)
72
+ end
73
+
74
+ it 'stubs the delay call on mailers' do
75
+ expect(Creeper::Extensions::DelayedMailer.jobs.size).to eq(0)
76
+ FooMailer.delay.bar('hello!')
77
+ expect(Creeper::Extensions::DelayedMailer.jobs.size).to eq(1)
78
+ end
79
+
80
+ it 'stubs the delay call on models' do
81
+ expect(Creeper::Extensions::DelayedModel.jobs.size).to eq(0)
82
+ FooModel.delay.bar('hello!')
83
+ expect(Creeper::Extensions::DelayedModel.jobs.size).to eq(1)
84
+ end
85
+
86
+ it 'stubs the enqueue call' do
87
+ expect(EnqueuedWorker.jobs.size).to eq(0)
88
+ expect(Creeper::Client.enqueue(EnqueuedWorker, 1, 2)).to be_true
89
+ expect(EnqueuedWorker.jobs.size).to eq(1)
90
+ end
91
+
92
+ it 'executes all stored jobs' do
93
+ expect(StoredWorker.perform_async(false)).to be_true
94
+ expect(StoredWorker.perform_async(true)).to be_true
95
+
96
+ expect(StoredWorker.jobs.size).to eq(2)
97
+ expect do
98
+ StoredWorker.drain
99
+ end.to raise_error(PerformError)
100
+ expect(StoredWorker.jobs.size).to eq(0)
101
+ end
102
+
103
+ end
104
+
105
+ end
@@ -1,131 +1,65 @@
1
1
  require 'spec_helper'
2
+ require 'creeper/cli'
2
3
 
3
4
  describe Creeper do
4
5
 
5
- after :each do
6
- Creeper.clear!
7
- end
8
-
9
- it "work a job and do it up" do
10
- val = rand(999999)
11
- Creeper.job('my.job') { |args| $result = args['val'] }
12
- Creeper.enqueue('my.job', :val => val)
13
- w = Creeper::Worker.new
14
- w.stub(:exception_message)
15
- w.stub(:log)
16
- w.prepare
17
- w.work_one_job
18
- val.should == $result
19
- end
20
-
21
- it "invoke error handler when defined" do
22
- with_an_error_handler
23
- Creeper.job('my.job') { |args| fail }
24
- Creeper.enqueue('my.job', :foo => 123)
25
- w = Creeper::Worker.new
26
- w.stub(:exception_message)
27
- w.stub(:log)
28
- w.prepare
29
- w.work_one_job
30
- $handled.should_not == nil
31
- 'my.job'.should == $job_name
32
- {'foo' => 123}.should == $job_args
33
- end
34
-
35
- it "should be compatible with legacy error handlers" do
36
- exception = StandardError.new("Oh my, the job has failed!")
37
- Creeper.error { |e| $handled = e }
38
- Creeper.job('my.job') { |args| raise exception }
39
- Creeper.enqueue('my.job')
40
- w = Creeper::Worker.new
41
- w.stub(:exception_message)
42
- w.stub(:log)
43
- w.prepare
44
- w.work_one_job
45
- exception.should == $handled
46
- end
47
-
48
- it "continue working when error handler not defined" do
49
- Creeper.error { |e| $handled = false }
50
- Creeper.job('my.job') { fail }
51
- Creeper.enqueue('my.job')
52
- w = Creeper::Worker.new
53
- w.stub(:exception_message)
54
- w.stub(:log)
55
- w.prepare
56
- w.work_one_job
57
- false.should == $handled
58
- end
59
-
60
- it "exception raised one second before beanstalk ttr reached" do
61
- with_an_error_handler
62
- Creeper.job('my.job') { sleep(3); $handled = "didn't time out" }
63
- Creeper.enqueue('my.job', {}, :ttr => 2)
64
- w = Creeper::Worker.new
65
- w.stub(:exception_message)
66
- w.stub(:log)
67
- w.prepare
68
- w.work_one_job
69
- $handled.should == "didn't time out"
70
- end
6
+ it 'is able to process a real job' do
7
+ pending 'still need to figure out how to test the daemon'
8
+ let(:cli) { Creeper::CLI.instance }
71
9
 
72
- it "before filter gets run first" do
73
- Creeper.before { |name| $flag = "i_was_here" }
74
- Creeper.job('my.job') { |args| $handled = ($flag == 'i_was_here') }
75
- Creeper.enqueue('my.job')
76
- w = Creeper::Worker.new
77
- w.stub(:exception_message)
78
- w.stub(:log)
79
- w.prepare
80
- w.work_one_job
81
- true.should == $handled
82
- end
10
+ before do
11
+ $rd, $wr = IO.pipe
12
+ $rd.sync, $wr.sync = true
13
+ if @pid = fork
14
+ # parent
15
+ $wr.close
16
+ else
17
+ # child
18
+ $rd.close
19
+ cli.parse(['creeper', '-r', './spec/support/fake_env.rb'])
20
+ sleep 5
21
+ begin
22
+ cli.run
23
+ rescue SystemExit
24
+ Process.kill(:KILL, $$)
25
+ end
26
+ end
27
+ end
83
28
 
84
- it "before filter passes the name of the job" do
85
- Creeper.before { |name| $jobname = name }
86
- Creeper.job('my.job') { true }
87
- Creeper.enqueue('my.job')
88
- w = Creeper::Worker.new
89
- w.stub(:exception_message)
90
- w.stub(:log)
91
- w.prepare
92
- w.work_one_job
93
- 'my.job'.should == $jobname
94
- end
29
+ after do
30
+ if @pid
31
+ Process.kill(:TERM, @pid)
32
+ done = nil
33
+ # 8.times do
34
+ # begin
35
+ # Process.getpgid(@pid)
36
+ # rescue Errno::ESRCH
37
+ # done = true
38
+ # break
39
+ # end
40
+ # sleep 1
41
+ # end
42
+ # expect(done).to be_true
43
+ sleep 1
44
+ Process.kill(:KILL, @pid)
45
+ child_pid, status = Process.waitpid2(-1, Process::WNOHANG)
46
+ expect(child_pid).to eq(@pid)
47
+ # expect(status).to be_success
95
48
 
96
- it "before filter can pass an instance var" do
97
- Creeper.before { |name| @foo = "hello" }
98
- Creeper.job('my.job') { |args| $handled = (@foo == "hello") }
99
- Creeper.enqueue('my.job')
100
- w = Creeper::Worker.new
101
- w.stub(:exception_message)
102
- w.stub(:log)
103
- w.prepare
104
- w.work_one_job
105
- true.should == $handled
106
- end
107
-
108
- it "before filter invokes error handler when defined" do
109
- with_an_error_handler
110
- Creeper.before { |name| fail }
111
- Creeper.job('my.job') { }
112
- Creeper.enqueue('my.job', :foo => 123)
113
- w = Creeper::Worker.new
114
- w.stub(:exception_message)
115
- w.stub(:log)
116
- w.prepare
117
- w.work_one_job
118
- $handled.should_not == nil
119
- 'my.job'.should == $job_name
120
- {'foo' => 123}.should == $job_args
121
- end
49
+ $rd.close rescue nil
50
+ $wr.close rescue nil
51
+ end
52
+ end
122
53
 
123
- def with_an_error_handler
124
- Creeper.error do |e, job_name, args|
125
- $handled = e.class
126
- $job_name = job_name
127
- $job_args = args
54
+ it 'is able to process a real job' do
55
+ pending 'still need to figure out how to test the daemon'
56
+ RealWorker.perform_async(1, 2)
57
+ result = nil
58
+ Timeout::timeout(10) do
59
+ result = $rd.read
60
+ end
61
+ expect(result).to eq('[1,2]')
128
62
  end
129
63
  end
130
-
64
+
131
65
  end