creeper 1.0.9 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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