moment 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,5 @@
1
+ This is a scheduling system in pure ruby. It runs jobs at specified intervals.
2
+ It has a server component that you can interface with via DRb, which makes
3
+ admining it from a Rails environment easy.
4
+
5
+ See Moment for more documentation.
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/ruby
2
+
3
+ #
4
+ # == Synopsis
5
+ #
6
+ # moment_server: scheduling server, accessible via DRb
7
+ #
8
+ # $ moment_server -p 9901 saved_jobs
9
+ # Loading previous jobs from saved_jobs..
10
+ # Loaded 0 jobs:
11
+ # []
12
+ # Starting service on druby://localhost:9901 ...
13
+ # Ready.<Ctrl-C>
14
+ # Saving 0 jobs to saved_jobs..
15
+ # Exiting..
16
+ #
17
+ # == Usage
18
+ #
19
+ # moment_server [@options] [job_file]
20
+ #
21
+ # -h, --help:
22
+ # show help
23
+ #
24
+ # -p, --port: (default 9000)
25
+ # port to run druby instance on
26
+ #
27
+ # -q, --[no-]quiet: (default false)
28
+ # run verbosely
29
+ #
30
+ # job_file
31
+ # if specified, will save still running jobs in the given file on
32
+ # exit to be read in again on next start.
33
+ #
34
+
35
+ require 'rubygems'
36
+ require 'moment'
37
+ require 'drb'
38
+ require 'ostruct'
39
+ require 'optparse'
40
+ require 'rdoc/usage'
41
+
42
+ @options = OpenStruct.new :port => 9000, :quiet => false, :file => nil
43
+ OptionParser.new do |o|
44
+ o.on '-p', '--port [port]', Integer do |port| @options.port = port end
45
+ o.on '-q', '--[no-]quiet' do |quiet| @options.quiet = quiet end
46
+ o.on '-h', '--help' do
47
+ RDoc::usage
48
+ exit
49
+ end
50
+ end.order! do |file|
51
+ @options.file ||= file
52
+ end
53
+
54
+ def putsv(*args)
55
+ puts args unless @options.quiet
56
+ end
57
+
58
+ url = "druby://localhost:#{@options.port}"
59
+ server = Moment::Server.new
60
+
61
+ unless @options.file.nil? or !File.exists?(@options.file)
62
+ putsv "Loading previous jobs from #{@options.file}.."
63
+ server.load(File.open(@options.file))
64
+ putsv "Loaded #{server.jobs.size} jobs:", server.jobs.inspect
65
+ end
66
+
67
+ server.run
68
+
69
+ putsv "Starting service on #{url} ..."
70
+ DRb.start_service(url, server)
71
+ begin
72
+ putsv "Ready."
73
+ DRb.thread.join
74
+ rescue Interrupt => e
75
+ if @options.file
76
+ putsv "Saving #{server.jobs.size} jobs to #{@options.file}.."
77
+ server.dump(File.open(@options.file, 'w'))
78
+ end
79
+
80
+ putsv "Exiting.."
81
+ end
@@ -0,0 +1,24 @@
1
+ require 'drb'
2
+ require 'shell_job'
3
+ require 'simple_trigger'
4
+
5
+ class Printer
6
+
7
+ include DRbUndumped
8
+ attr_accessor :name, :counter
9
+
10
+ def initialize(name = nil)
11
+ self.name = name
12
+ self.counter = 0
13
+ end
14
+
15
+ def execute
16
+ puts self.inspect, Time.now
17
+ @counter += 1
18
+ end
19
+
20
+ end
21
+
22
+ DRb.start_service
23
+ scheduler = DRbObject.new(nil, 'druby://localhost:9000')
24
+ scheduler.schedule(Moment::ShellJob.new('ls'), Moment::SimpleTrigger.new(Time.now, Time.now + 10, 2))
@@ -0,0 +1,161 @@
1
+ require File.dirname(__FILE__) + '/moment'
2
+ require File.dirname(__FILE__) + '/trigger'
3
+
4
+ class Moment::CronTrigger < Moment::Trigger
5
+
6
+ attr_reader :sec, :min, :hour, :day, :month, :wday, :year, :cron_expr
7
+
8
+ def initialize(expr)
9
+ super()
10
+ self.cron_expr = expr
11
+ end
12
+
13
+ def cron_expr=(expr)
14
+ @cron_expr = expr
15
+ self.sec, self.min, self.hour, self.day, self.month, self.wday, self.year = @cron_expr.split(' ')
16
+ #puts inspect
17
+ end
18
+
19
+ def fire_time_after(time)
20
+ sec, min, hour, day, month, year, wday, yday, isdst, zone = time.to_a
21
+
22
+ loop do
23
+ # year
24
+ unless @year.nil? or @year.include?(year)
25
+ return nil if year > @year.max
26
+ year = @year.detect do |y| y > year end # next allowable year
27
+ end
28
+
29
+ # month
30
+ unless @month.include?(month)
31
+ # next allowable month
32
+ next_month = @month.detect(lambda { @month.min }) do |m| m > month end
33
+ # reset everything lower
34
+ day, hour, min, sec = @day.min, @hour.min, @min.min, @sec.min
35
+ # carry case
36
+ if next_month < month
37
+ month = next_month
38
+ year += 1
39
+ retry
40
+ end
41
+ month = next_month
42
+ end
43
+
44
+ # day
45
+ month_days = (1 .. month_days(year, month))
46
+ days = @day.select do |d| month_days === d end
47
+ unless days.include?(day)
48
+ next_day = days.detect(lambda { days.min }) do |d| d > day end
49
+ hour, min, sec = @hour.min, @min.min, @sec.min
50
+ if next_day.nil? or next_day < day
51
+ day = next_day.nil? ? @day.min : next_day
52
+ month += 1
53
+ retry
54
+ end
55
+ day = next_day
56
+ end
57
+
58
+ # hour
59
+ unless @hour.include?(hour)
60
+ next_hour = @hour.detect(lambda { @hour.min }) do |h| h > hour end
61
+ min, sec = @min.min, @sec.min
62
+ if next_hour < hour
63
+ hour = next_hour
64
+ day += 1
65
+ retry
66
+ end
67
+ hour = next_hour
68
+ end
69
+
70
+ # min
71
+ unless @min.include?(min)
72
+ next_min = @min.detect(lambda { @min.min }) do |m| m > min end
73
+ sec = @sec.min
74
+ if next_min < min
75
+ min = next_min
76
+ hour += 1
77
+ retry
78
+ end
79
+ min = next_min
80
+ end
81
+
82
+ # sec
83
+ unless @sec.include?(sec)
84
+ next_sec = @sec.detect(lambda { @sec.min }) do |s| s > sec end
85
+ if next_sec < sec
86
+ sec = next_sec
87
+ min += 1
88
+ retry
89
+ end
90
+ sec = next_sec
91
+ end
92
+
93
+ break
94
+ end
95
+
96
+ Time.local sec, min, hour, day, month, year, wday, yday, isdst, zone
97
+ end
98
+
99
+ # TODO: mimic attr_reader to define all of these
100
+ def sec=(sec)
101
+ @sec = parse_part(sec, 0 .. 59)
102
+ end
103
+
104
+ def min=(min)
105
+ @min = parse_part(min, 0 .. 59)
106
+ end
107
+
108
+ def hour=(hour)
109
+ @hour = parse_part(hour, 0 .. 23)
110
+ end
111
+
112
+ def day=(day)
113
+ @day = parse_part(day, 1 .. 31)
114
+ end
115
+
116
+ def month=(month)
117
+ @month = parse_part(month, 1 .. 12)
118
+ end
119
+
120
+ def year=(year)
121
+ @year = parse_part(year)
122
+ end
123
+
124
+ def wday=(wday)
125
+ @wday = parse_part(wday, 0 .. 6)
126
+ end
127
+
128
+ LeapYearMonthDays = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
129
+ CommonYearMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
130
+ private
131
+ def month_days(y, m)
132
+ if ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)
133
+ LeapYearMonthDays[m-1]
134
+ else
135
+ CommonYearMonthDays[m-1]
136
+ end
137
+ end
138
+
139
+ # 0-5,8,10; 0-5; *; */5
140
+ def parse_part(part, range=nil)
141
+ return range if part.nil? or part == '*' or part =~ /[*0]\/1/
142
+
143
+ r = Array.new
144
+ part.split(',').each do |p|
145
+ if p =~ /-/ # 0-5
146
+ r << Range.new(*p.scan(/\d+/)).to_a.map do |x| x.to_i end
147
+ elsif p =~ /(\*|\d+)\/(\d+)/ and not range.nil? # */5, 2/10
148
+ min = $1 == '*' ? 0 : $1.to_i
149
+ inc = $2.to_i
150
+ (min .. range.end).each_with_index do |x, i|
151
+ r << x if i % inc == 0
152
+ end
153
+ else
154
+ r << p.to_i
155
+ end
156
+ end
157
+
158
+ r.flatten
159
+ end
160
+
161
+ end
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/moment'
2
+
3
+ class Moment::Job
4
+
5
+ def execute
6
+ puts "Implement me"
7
+ end
8
+
9
+ end
@@ -0,0 +1,70 @@
1
+ #
2
+ # == Moment. a scheduler.
3
+ #
4
+ # Author:: visnup <visnux@swivel.com>
5
+ # Started:: 8 March 2006
6
+ # Copyright:: Copyright (c) 2006 Swivel, LLC
7
+ # License:: Ruby License
8
+ #
9
+ # i just ate some doritos and need to drink more water.
10
+ #
11
+ # === Introduction
12
+ #
13
+ # Moment is a scheduling service that handles running given jobs at specified
14
+ # intervals.
15
+ #
16
+ # === Features
17
+ #
18
+ # Built-in triggers include a cron implementation (CronTrigger) and simple
19
+ # reptition (SimpleTrigger). Users-written triggers are of course supported by
20
+ # extending Trigger. A Server is also provided that handles multithreading.
21
+ # There is also a seperate executable +moment_server+ that can be run and
22
+ # scheduled to via DRb. Built-in job types include a shell execution job
23
+ # (ShellJob), or you can extend Job.
24
+ #
25
+ # === Example
26
+ #
27
+ # require 'rubygems'
28
+ # require 'moment'
29
+ # require 'drb'
30
+ #
31
+ # class Printer
32
+ #
33
+ # include DRbUndumped
34
+ # attr_accessor :name, :counter
35
+ #
36
+ # def initialize(name = nil)
37
+ # self.name = name
38
+ # self.counter = 0
39
+ # end
40
+ #
41
+ # def execute
42
+ # puts self.inspect, Time.now
43
+ # @counter += 1
44
+ # end
45
+ #
46
+ # end
47
+ #
48
+ # DRb.start_service
49
+ # scheduler = DRbObject.new(nil, 'druby://localhost:9901')
50
+ # scheduler.schedule(Moment::ShellJob.new('ls'),
51
+ # Moment::SimpleTrigger.new(Time.now, Time.now + 10, 2)) # from now till 10 seconds from now, every 2 seconds
52
+ # scheduler.schedule(Moment::ShellJob.new('date'),
53
+ # Moment::CronTrigger.new('0 0/5 * * 3,5') # every 5 minutes during March and May
54
+ #
55
+ # === Server
56
+ #
57
+ # The above example assumes the included server +moment_server+ is running on
58
+ # port 9901. See the documentation on running +moment_server+.
59
+ #
60
+
61
+ module Moment
62
+ end
63
+
64
+ require File.dirname(__FILE__) + '/cron_trigger.rb'
65
+ require File.dirname(__FILE__) + '/job.rb'
66
+ require File.dirname(__FILE__) + '/scheduler.rb'
67
+ require File.dirname(__FILE__) + '/server.rb'
68
+ require File.dirname(__FILE__) + '/shell_job.rb'
69
+ require File.dirname(__FILE__) + '/simple_trigger.rb'
70
+ require File.dirname(__FILE__) + '/trigger.rb'
@@ -0,0 +1,78 @@
1
+ require File.dirname(__FILE__) + '/moment'
2
+
3
+ class Moment::Scheduler
4
+
5
+ Event = Struct.new(:job, :trigger)
6
+
7
+ attr_accessor :exit_on_idle
8
+ attr_reader :jobs
9
+
10
+ def initialize(exit_on_idle = true)
11
+ self.exit_on_idle = exit_on_idle
12
+ @jobs = Array.new
13
+ @now = Time.now
14
+ end
15
+
16
+ def schedule(job, trigger = nil)
17
+ job_id = @jobs.size
18
+ @jobs[job_id] = Event.new(job, trigger)
19
+
20
+ job_id
21
+ end
22
+
23
+ def unschedule(job_id)
24
+ @jobs.delete_at(job_id)
25
+ end
26
+
27
+ def clean_up
28
+ @jobs.delete_if do |entry| entry.trigger.fire_time_after(@now).nil? end
29
+ end
30
+
31
+ def run
32
+ loop do
33
+ # find the next firing triggers
34
+ todo = next_jobs
35
+ if todo.empty? # nothing to do, so we wait
36
+ break if @exit_on_idle
37
+ sleep
38
+ retry # check again if we're woken up
39
+ end
40
+
41
+ # sleep until the next event; if we get woken up, retry from the start
42
+ pause_time = todo.first.trigger.fire_time_after(@now) - Time.now
43
+ retry if (pause_time > 0 and sleep(pause_time) < pause_time)
44
+
45
+ todo.each do |entry|
46
+ next unless @jobs.index(entry) # make sure since we were sleeping
47
+ entry.job.execute rescue puts $!
48
+ end
49
+
50
+ # make sure next call to next_jobs won't return the exact same result
51
+ sleep 0.5 # TODO this is dangerous; could skip over some jobs
52
+ end
53
+ end
54
+
55
+ # find the next wakeup triggers in our job/trigger list
56
+ def next_jobs
57
+ @now = Time.now
58
+ earliest = nil
59
+ jobs = Array.new
60
+
61
+ @jobs.each do |entry|
62
+ job, trigger = entry.job, entry.trigger
63
+ time = trigger.fire_time_after(@now)
64
+ case
65
+ when time.nil?
66
+ # do nothing
67
+ when earliest.nil?, time < earliest
68
+ earliest = time
69
+ jobs = [ entry ]
70
+ when time == earliest
71
+ jobs << entry
72
+ end
73
+ end
74
+
75
+ jobs
76
+ end
77
+
78
+ end # class Moment::Scheduler
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/moment'
2
+ require File.dirname(__FILE__) + '/scheduler'
3
+ require File.dirname(__FILE__) + '/trigger'
4
+ require File.dirname(__FILE__) + '/job'
5
+ require File.dirname(__FILE__) + '/shell_job'
6
+ require File.dirname(__FILE__) + '/simple_trigger'
7
+ require File.dirname(__FILE__) + '/cron_trigger'
8
+
9
+ class Moment::Server < Moment::Scheduler
10
+
11
+ def initialize
12
+ super(false) # don't exit on idle
13
+ @threads = Array.new
14
+ end
15
+
16
+ def run
17
+ @threads << Thread.new do
18
+ super
19
+ end
20
+ end
21
+
22
+ def schedule(job, trigger)
23
+ puts 'scheduling:', job.inspect, trigger.inspect
24
+ retval = super
25
+ @threads.each do |t| t.wakeup end
26
+ retval
27
+ end
28
+
29
+ def dump(file)
30
+ file << Marshal.dump(@jobs)
31
+ end
32
+
33
+ def load(file)
34
+ @jobs = Marshal.load(file.read)
35
+ rescue ArgumentError
36
+ # ignore if the file is empty
37
+ end
38
+
39
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/job'
2
+
3
+ class Moment::ShellJob < Moment::Job
4
+
5
+ attr_accessor :command
6
+ attr_reader :last_result
7
+
8
+ def initialize(command)
9
+ self.command = command
10
+ @last_result = nil
11
+ end
12
+
13
+ def execute
14
+ @last_result = `#{command}`
15
+ end
16
+
17
+ end
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/moment'
2
+ require File.dirname(__FILE__) + '/trigger'
3
+
4
+ class Moment::SimpleTrigger < Moment::Trigger
5
+
6
+ attr_accessor :start_time, :end_time, :repeat_interval
7
+
8
+ def initialize(start_time = nil, end_time = nil, repeat_interval = nil)
9
+ super()
10
+ self.start_time = start_time
11
+ self.end_time = end_time
12
+ self.repeat_interval = repeat_interval
13
+ end
14
+
15
+ def fire_time_after(time)
16
+ @start_time = time if not @start_time
17
+
18
+ case
19
+ when end_time && time > end_time
20
+ nil
21
+ when time < start_time
22
+ start_time
23
+ when repeat_interval != nil && repeat_interval > 0
24
+ time + repeat_interval - ((time - start_time) % repeat_interval)
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/moment'
2
+
3
+ class Moment::Trigger
4
+
5
+ def fire_time_after(time)
6
+ nil
7
+ end
8
+
9
+ end
@@ -0,0 +1,105 @@
1
+
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/cron_trigger'
4
+
5
+ class CronTriggerTest < Test::Unit::TestCase
6
+
7
+ def test_create
8
+ expr = '0 0 0 * *'
9
+ cron = Moment::CronTrigger.new(expr)
10
+ assert_equal(expr, cron.cron_expr)
11
+ end
12
+
13
+ def test_explicit_no_carry
14
+ input = Time.local(0, 0, 0, 1, 1, 2004, nil, nil, false, 'UTC')
15
+ cron = Moment::CronTrigger.new('10 5 4 3 2')
16
+ expected = Time.local(10, 5, 4, 3, 2, 2004, nil, nil, false, 'UTC')
17
+ assert_equal(expected, cron.fire_time_after(input))
18
+ end
19
+
20
+ def test_explicit_no_carry_day
21
+ input = Time.local(0, 0, 0, 1, 1, 2004, nil, nil, false, 'UTC')
22
+ cron = Moment::CronTrigger.new('10 5 4 3 1')
23
+ expected = Time.local(10, 5, 4, 3, 1, 2004, nil, nil, false, 'UTC')
24
+ assert_equal(expected, cron.fire_time_after(input))
25
+ end
26
+
27
+ def test_explicit_no_carry_hour
28
+ input = Time.local(0, 0, 0, 1, 1, 2004, nil, nil, false, 'UTC')
29
+ cron = Moment::CronTrigger.new('10 5 4 1 1')
30
+ expected = Time.local(10, 5, 4, 1, 1, 2004, nil, nil, false, 'UTC')
31
+ assert_equal(expected, cron.fire_time_after(input))
32
+ end
33
+
34
+ def test_explicit_no_carry_min
35
+ input = Time.local(0, 0, 0, 1, 1, 2004, nil, nil, false, 'UTC')
36
+ cron = Moment::CronTrigger.new('10 5 0 1 1')
37
+ expected = Time.local(10, 5, 0, 1, 1, 2004, nil, nil, false, 'UTC')
38
+ assert_equal(expected, cron.fire_time_after(input))
39
+ end
40
+
41
+ def test_explicit_with_carry
42
+ input = Time.local(0, 1, 23, 1, 1, 2004, nil, nil, false, 'UTC')
43
+ cron = Moment::CronTrigger.new('0 0 23 1 1')
44
+ expected = Time.local(0, 0, 23, 1, 1, 2005, nil, nil, false, 'UTC')
45
+ assert_equal(expected, cron.fire_time_after(input))
46
+ end
47
+
48
+ def test_implicit_with_carry
49
+ input = Time.local(0, 1, 23, 1, 1, 2004, nil, nil, false, 'UTC')
50
+ cron = Moment::CronTrigger.new('0 0 * * *')
51
+ expected = Time.local(0, 0, 0, 2, 1, 2004, nil, nil, false, 'UTC')
52
+ assert_equal(expected, cron.fire_time_after(input))
53
+ end
54
+
55
+ def test_year_before
56
+ input = Time.local(0, 1, 23, 1, 1, 2004, nil, nil, false, 'UTC')
57
+ cron = Moment::CronTrigger.new('0 15 10 * * * 2003')
58
+ expected = nil
59
+ assert_equal(expected, cron.fire_time_after(input))
60
+ end
61
+
62
+ def test_year_after
63
+ input = Time.local(0, 1, 23, 1, 1, 2004, nil, nil, false, 'UTC')
64
+ cron = Moment::CronTrigger.new('0 15 10 * * * 2005')
65
+ expected = Time.local(0, 15, 10, 2, 1, 2005, nil, nil, false, 'UTC')
66
+ assert_equal(expected, cron.fire_time_after(input))
67
+ end
68
+
69
+ def test_month_over
70
+ input = Time.local(0, 1, 23, 2, 12, 2004, nil, nil, false, 'UTC')
71
+ cron = Moment::CronTrigger.new('0 15 10 1 * * *')
72
+ expected = Time.local(0, 15, 10, 1, 1, 2005, nil, nil, false, 'UTC')
73
+ assert_equal(expected, cron.fire_time_after(input))
74
+ end
75
+
76
+ def test_day_over
77
+ input = Time.local(0, 1, 23, 30, 11, 2004, nil, nil, false, 'UTC')
78
+ cron = Moment::CronTrigger.new('* * * 31 * * *')
79
+ expected = Time.local(0, 0, 0, 31, 12, 2004, nil, nil, false, 'UTC')
80
+ assert_equal(expected, cron.fire_time_after(input))
81
+ end
82
+
83
+ def test_min_over
84
+ input = Time.local(2, 59, 12, 30, 11, 2004, nil, nil, false, 'UTC')
85
+ cron = Moment::CronTrigger.new('1 * * * * * *')
86
+ expected = Time.local(1, 0, 13, 30, 11, 2004, nil, nil, false, 'UTC')
87
+ assert_equal(expected, cron.fire_time_after(input))
88
+ end
89
+
90
+ def test_range
91
+ input0 = Time.local(2, 59, 12, 30, 11, 2004, nil, nil, false, 'UTC')
92
+ cron = Moment::CronTrigger.new('28/5,59 1-4,6,20 */1 * 5,0/1 * *')
93
+ assert_equal([28,33,38,43,48,53,58,59], cron.sec)
94
+ assert_equal([1,2,3,4,6,20], cron.min)
95
+ assert_equal((0 .. 23), cron.hour)
96
+ assert_equal((1 .. 12), cron.month)
97
+
98
+ expected0 = Time.local(28, 1, 13, 30, 11, 2004, nil, nil, false, 'UTC')
99
+ input1 = Time.local(29, 1, 13, 30, 11, 2004, nil, nil, false, 'UTC')
100
+ expected1 = Time.local(33, 1, 13, 30, 11, 2004, nil, nil, false, 'UTC')
101
+ assert_equal(expected0, cron.fire_time_after(input0))
102
+ assert_equal(expected1, cron.fire_time_after(input1))
103
+ end
104
+
105
+ end
@@ -0,0 +1,13 @@
1
+
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/job'
4
+
5
+ class JobTest < Test::Unit::TestCase
6
+
7
+ def test_execute
8
+ job = Moment::Job.new
9
+ assert_respond_to(job, :execute)
10
+ job.execute
11
+ end
12
+
13
+ end
@@ -0,0 +1,9 @@
1
+ require 'test/unit'
2
+
3
+ require File.dirname(__FILE__) + '/cron_trigger_test'
4
+ require File.dirname(__FILE__) + '/job_test'
5
+ require File.dirname(__FILE__) + '/scheduler_test'
6
+ require File.dirname(__FILE__) + '/server_test'
7
+ require File.dirname(__FILE__) + '/shell_job_test'
8
+ require File.dirname(__FILE__) + '/simple_trigger_test'
9
+ require File.dirname(__FILE__) + '/trigger_test'
@@ -0,0 +1,64 @@
1
+
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/scheduler'
4
+ require File.dirname(__FILE__) + '/../lib/simple_trigger'
5
+ require File.dirname(__FILE__) + '/../lib/job'
6
+
7
+ class SchedulerTest < Test::Unit::TestCase
8
+
9
+ def test_initialize
10
+ scheduler = Moment::Scheduler.new
11
+ assert_equal([], scheduler.jobs)
12
+ end
13
+
14
+ class CountExecuted < Moment::Job
15
+ attr_reader :executed
16
+ def initialize
17
+ @executed = 0
18
+ end
19
+ def execute
20
+ @executed += 1
21
+ end
22
+ end
23
+
24
+ def test_schedule
25
+ scheduler = Moment::Scheduler.new
26
+ simple = Moment::SimpleTrigger.new(Time.now+1, Time.now+2, nil)
27
+ job = CountExecuted.new
28
+
29
+ scheduler.schedule(job, simple)
30
+ scheduler.schedule(job, simple)
31
+ scheduler.run
32
+
33
+ assert_not_equal(0, job.executed)
34
+ end
35
+
36
+ def test_unschedule
37
+ scheduler = Moment::Scheduler.new
38
+ simple = Moment::SimpleTrigger.new(nil, nil, 1)
39
+ job = CountExecuted.new
40
+
41
+ job_id = scheduler.schedule(job, simple)
42
+
43
+ assert_equal(1, scheduler.jobs.size)
44
+ assert_equal(Moment::Scheduler::Event.new(job, simple),
45
+ scheduler.unschedule(job_id))
46
+ assert_equal(0, scheduler.jobs.size)
47
+ end
48
+
49
+ def test_cleanup
50
+ scheduler = Moment::Scheduler.new
51
+ dead = Moment::SimpleTrigger.new(nil, Time.now-2, 1)
52
+ alive = Moment::SimpleTrigger.new(nil, nil, 1)
53
+
54
+ scheduler.schedule(Moment::Job.new, dead)
55
+ scheduler.schedule(Moment::Job.new, alive)
56
+
57
+ scheduler.clean_up
58
+
59
+ assert_equal(1, scheduler.jobs.size)
60
+ assert_equal(alive, scheduler.jobs.first[:trigger])
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,53 @@
1
+
2
+ require 'test/unit'
3
+ require 'stringio'
4
+ require File.dirname(__FILE__) + '/../lib/server'
5
+ require File.dirname(__FILE__) + '/../lib/simple_trigger'
6
+ require File.dirname(__FILE__) + '/../lib/job'
7
+
8
+ class ServerTest < Test::Unit::TestCase
9
+
10
+ def test_initialize
11
+ server = Moment::Server.new
12
+ assert_equal([], server.jobs)
13
+ end
14
+
15
+ class CountExecuted < Moment::Job
16
+ attr_reader :executed
17
+ def initialize
18
+ @executed = 0
19
+ end
20
+ def execute
21
+ @executed += 1
22
+ end
23
+ end
24
+
25
+ def test_threading
26
+ scheduler = Moment::Server.new
27
+ simple = Moment::SimpleTrigger.new(Time.now, nil, 1)
28
+ job = CountExecuted.new
29
+
30
+ scheduler.run # start running first
31
+ scheduler.schedule(job, simple)
32
+ sleep 3 # make sure to wait for the job to run at least once
33
+
34
+ assert_not_equal(0, job.executed)
35
+ end
36
+
37
+ def test_serialization
38
+ scheduler = Moment::Server.new
39
+ scheduler.schedule(CountExecuted.new, Moment::SimpleTrigger.new(nil, nil, 1))
40
+ file = StringIO.new
41
+ scheduler.dump(file)
42
+ assert_not_equal(0, file.size)
43
+ old_jobs = scheduler.jobs
44
+ assert_not_equal(0, scheduler.jobs.size)
45
+
46
+ file.rewind
47
+ scheduler = Moment::Server.new
48
+ assert_equal(0, scheduler.jobs.size)
49
+ scheduler.load(file)
50
+ assert_equal(old_jobs.size, scheduler.jobs.size)
51
+ end
52
+
53
+ end
@@ -0,0 +1,19 @@
1
+
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/shell_job'
4
+
5
+ class ShellJobTest < Test::Unit::TestCase
6
+
7
+ def test_initialize
8
+ job = Moment::ShellJob.new('cmd')
9
+ assert_not_nil(job)
10
+ assert_equal('cmd', job.command)
11
+ end
12
+
13
+ def test_execute
14
+ job = Moment::ShellJob.new('ls')
15
+ job.execute
16
+ assert_equal(`ls`, job.last_result)
17
+ end
18
+
19
+ end
@@ -0,0 +1,16 @@
1
+
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/simple_trigger'
4
+
5
+ class SimpleTriggerTest < Test::Unit::TestCase
6
+
7
+ def test_create
8
+ trig = Moment::SimpleTrigger.new
9
+ assert_not_nil(trig)
10
+ end
11
+
12
+ def test_start_time
13
+ trig = Moment::SimpleTrigger.new(nil, Time.now, nil)
14
+ end
15
+
16
+ end
@@ -0,0 +1,11 @@
1
+
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/trigger'
4
+
5
+ class CronTriggerTest < Test::Unit::TestCase
6
+
7
+ def test_fire_time_after
8
+ assert_nil(Moment::Trigger.new.fire_time_after(Time.now))
9
+ end
10
+
11
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: moment
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2006-04-25 00:00:00 -07:00
8
+ summary: A scheduler (like cron) that will run specified ruby code at given intervals or times
9
+ require_paths:
10
+ - lib
11
+ email: visnux@swivel.com
12
+ homepage: http://visnup.com
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: moment
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - Visnu Pitiyanuvath
30
+ files:
31
+ - bin/moment_server
32
+ - lib/server.rb
33
+ - lib/client.rb
34
+ - lib/trigger.rb
35
+ - lib/shell_job.rb
36
+ - lib/moment.rb
37
+ - lib/cron_trigger.rb
38
+ - lib/simple_trigger.rb
39
+ - lib/scheduler.rb
40
+ - lib/job.rb
41
+ - test/server_test.rb
42
+ - test/simple_trigger_test.rb
43
+ - test/scheduler_test.rb
44
+ - test/job_test.rb
45
+ - test/cron_trigger_test.rb
46
+ - test/trigger_test.rb
47
+ - test/shell_job_test.rb
48
+ - test/moment_test.rb
49
+ - README
50
+ test_files:
51
+ - test/moment_test.rb
52
+ rdoc_options: []
53
+
54
+ extra_rdoc_files:
55
+ - README
56
+ - bin/moment_server
57
+ executables:
58
+ - moment_server
59
+ extensions: []
60
+
61
+ requirements: []
62
+
63
+ dependencies: []
64
+