tickwork 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,576 @@
1
+ require File.expand_path('../../lib/tickwork', __FILE__)
2
+ require File.expand_path('../data_stores/fake_store.rb', __FILE__)
3
+ require File.expand_path('../null_logger.rb', __FILE__)
4
+ require "minitest/autorun"
5
+ require 'mocha/mini_test'
6
+ require 'time'
7
+ require 'active_support/time'
8
+
9
+ describe Tickwork::Manager do
10
+ def self.test_order
11
+ :alpha
12
+ end
13
+ before do
14
+ @manager = Tickwork::Manager.new
15
+ @manager.configure do |config|
16
+ config[:data_store] = Tickwork::FakeStore.new
17
+ config[:logger] = NullLogger.new
18
+ end
19
+ class << @manager
20
+ def log(msg); end
21
+ end
22
+ @manager.handler { }
23
+ end
24
+
25
+ def assert_will_run(t)
26
+ if t.is_a? String
27
+ t = Time.parse(t)
28
+ end
29
+ assert_equal 1, @manager.tick(t).size
30
+ end
31
+
32
+ def assert_wont_run(t)
33
+ if t.is_a? String
34
+ t = Time.parse(t)
35
+ end
36
+ assert_equal 0, @manager.tick(t).size
37
+ end
38
+
39
+ it "once a minute" do
40
+ @manager.every(1.minute, 'myjob')
41
+
42
+ assert_will_run(t=Time.now)
43
+ assert_wont_run(t+30)
44
+ assert_will_run(t+60)
45
+ end
46
+
47
+ it "every three minutes" do
48
+ @manager.every(3.minutes, 'myjob')
49
+
50
+ assert_will_run(t=Time.now)
51
+ assert_wont_run(t+2*60)
52
+ assert_will_run(t+3*60)
53
+ end
54
+
55
+ it "once an hour" do
56
+ @manager.every(1.hour, 'myjob')
57
+
58
+ assert_will_run(t=Time.now)
59
+ assert_wont_run(t+30*60)
60
+ assert_will_run(t+60*60)
61
+ end
62
+
63
+ it "once a week" do
64
+ @manager.every(1.week, 'myjob')
65
+
66
+ assert_will_run(t=Time.now)
67
+ assert_wont_run(t+60*60*24*6)
68
+ assert_will_run(t+60*60*24*7)
69
+ end
70
+
71
+ it "won't drift later and later" do
72
+ @manager.every(1.hour, 'myjob')
73
+
74
+ assert_will_run(Time.parse("10:00:00.5"))
75
+ assert_wont_run(Time.parse("10:59:59.999"))
76
+ assert_will_run(Time.parse("11:00:00.0"))
77
+ end
78
+
79
+ it "aborts when no handler defined" do
80
+ manager = Tickwork::Manager.new
81
+ assert_raises(Tickwork::Manager::NoHandlerDefined) do
82
+ manager.every(1.minute, 'myjob')
83
+ end
84
+ end
85
+
86
+ it "aborts when fails to parse" do
87
+ assert_raises(Tickwork::At::FailedToParse) do
88
+ @manager.every(1.day, "myjob", :at => "a:bc")
89
+ end
90
+ end
91
+
92
+ it "general handler" do
93
+ $set_me = 0
94
+ @manager.handler { $set_me = 1 }
95
+ @manager.every(1.minute, 'myjob')
96
+ @manager.tick(Time.now)
97
+ assert_equal 1, $set_me
98
+ end
99
+
100
+ it "event-specific handler" do
101
+ $set_me = 0
102
+ @manager.every(1.minute, 'myjob') { $set_me = 2 }
103
+ @manager.tick(Time.now)
104
+
105
+ assert_equal 2, $set_me
106
+ end
107
+
108
+ it "should pass time to the general handler" do
109
+ received = nil
110
+ now = Time.now
111
+ @manager.handler { |job, time| received = time }
112
+ @manager.every(1.minute, 'myjob')
113
+ @manager.tick(now)
114
+ assert_equal now, received
115
+ end
116
+
117
+ it "should pass time to the event-specific handler" do
118
+ received = nil
119
+ now = Time.now
120
+ @manager.every(1.minute, 'myjob') { |job, time| received = time }
121
+ @manager.tick(now)
122
+ assert_equal now, received
123
+ end
124
+
125
+ it "exceptions are trapped and logged" do
126
+ @manager.handler { raise 'boom' }
127
+ @manager.every(1.minute, 'myjob')
128
+
129
+ mocked_logger = MiniTest::Mock.new
130
+ mocked_logger.expect :error, true, [RuntimeError]
131
+ @manager.configure { |c| c[:logger] = mocked_logger }
132
+ @manager.tick(Time.now)
133
+ mocked_logger.verify
134
+ end
135
+
136
+ it "exceptions still set the last timestamp to avoid spastic error loops" do
137
+ @manager.handler { raise 'boom' }
138
+ event = @manager.every(1.minute, 'myjob')
139
+ @manager.stubs(:log_error)
140
+ @manager.tick(t = Time.now)
141
+ assert_equal t, event.last
142
+ end
143
+
144
+ it "should be configurable" do
145
+ logger = NullLogger.new
146
+ @manager.configure do |config|
147
+ config[:logger] = logger
148
+ config[:max_threads] = 20
149
+ config[:max_ticks] = 21
150
+ config[:tick_size] = 59
151
+ config[:max_catchup] = 3000
152
+ config[:thread] = true
153
+ config[:namespace] = 'superhero'
154
+ end
155
+
156
+ assert_equal logger, @manager.config[:logger]
157
+ assert_equal 20, @manager.config[:max_threads]
158
+ assert_equal 21, @manager.config[:max_ticks]
159
+ assert_equal 59, @manager.config[:tick_size]
160
+ assert_equal 3000, @manager.config[:max_catchup]
161
+ assert_equal true, @manager.config[:thread]
162
+ assert_equal 'superhero', @manager.config[:namespace]
163
+ end
164
+
165
+ it "configuration should have reasonable defaults" do
166
+ @manager = Tickwork::Manager.new
167
+ assert @manager.config[:logger].is_a?(Logger)
168
+ assert_equal 10, @manager.config[:max_threads]
169
+ assert_equal 10, @manager.config[:max_ticks]
170
+ assert_equal 60, @manager.config[:tick_size]
171
+ assert_equal 3600, @manager.config[:max_catchup]
172
+ assert_equal false, @manager.config[:thread]
173
+ assert_equal '_tickwork_', @manager.config[:namespace]
174
+ end
175
+
176
+ it "config raises exception without a datastore" do
177
+ @my_manager = Tickwork::Manager.new
178
+ assert_raises Tickwork::Manager::NoDataStoreDefined do
179
+ @my_manager.configure do |config|
180
+ config[:tick_size] = 10
181
+ end
182
+ end
183
+ end
184
+
185
+ it "run raises exception without a datastore" do
186
+ @my_manager = Tickwork::Manager.new
187
+ assert_raises Tickwork::Manager::NoDataStoreDefined do
188
+ @my_manager.run
189
+ end
190
+ end
191
+
192
+ describe ':at option' do
193
+ it "once a day at 16:20" do
194
+ @manager.every(1.day, 'myjob', :at => '16:20')
195
+
196
+ assert_wont_run 'jan 1 2010 16:19:59'
197
+ assert_will_run 'jan 1 2010 16:20:00'
198
+ assert_wont_run 'jan 1 2010 16:20:01'
199
+ assert_wont_run 'jan 2 2010 16:19:59'
200
+ assert_will_run 'jan 2 2010 16:20:00'
201
+ end
202
+
203
+ it "twice a day at 16:20 and 18:10" do
204
+ @manager.every(1.day, 'myjob', :at => ['16:20', '18:10'])
205
+
206
+ assert_wont_run 'jan 1 2010 16:19:59'
207
+ assert_will_run 'jan 1 2010 16:20:00'
208
+ assert_wont_run 'jan 1 2010 16:20:01'
209
+
210
+ assert_wont_run 'jan 1 2010 18:09:59'
211
+ assert_will_run 'jan 1 2010 18:10:00'
212
+ assert_wont_run 'jan 1 2010 18:10:01'
213
+ end
214
+ end
215
+
216
+ describe ':tz option' do
217
+ it "time zone is not set by default" do
218
+ assert @manager.config[:tz].nil?
219
+ end
220
+
221
+ it "should be able to specify a different timezone than local" do
222
+ @manager.every(1.day, 'myjob', :at => '10:00', :tz => 'UTC')
223
+
224
+ assert_wont_run 'jan 1 2010 10:00:00 EST'
225
+ assert_will_run 'jan 1 2010 10:00:00 UTC'
226
+ end
227
+
228
+ it "should be able to specify a different timezone than local for multiple times" do
229
+ @manager.every(1.day, 'myjob', :at => ['10:00', '8:00'], :tz => 'UTC')
230
+
231
+ assert_wont_run 'jan 1 2010 08:00:00 EST'
232
+ assert_will_run 'jan 1 2010 08:00:00 UTC'
233
+ assert_wont_run 'jan 1 2010 10:00:00 EST'
234
+ assert_will_run 'jan 1 2010 10:00:00 UTC'
235
+ end
236
+
237
+ it "should be able to configure a default timezone to use for all events" do
238
+ @manager.configure { |config| config[:tz] = 'UTC' }
239
+ @manager.every(1.day, 'myjob', :at => '10:00')
240
+
241
+ assert_wont_run 'jan 1 2010 10:00:00 EST'
242
+ assert_will_run 'jan 1 2010 10:00:00 UTC'
243
+ end
244
+
245
+ it "should be able to override a default timezone in an event" do
246
+ @manager.configure { |config| config[:tz] = 'UTC' }
247
+ @manager.every(1.day, 'myjob', :at => '10:00', :tz => 'EST')
248
+
249
+ assert_will_run 'jan 1 2010 10:00:00 EST'
250
+ assert_wont_run 'jan 1 2010 10:00:00 UTC'
251
+ end
252
+ end
253
+
254
+ describe ':if option' do
255
+ it ":if true then always run" do
256
+ @manager.every(1.second, 'myjob', :if => lambda { |_| true })
257
+
258
+ assert_will_run 'jan 1 2010 16:20:00'
259
+ end
260
+
261
+ it ":if false then never run" do
262
+ @manager.every(1.second, 'myjob', :if => lambda { |_| false })
263
+
264
+ assert_wont_run 'jan 1 2010 16:20:00'
265
+ end
266
+
267
+ it ":if the first day of month" do
268
+ @manager.every(1.second, 'myjob', :if => lambda { |t| t.day == 1 })
269
+
270
+ assert_will_run 'jan 1 2010 16:20:00'
271
+ assert_wont_run 'jan 2 2010 16:20:00'
272
+ assert_will_run 'feb 1 2010 16:20:00'
273
+ end
274
+
275
+ it ":if it is compared to a time with zone" do
276
+ tz = 'America/Chicago'
277
+ time = Time.utc(2012,5,25,10,00)
278
+ @manager.every(1.second, 'myjob', tz: tz, :if => lambda { |t|
279
+ ((time - 1.hour)..(time + 1.hour)).cover? t
280
+ })
281
+ assert_will_run time
282
+ end
283
+
284
+ it ":if is not callable then raise ArgumentError" do
285
+ assert_raises(ArgumentError) do
286
+ @manager.every(1.second, 'myjob', :if => true)
287
+ end
288
+ end
289
+ end
290
+
291
+ describe "max_threads" do
292
+ it "should warn when an event tries to generate threads more than max_threads" do
293
+ logger = NullLogger.new
294
+ @manager.configure do |config|
295
+ config[:max_threads] = 1
296
+ config[:logger] = logger
297
+ end
298
+
299
+ @manager.every(1.minute, 'myjob1', :thread => true) { sleep 2 }
300
+ @manager.every(1.minute, 'myjob2', :thread => true) { sleep 2 }
301
+ logger.expects(:error).with("Threads exhausted; skipping myjob2")
302
+
303
+ @manager.tick(Time.now)
304
+ end
305
+
306
+ it "should not warn when thread is managed by others" do
307
+ begin
308
+ t = Thread.new { sleep 5 }
309
+ logger = Logger.new(StringIO.new)
310
+ @manager.configure do |config|
311
+ config[:max_threads] = 1
312
+ config[:logger] = logger
313
+ end
314
+
315
+ @manager.every(1.minute, 'myjob', :thread => true)
316
+ logger.expects(:error).never
317
+
318
+ @manager.tick(Time.now)
319
+ ensure
320
+ t.kill
321
+ end
322
+ end
323
+ end
324
+
325
+ describe "callbacks" do
326
+ it "should not accept unknown callback name" do
327
+ assert_raises(RuntimeError, "Unsupported callback unknown_callback") do
328
+ @manager.on(:unknown_callback) do
329
+ true
330
+ end
331
+ end
332
+ end
333
+
334
+ it "should run before_tick callback once on tick" do
335
+ counter = 0
336
+ @manager.on(:before_tick) do
337
+ counter += 1
338
+ end
339
+ @manager.tick
340
+ assert_equal 1, counter
341
+ end
342
+
343
+ it "should not run events if before_tick returns false" do
344
+ @manager.on(:before_tick) do
345
+ false
346
+ end
347
+ @manager.every(1.second, 'myjob') { raise "should not run" }
348
+ @manager.tick
349
+ end
350
+
351
+ it "should run before_run twice if two events are registered" do
352
+ counter = 0
353
+ @manager.on(:before_run) do
354
+ counter += 1
355
+ end
356
+ @manager.every(1.second, 'myjob')
357
+ @manager.every(1.second, 'myjob2')
358
+ @manager.tick
359
+ assert_equal 2, counter
360
+ end
361
+
362
+ it "should run even jobs only" do
363
+ counter = 0
364
+ ran = false
365
+ @manager.on(:before_run) do
366
+ counter += 1
367
+ counter % 2 == 0
368
+ end
369
+ @manager.every(1.second, 'myjob') { raise "should not ran" }
370
+ @manager.every(1.second, 'myjob2') { ran = true }
371
+ @manager.tick
372
+ assert ran
373
+ end
374
+
375
+ it "should run after_run callback for each event" do
376
+ counter = 0
377
+ @manager.on(:after_run) do
378
+ counter += 1
379
+ end
380
+ @manager.every(1.second, 'myjob')
381
+ @manager.every(1.second, 'myjob2')
382
+ @manager.tick
383
+ assert_equal 2, counter
384
+ end
385
+
386
+ it "should run after_tick callback once" do
387
+ counter = 0
388
+ @manager.on(:after_tick) do
389
+ counter += 1
390
+ end
391
+ @manager.tick
392
+ assert_equal 1, counter
393
+ end
394
+ end
395
+
396
+ it "should start from last tick" do
397
+ @manager.configure do |config|
398
+ config[:tick_size] = 1
399
+ config[:max_ticks] = 1
400
+ end
401
+ last = Time.now.to_i - 1000
402
+ @manager.data_store.set(@manager.data_store_key, last)
403
+ @manager.expects(:tick).with(last + 1).then.returns
404
+ @manager.run
405
+ end
406
+
407
+ it "should tick to max_ticks" do
408
+ @manager.configure do |config|
409
+ config[:tick_size] = 1
410
+ config[:max_ticks] = 3
411
+ end
412
+ last = Time.now.to_i - 1000
413
+ @manager.data_store.set(@manager.data_store_key, last)
414
+ @manager.expects(:tick).with(last + 1).then.returns
415
+ @manager.expects(:tick).with(last + 2).then.returns
416
+ @manager.expects(:tick).with(last + 3).then.returns
417
+ @manager.run
418
+ end
419
+
420
+ it "should tick by tick size" do
421
+ @manager.configure do |config|
422
+ config[:tick_size] = 2
423
+ config[:max_ticks] = 3
424
+ end
425
+ last = Time.now.to_i - 1000
426
+ @manager.data_store.set(@manager.data_store_key, last)
427
+ @manager.expects(:tick).with(last + 2).then.returns
428
+ @manager.expects(:tick).with(last + 4).then.returns
429
+ @manager.expects(:tick).with(last + 6).then.returns
430
+ @manager.run
431
+ end
432
+
433
+ it "should not tick into the future" do
434
+ @manager.configure do |config|
435
+ config[:tick_size] = 10
436
+ config[:max_ticks] = 3
437
+ end
438
+ last = Time.now.to_i - 1
439
+ @manager.data_store.set(@manager.data_store_key, last)
440
+ module Failure
441
+ def tick
442
+ raise "don't call me"
443
+ end
444
+ end
445
+ @manager.extend Failure
446
+ @manager.run
447
+ end
448
+
449
+ it "should save the last tick time" do
450
+ @manager.configure do |config|
451
+ config[:tick_size] = 10
452
+ config[:max_ticks] = 1
453
+ end
454
+ last = Time.now.to_i - 1000
455
+ @manager.data_store.set(@manager.data_store_key, last)
456
+ @manager.expects(:tick).with(last + 10).then.returns
457
+ @manager.run
458
+ assert_equal (last + 10), @manager.data_store.get(@manager.data_store_key)
459
+ end
460
+
461
+ it "should tick from now if no last time" do
462
+ @manager.configure do |config|
463
+ config[:tick_size] = 10
464
+ config[:max_ticks] = 1
465
+ end
466
+ @manager.expects(:tick).with(Time.now.to_i).then.returns
467
+ @manager.run
468
+ end
469
+
470
+ it "should be saving event last run times" do
471
+ @manager.configure do |config|
472
+ config[:tick_size] = 10
473
+ config[:max_ticks] = 1
474
+ end
475
+ @manager.every(1.minute, 'myjob')
476
+ assert_equal 0, @manager.config[:data_store].size
477
+ @manager.run
478
+ assert_equal 2, @manager.config[:data_store].size
479
+ assert_equal false, @manager.config[:data_store].get('_tickwork_myjob').nil?
480
+ end
481
+
482
+ it "should start from max catchup when last is further in the past" do
483
+ @manager.configure do |config|
484
+ config[:tick_size] = 1
485
+ config[:max_ticks] = 1
486
+ config[:max_catchup] = 1800
487
+ end
488
+
489
+ @manager.every(1.minute, 'myjob')
490
+ last = Time.now.to_i - 3600
491
+ @manager.data_store.set(@manager.data_store_key, last)
492
+ @manager.expects(:tick).with(Time.now.to_i - 1800).then.returns
493
+ @manager.run
494
+ end
495
+
496
+ it "0 should disable max catchup" do
497
+ @manager.configure do |config|
498
+ config[:tick_size] = 1
499
+ config[:max_ticks] = 1
500
+ config[:max_catchup] = 0
501
+ end
502
+
503
+ @manager.every(1.minute, 'myjob')
504
+ last = Time.now.to_i - 36000
505
+ @manager.data_store.set(@manager.data_store_key, last)
506
+ @manager.expects(:tick).with(Time.now.to_i - 36000 + 1).then.returns
507
+ @manager.run
508
+ end
509
+
510
+ it "0 should disable max catchup" do
511
+ @manager.configure do |config|
512
+ config[:tick_size] = 1
513
+ config[:max_ticks] = 1
514
+ config[:max_catchup] = nil
515
+ end
516
+
517
+ @manager.every(1.minute, 'myjob')
518
+ last = Time.now.to_i - 36000
519
+ @manager.data_store.set(@manager.data_store_key, last)
520
+ @manager.expects(:tick).with(Time.now.to_i - 36000 + 1).then.returns
521
+ @manager.run
522
+ end
523
+
524
+ it "should return the last time it ran" do
525
+ @manager.configure do |config|
526
+ config[:tick_size] = 10
527
+ config[:max_ticks] = 2
528
+ end
529
+ last = Time.now.to_i - 1000
530
+ @manager.data_store.set(@manager.data_store_key, last)
531
+ @manager.expects(:tick).with(last + 10).then.returns
532
+ @manager.expects(:tick).with(last + 20).then.returns
533
+ assert_equal last + 20, @manager.run
534
+ end
535
+
536
+ it "should clear it's datastore on #clear!" do
537
+ @manager.data_store.set(@manager.data_store_key, "10")
538
+ @manager.clear!
539
+ assert_equal nil, @manager.data_store.get(@manager.data_store_key)
540
+ end
541
+
542
+ describe 'error_handler' do
543
+ before do
544
+ @errors = []
545
+ @manager.error_handler do |e|
546
+ @errors << e
547
+ end
548
+
549
+ # block error log
550
+ @string_io = StringIO.new
551
+ @manager.configure do |config|
552
+ config[:logger] = Logger.new(@string_io)
553
+ end
554
+ @manager.every(1.second, 'myjob') { raise 'it error' }
555
+ end
556
+
557
+ it 'registered error_handler handles error from event' do
558
+ @manager.tick
559
+ assert_equal ['it error'], @errors.map(&:message)
560
+ end
561
+
562
+ it 'error is notified to logger and handler' do
563
+ @manager.tick
564
+ assert @string_io.string.include?('it error')
565
+ end
566
+
567
+ it 'error in handler will NOT be suppressed' do
568
+ @manager.error_handler do |e|
569
+ raise e.message + ' re-raised'
570
+ end
571
+ assert_raises(RuntimeError, 'it error re-raised') do
572
+ @manager.tick
573
+ end
574
+ end
575
+ end
576
+ end
@@ -0,0 +1,19 @@
1
+ # https://github.com/karafka/null-logger/blob/master/lib/null_logger.rb
2
+ # under MIT license as of 5/9/2016
3
+
4
+ # Null logger class
5
+ # Is used when logger is not defined
6
+ class NullLogger
7
+ # Possible log levels from ruby Logger::Severity class
8
+ LOG_LEVELS = %w( unknown fatal error warn info debug ).freeze
9
+
10
+ # Returns nil for any method call from LOG_LEVELS array
11
+ # Instead raise NoMethodError
12
+ # @example:
13
+ # NullLogger.new.fatal -> return nil
14
+ # NullLogger.new.wrong_method -> raise NoMethodError
15
+ def method_missing(method_name, *args, &block)
16
+ return nil if LOG_LEVELS.include?(method_name.to_s)
17
+ super(method_name, *args, &block)
18
+ end
19
+ end
@@ -0,0 +1,91 @@
1
+ require File.expand_path('../../lib/tickwork', __FILE__)
2
+ require File.expand_path('../data_stores/fake_store.rb', __FILE__)
3
+ require 'minitest/autorun'
4
+ require 'mocha/mini_test'
5
+
6
+ describe Tickwork do
7
+ def self.test_order
8
+ :alpha
9
+ end
10
+ before do
11
+ @log_output = StringIO.new
12
+ Tickwork.configure do |config|
13
+ config[:logger] = Logger.new(@log_output)
14
+ #config[:logger] = Logger.new(STDOUT)
15
+ config[:data_store] = Tickwork::FakeStore.new
16
+ end
17
+ end
18
+
19
+ after do
20
+ Tickwork.clear!
21
+ end
22
+
23
+ it 'should run events with configured logger' do
24
+ run = false
25
+ Tickwork.handler do |job|
26
+ run = job == 'myjob'
27
+ end
28
+ Tickwork.every(1.minute, 'myjob')
29
+ # don't know why this doesn't work with while but did with loop
30
+ #Tickwork.manager.expects(:while).yields.then.returns
31
+ Tickwork.run
32
+
33
+ assert run
34
+ assert @log_output.string.include?('Triggering')
35
+ end
36
+
37
+ it 'should log event correctly' do
38
+ run = false
39
+ Tickwork.handler do |job|
40
+ run = job == 'an event'
41
+ end
42
+ Tickwork.every(1.minute, 'an event')
43
+ # Tickwork.manager.expects(:while).yields.then.returns
44
+ Tickwork.run
45
+ assert run
46
+ assert @log_output.string.include?("Triggering 'an event'")
47
+ end
48
+
49
+ it 'should pass event without modification to handler' do
50
+ event_object = 'myEvent'
51
+ run = false
52
+ Tickwork.handler do |job|
53
+ run = job == event_object
54
+ end
55
+ Tickwork.every(1.minute, event_object)
56
+ # Tickwork.manager.expects(:while).yields.then.returns
57
+ Tickwork.run
58
+ assert run
59
+ end
60
+
61
+ it 'should not run anything after reset' do
62
+ Tickwork.every(1.minute, 'myjob') { }
63
+ Tickwork.clear!
64
+ Tickwork.configure do |config|
65
+ config[:sleep_timeout] = 0
66
+ config[:logger] = Logger.new(@log_output)
67
+ config[:data_store] = Tickwork::FakeStore.new
68
+ end
69
+ # Tickwork.manager.expects(:while).yields.then.returns
70
+ Tickwork.run
71
+ assert @log_output.string.include?('0 events')
72
+ end
73
+
74
+ it 'should pass all arguments to every' do
75
+ Tickwork.every(1.second, 'myjob', if: lambda { |_| false }) { }
76
+ # Tickwork.manager.expects(:while).yields.then.returns
77
+ Tickwork.run
78
+ assert @log_output.string.include?('1 events')
79
+ assert !@log_output.string.include?('Triggering')
80
+ end
81
+
82
+ it 'support module re-open style' do
83
+ $called = false
84
+ module ::Tickwork
85
+ every(1.second, 'myjob') { $called = true }
86
+ end
87
+ # Tickwork.manager.expects(:while).yields.then.returns
88
+ Tickwork.run
89
+ assert $called
90
+ end
91
+ end
@@ -0,0 +1,28 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "tickwork"
3
+ s.version = "0.0.1"
4
+
5
+ s.authors = ["John Hinnegan"]
6
+ s.license = 'MIT'
7
+ s.description = "A fork of clockwork. Under development."
8
+ s.email = ["tickwork@johnhinnegan.com"]
9
+ s.extra_rdoc_files = [
10
+ "README.md"
11
+ ]
12
+ s.homepage = "http://github.com/softwaregravy/clockwork"
13
+ s.summary = "A scheduling library"
14
+
15
+ s.files = `git ls-files`.split($/)
16
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency(%q<tzinfo>)
21
+ s.add_dependency(%q<activesupport>)
22
+
23
+ s.add_development_dependency "bundler", "~> 1.3"
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "daemons"
26
+ s.add_development_dependency "minitest", "~> 5.8"
27
+ s.add_development_dependency "mocha"
28
+ end