serial-scheduler 0.1.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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Andi Bade
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = serial-scheduler
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 Andi Bade. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "serial-scheduler"
8
+ gem.summary = %Q{Schedule Task – execute all tasks at the same time one after another}
9
+ gem.description = %Q{Schedule Task – execute all tasks at the same time one after another}
10
+ gem.email = "andi@galaxycats.com"
11
+ gem.homepage = "http://github.com/thyphoon/serial-scheduler"
12
+ gem.authors = ["Andi Bade"]
13
+ gem.add_dependency "activesupport", "~> 3.0.0"
14
+ # gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/*_test.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/*_test.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+ task :test => :check_dependencies
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "serial-scheduler #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1 @@
1
+ require "serial_scheduler"
@@ -0,0 +1,30 @@
1
+ module SerialScheduler
2
+
3
+ class <<self
4
+
5
+ def define(environment_target, &block)
6
+ SerialScheduler::Dsl.new.instance_eval(&block) if !defined?(Rails) || environment_target == Rails.env.to_sym
7
+ end
8
+
9
+ def run(time = Time.now)
10
+ SerialScheduler::Runner.run(time)
11
+ end
12
+
13
+ def dry_run(time = Time.now)
14
+ SerialScheduler::Runner.dry_run(time)
15
+ end
16
+
17
+ if defined?(NewRelic)
18
+ include NewRelic::Agent::Instrumentation::ControllerInstrumentation
19
+ add_transaction_tracer :run, :category => :task
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+
26
+ require "serial_scheduler/date_day_names_core_extension"
27
+ require "serial_scheduler/converter"
28
+ require "serial_scheduler/dsl"
29
+ require "serial_scheduler/runner"
30
+ require "serial_scheduler/time_table"
@@ -0,0 +1,70 @@
1
+ class SerialScheduler::Converter
2
+
3
+ class <<self
4
+ def to_datetime(string_or_time_or_datetime)
5
+ string_or_time_or_datetime.kind_of?(String) ?
6
+ DateTime.parse(string_or_time_or_datetime) :
7
+ string_or_time_or_datetime.to_datetime
8
+ end
9
+
10
+ def hour_and_minute(time_or_datetime)
11
+ datetime = to_datetime(time_or_datetime)
12
+ formated_hour_and_minute_string(datetime.hour, datetime.min)
13
+ end
14
+
15
+ def to_hour_and_minute(time_or_datetime)
16
+ hour_and_minute(time_or_datetime)
17
+ end
18
+
19
+ def hour_and_minute_in_5_minute_steps(time_or_datetime)
20
+ datetime = to_datetime(time_or_datetime)
21
+ minutes = floor_to_five(datetime.min)
22
+ formated_hour_and_minute_string(datetime.hour, minutes)
23
+ end
24
+
25
+ def weekday_hour_and_minute_in_5_minute_steps(time_or_datetime)
26
+ datetime = to_datetime(time_or_datetime)
27
+ "#{datetime.wday}:#{hour_and_minute_in_5_minute_steps(datetime)}"
28
+ end
29
+
30
+ def floor_to_five(fixnum)
31
+ unit_digit = fixnum % 10
32
+ if unit_digit < 5
33
+ fixnum - unit_digit
34
+ else
35
+ fixnum - (unit_digit - 5)
36
+ end
37
+ end
38
+
39
+ def formated_hour_and_minute_string(hours, minutes)
40
+ minutes = minutes < 10 ? "0#{minutes}" : "#{minutes}"
41
+ hours = hours < 10 ? "0#{hours}" : "#{hours}"
42
+ "#{hours}:#{minutes}"
43
+ end
44
+
45
+ def hours_between(from, to)
46
+ hours = []
47
+ for_each_hour(from,to) do |hour|
48
+ hours << hour
49
+ end
50
+ hours
51
+ end
52
+
53
+ def for_each_hour(from, to)
54
+ for_each_time_with_step(from, to, 1.hour) do |time|
55
+ yield(time)
56
+ end
57
+ end
58
+
59
+ def for_each_time_with_step(from, to, step)
60
+ current_time = DateTime.parse(from)
61
+ max_time = DateTime.parse(to)
62
+ max_time = max_time + 1.day if max_time <= current_time
63
+ while current_time <= max_time
64
+ yield(SerialScheduler::Converter.to_hour_and_minute(current_time))
65
+ current_time += step
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,7 @@
1
+ Date::DAYNAMES.each_with_index do |dayname, idx|
2
+ Date.const_set(dayname.upcase, idx)
3
+ end
4
+
5
+ def Date.human_wday(number)
6
+ Date::DAYNAMES[number].to_s.capitalize
7
+ end
@@ -0,0 +1,109 @@
1
+ class SerialScheduler::Dsl
2
+
3
+ class CallWrapper
4
+ attr_reader :callee, :meth
5
+ def initialize(callee, meth)
6
+ @callee = callee
7
+ @meth = meth
8
+ end
9
+
10
+ def call
11
+ instance_to_call = callee.kind_of?(String) ? callee.constantize : callee
12
+ instance_to_call.send(meth)
13
+ end
14
+
15
+ def to_s
16
+ "#{callee}.#{meth}"
17
+ end
18
+ end
19
+
20
+ attr_accessor :callee
21
+
22
+
23
+ # How to use the scheduler
24
+ #
25
+ # With the scheduler DSL you can define jobs in a simple language
26
+ #
27
+ # Example:
28
+ #
29
+ # schedule AnyReceiver do
30
+ # some_method { every :hour }
31
+ # some_other_method { every 2.hours, :from => "9:00", :to => "18:00" }
32
+ # and_another_method { every :friday, :at => "3:00" }
33
+ # end
34
+
35
+ def schedule(callee, &block)
36
+ self.callee = callee
37
+ self.instance_eval(&block)
38
+ end
39
+
40
+ def every(*args)
41
+ case args.first
42
+ when Symbol
43
+ time_keys_by_symbol(*args)
44
+ when ActiveSupport::Duration
45
+ time_keys_by_duration(*args)
46
+ else
47
+ raise "SerialScheduler::Dsl - every - You have to specify either a symbol or a duration (was #{args.first.inspect})"
48
+ end
49
+ end
50
+
51
+ def time_keys_by_symbol(*args)
52
+ time_keys = []
53
+ options = args.extract_options!
54
+ case args.first
55
+ when :hour
56
+ from, to = extract_from_to_or_default(options)
57
+ time_keys = SerialScheduler::Converter.hours_between(from, to)
58
+ when :day
59
+ time_keys = extract_at_or_default(options)
60
+ else
61
+ at = extract_at_or_default(options)
62
+ day = args.first
63
+ if [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday].include?(day)
64
+ time_keys << "#{Date.const_get(day.to_s.upcase)}:#{at}"
65
+ end
66
+ end
67
+ return time_keys
68
+ end
69
+
70
+ def time_keys_by_duration(*args)
71
+ options = args.extract_options!
72
+ from, to = extract_from_to_or_default(options)
73
+ step = args.first
74
+ time_keys = []
75
+ SerialScheduler::Converter.for_each_time_with_step(from, to, step) do |time_key|
76
+ time_keys << time_key
77
+ end
78
+ time_keys
79
+ end
80
+
81
+ def extract_from_to_or_default(options)
82
+ options ||= {}
83
+ from = options[:from] ? SerialScheduler::Converter.to_hour_and_minute(options[:from]) : "00:00"
84
+ to = options[:to] ? SerialScheduler::Converter.to_hour_and_minute(options[:to]) : "23:59"
85
+ return from, to
86
+ end
87
+
88
+ def extract_at_or_default(options)
89
+ options ||= {}
90
+ options[:at] ? SerialScheduler::Converter.to_hour_and_minute(options[:at]) : "00:00"
91
+ end
92
+
93
+ def create_time_table_with_time_keys(time_keys, callee, meth)
94
+ time_keys.inject({}) do |time_table, time_key|
95
+ time_table[time_key] = CallWrapper.new(callee, meth)
96
+ time_table
97
+ end
98
+ end
99
+
100
+ def method_missing(meth, *args, &blk)
101
+ if block_given?
102
+ time_keys = instance_eval(&blk)
103
+ SerialScheduler::TimeTable.add(create_time_table_with_time_keys(time_keys, self.callee, meth))
104
+ else
105
+ super
106
+ end
107
+ end
108
+
109
+ end
@@ -0,0 +1,32 @@
1
+ class SerialScheduler::Runner
2
+
3
+ class <<self
4
+
5
+ def run(time, options = {})
6
+ daily_time_key = SerialScheduler::Converter.hour_and_minute_in_5_minute_steps(time)
7
+ weekly_time_key = SerialScheduler::Converter.weekday_hour_and_minute_in_5_minute_steps(time)
8
+ jobs = SerialScheduler::TimeTable.jobs_for([weekly_time_key, daily_time_key].compact)
9
+ jobs.each do |job|
10
+ begin
11
+ if options[:dry_run]
12
+ puts ">> #{job}"
13
+ else
14
+ job.call
15
+ end
16
+ rescue => e
17
+ if defined?(Rails)
18
+ raise e if Rails.env.development?
19
+ Notifier.deliver_scheduler_error(e, job, time)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ def dry_run(time)
26
+ run(time, :dry_run => true)
27
+ puts ">> end"
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,74 @@
1
+ require 'singleton'
2
+
3
+ class SerialScheduler::TimeTable
4
+ include Singleton
5
+
6
+ attr_reader :timing
7
+
8
+ def initialize
9
+ @timing = {}
10
+ end
11
+
12
+ class <<self
13
+ def jobs_for(*time_keys)
14
+ [time_keys].flatten.collect do |time_key|
15
+ timing[time_key]
16
+ end.flatten.compact
17
+ end
18
+
19
+ def method_missing(meth, *args, &blk)
20
+ if self.instance.respond_to?(meth)
21
+ self.instance.send(meth, *args, &blk)
22
+ else
23
+ super
24
+ end
25
+ end
26
+ end
27
+
28
+ def add(hash_with_timing_info)
29
+ hash_with_timing_info.each do |timing_key, calls|
30
+ self.timing[timing_key] ||= []
31
+ self.timing[timing_key] += [calls].flatten
32
+ end
33
+ end
34
+
35
+ def clear
36
+ self.timing = {}
37
+ end
38
+
39
+ def weekly_timing
40
+ timing.reject { |time_key, call| time_key.size != 7 }
41
+ end
42
+
43
+ def daily_timing
44
+ timing.reject { |time_key, call| time_key.size != 5 }
45
+ end
46
+
47
+ def print
48
+ print_daily_timing
49
+ print_weekly_timing
50
+ end
51
+
52
+ def print_daily_timing
53
+ puts
54
+ puts "daily timing"
55
+ puts "-"*15
56
+ daily_timing.keys.sort.each do |time_key|
57
+ scheduled_calls = timing[time_key]
58
+ puts "#{time_key} |\t#{scheduled_calls.join("\n\t")}"
59
+ end
60
+ end
61
+
62
+ def print_weekly_timing
63
+ puts
64
+ puts "weekly timing"
65
+ puts "-"*15
66
+ weekly_timing.keys.sort.each do |time_key|
67
+ scheduled_calls = timing[time_key]
68
+ puts "#{Date.human_wday(time_key.first.to_i)}, #{time_key[2..-1]} |\t#{scheduled_calls.join("\n\t")}"
69
+ end
70
+ end
71
+
72
+ private
73
+ attr_writer :timing
74
+ end
@@ -0,0 +1,66 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{serial-scheduler}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Andi Bade"]
12
+ s.date = %q{2011-02-28}
13
+ s.description = %q{Schedule Task – execute all tasks at the same time one after another}
14
+ s.email = %q{andi@galaxycats.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/serial-scheduler.rb",
27
+ "lib/serial_scheduler.rb",
28
+ "lib/serial_scheduler/converter.rb",
29
+ "lib/serial_scheduler/date_day_names_core_extension.rb",
30
+ "lib/serial_scheduler/dsl.rb",
31
+ "lib/serial_scheduler/runner.rb",
32
+ "lib/serial_scheduler/time_table.rb",
33
+ "serial-scheduler.gemspec",
34
+ "test/converter_test.rb",
35
+ "test/dsl_test.rb",
36
+ "test/runner_test.rb",
37
+ "test/serial_scheduler_test.rb",
38
+ "test/test_helper.rb"
39
+ ]
40
+ s.homepage = %q{http://github.com/thyphoon/serial-scheduler}
41
+ s.rdoc_options = ["--charset=UTF-8"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.6}
44
+ s.summary = %q{Schedule Task – execute all tasks at the same time one after another}
45
+ s.test_files = [
46
+ "test/converter_test.rb",
47
+ "test/dsl_test.rb",
48
+ "test/runner_test.rb",
49
+ "test/serial_scheduler_test.rb",
50
+ "test/test_helper.rb"
51
+ ]
52
+
53
+ if s.respond_to? :specification_version then
54
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
+ s.specification_version = 3
56
+
57
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
58
+ s.add_runtime_dependency(%q<activesupport>, ["~> 3.0.0"])
59
+ else
60
+ s.add_dependency(%q<activesupport>, ["~> 3.0.0"])
61
+ end
62
+ else
63
+ s.add_dependency(%q<activesupport>, ["~> 3.0.0"])
64
+ end
65
+ end
66
+
@@ -0,0 +1,50 @@
1
+ require 'test_helper'
2
+
3
+ class ConverterTest < ActiveSupport::TestCase
4
+
5
+ test "should calculate hour and minute string floored in 5 minute steps" do
6
+ assert_equal "11:55", SerialScheduler::Converter.hour_and_minute_in_5_minute_steps("17.12.2010 11:59".to_datetime)
7
+ assert_equal "12:00", SerialScheduler::Converter.hour_and_minute_in_5_minute_steps("17.12.2010 12:00".to_datetime)
8
+ assert_equal "12:00", SerialScheduler::Converter.hour_and_minute_in_5_minute_steps("17.12.2010 12:04".to_datetime)
9
+ assert_equal "12:05", SerialScheduler::Converter.hour_and_minute_in_5_minute_steps("17.12.2010 12:05".to_datetime)
10
+ assert_equal "12:05", SerialScheduler::Converter.hour_and_minute_in_5_minute_steps("17.12.2010 12:06".to_datetime)
11
+ end
12
+
13
+ test "should calculate weekday, hour and minute string floored in 5 minute steps" do
14
+ assert_equal "#{Date::FRIDAY}:11:55", SerialScheduler::Converter.weekday_hour_and_minute_in_5_minute_steps("17.12.2010 11:59".to_datetime)
15
+ assert_equal "#{Date::SATURDAY}:12:00", SerialScheduler::Converter.weekday_hour_and_minute_in_5_minute_steps("18.12.2010 12:00".to_datetime)
16
+ assert_equal "#{Date::SUNDAY}:12:00", SerialScheduler::Converter.weekday_hour_and_minute_in_5_minute_steps("19.12.2010 12:04".to_datetime)
17
+ assert_equal "#{Date::MONDAY}:12:05", SerialScheduler::Converter.weekday_hour_and_minute_in_5_minute_steps("20.12.2010 12:05".to_datetime)
18
+ assert_equal "#{Date::TUESDAY}:12:05", SerialScheduler::Converter.weekday_hour_and_minute_in_5_minute_steps("21.12.2010 12:06".to_datetime)
19
+ assert_equal "#{Date::WEDNESDAY}:14:05", SerialScheduler::Converter.weekday_hour_and_minute_in_5_minute_steps("22.12.2010 14:06".to_datetime)
20
+ assert_equal "#{Date::THURSDAY}:18:05", SerialScheduler::Converter.weekday_hour_and_minute_in_5_minute_steps("23.12.2010 18:06".to_datetime)
21
+ end
22
+
23
+ test "should round (floor) numbers in steps of 5" do
24
+ assert_equal 0, SerialScheduler::Converter.floor_to_five(1)
25
+ assert_equal 0, SerialScheduler::Converter.floor_to_five(4)
26
+ assert_equal 5, SerialScheduler::Converter.floor_to_five(5)
27
+ assert_equal 5, SerialScheduler::Converter.floor_to_five(6)
28
+ assert_equal 5, SerialScheduler::Converter.floor_to_five(9)
29
+ assert_equal 10, SerialScheduler::Converter.floor_to_five(10)
30
+ assert_equal 10, SerialScheduler::Converter.floor_to_five(11)
31
+ end
32
+
33
+ test "should format hour and minute as a string with two and two digits" do
34
+ assert_equal "01:09", SerialScheduler::Converter.formated_hour_and_minute_string(1, 9)
35
+ assert_equal "12:00", SerialScheduler::Converter.formated_hour_and_minute_string(12, 0)
36
+ assert_equal "14:03", SerialScheduler::Converter.formated_hour_and_minute_string(14, 3)
37
+ assert_equal "23:59", SerialScheduler::Converter.formated_hour_and_minute_string(23, 59)
38
+ end
39
+
40
+ test "should return an array with all hours between two hours" do
41
+ assert_equal ["23:00", "00:00", "01:00", "02:00"], SerialScheduler::Converter.hours_between("23:00", "02:00")
42
+ assert_equal ["03:00", "04:00", "05:00", "06:00", "07:00", "08:00", "09:00", "10:00", "11:00", "12:00", "13:00", "14:00",
43
+ "15:00", "16:00", "17:00", "18:00", "19:00", "20:00", "21:00", "22:00", "23:00", "00:00", "01:00", "02:00", "03:00"], SerialScheduler::Converter.hours_between("03:00", "03:00")
44
+ assert_equal ["03:00", "04:00"], SerialScheduler::Converter.hours_between("03:00", "04:00")
45
+ assert_equal ["03:00"], SerialScheduler::Converter.hours_between("03:00", "03:01")
46
+ assert_equal ["08:00", "09:00", "10:00", "11:00", "12:00", "13:00"], SerialScheduler::Converter.hours_between("08:00", "13:00")
47
+ end
48
+
49
+
50
+ end
data/test/dsl_test.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'test_helper'
2
+
3
+ class DslTest < ActiveSupport::TestCase
4
+
5
+ test "should create time keys by symbol :hour" do
6
+ assert_equal ["00:00", "01:00", "02:00", "03:00", "04:00", "05:00", "06:00", "07:00", "08:00", "09:00", "10:00", "11:00",
7
+ "12:00", "13:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00", "20:00", "21:00", "22:00", "23:00"], SerialScheduler::Dsl.new.time_keys_by_symbol(:hour)
8
+
9
+ assert_equal ["08:00", "09:00", "10:00", "11:00", "12:00", "13:00",
10
+ "14:00", "15:00", "16:00", "17:00", "18:00", "19:00", "20:00"], SerialScheduler::Dsl.new.time_keys_by_symbol(:hour, :from => "8:00", :to => "20:00")
11
+ end
12
+
13
+ test "should create time keys by time step size (duration)" do
14
+ expected_time_keys = []
15
+ SerialScheduler::Converter.for_each_time_with_step("00:00", "23:55", 5.minutes) { |time_key| expected_time_keys << time_key }
16
+ assert_equal expected_time_keys, SerialScheduler::Dsl.new.time_keys_by_duration(5.minutes)
17
+
18
+ assert_equal ["11:23", "11:28", "11:33"], SerialScheduler::Dsl.new.time_keys_by_duration(5.minutes, :from => "11:23", :to => "11:37")
19
+ end
20
+
21
+ test "should create time key for a day symbol with 'at' condition" do
22
+ assert_equal ["5:00:00"], SerialScheduler::Dsl.new.time_keys_by_symbol(:friday)
23
+ end
24
+
25
+ test "should extract from and to from options or return defaults" do
26
+ dsl = SerialScheduler::Dsl.new
27
+ assert_equal ["08:00", "09:00"], dsl.extract_from_to_or_default({:from => "8:00", :to => "9:00"})
28
+ assert_equal ["12:00", "13:00"], dsl.extract_from_to_or_default({:from => "12:00", :to => "13:00"})
29
+ assert_equal ["00:00", "23:59"], dsl.extract_from_to_or_default(nil)
30
+ end
31
+
32
+ test "should extract at from options or return default" do
33
+ dsl = SerialScheduler::Dsl.new
34
+ assert_equal "00:00", dsl.extract_at_or_default({:at => "0:00"})
35
+ assert_equal "12:00", dsl.extract_at_or_default({:at => "12:00"})
36
+ assert_equal "00:00", dsl.extract_at_or_default(nil)
37
+ end
38
+
39
+ test "should create time stamps for every :day" do
40
+ assert_equal "03:00", SerialScheduler::Dsl.new.time_keys_by_symbol(:day, :at => "3:00")
41
+ end
42
+
43
+ end
@@ -0,0 +1,38 @@
1
+ require 'test_helper'
2
+
3
+ class RunnerTest < ActiveSupport::TestCase
4
+
5
+ class MockReceiver; end
6
+
7
+ def setup
8
+ SerialScheduler::TimeTable.clear
9
+ SerialScheduler.define :test do
10
+ schedule RunnerTest::MockReceiver do
11
+ lastminute { every :hour, :from => "8:00", :to => "20:00" }
12
+ availability { every 2.hours, :from => "0:00", :to => "4:00" }
13
+ houses { every :monday, :at => "0:00" }
14
+ end
15
+ end
16
+ end
17
+
18
+ test "should run all relevant jobs for given time" do
19
+ MockReceiver.expects(:houses)
20
+ MockReceiver.expects(:availability)
21
+ SerialScheduler::Runner.run("27.12.2010 00:00".to_datetime)
22
+ end
23
+
24
+ test "should dry-run all relevant jobs for given time" do
25
+ MockReceiver.expects(:houses).never
26
+ MockReceiver.expects(:availability).never
27
+ SerialScheduler::Runner.dry_run("27.12.2010 00:00".to_datetime)
28
+ end
29
+
30
+ test "should catch all exceptions during job execution and send an email to developers" do
31
+ if defined?(Rails)
32
+ MockReceiver.expects(:lastminute).raises(ArgumentError, "Hello from test")
33
+ Notifier.expects(:deliver_scheduler_error)
34
+ SerialScheduler::Runner.run("27.12.2010 8:00".to_datetime)
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class SerialSchedulerTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ SerialScheduler::TimeTable.clear
7
+ end
8
+
9
+ test "should evaluate a definition with every hour" do
10
+ SerialScheduler.define :test do
11
+ schedule "some importer" do
12
+ lastminute { every :hour }
13
+ end
14
+ end
15
+ assert_equal(
16
+ ["00:00", "01:00", "02:00", "03:00", "04:00", "05:00", "06:00", "07:00", "08:00", "09:00", "10:00", "11:00",
17
+ "12:00", "13:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00", "20:00", "21:00", "22:00", "23:00"],
18
+ SerialScheduler::TimeTable.timing.keys.sort
19
+ )
20
+ SerialScheduler::TimeTable.timing.values.each do |vals|
21
+ assert_kind_of Array, vals
22
+ assert vals.all? { |val| val.kind_of?(SerialScheduler::Dsl::CallWrapper) }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_support'
4
+ require 'active_support/test_case'
5
+ require 'active_support/core_ext'
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
9
+ require 'serial-scheduler'
10
+
11
+ class Test::Unit::TestCase
12
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: serial-scheduler
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Andi Bade
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-02-28 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activesupport
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 3
29
+ - 0
30
+ - 0
31
+ version: 3.0.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: "Schedule Task \xE2\x80\x93 execute all tasks at the same time one after another"
35
+ email: andi@galaxycats.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - LICENSE
42
+ - README.rdoc
43
+ files:
44
+ - .document
45
+ - .gitignore
46
+ - LICENSE
47
+ - README.rdoc
48
+ - Rakefile
49
+ - VERSION
50
+ - lib/serial-scheduler.rb
51
+ - lib/serial_scheduler.rb
52
+ - lib/serial_scheduler/converter.rb
53
+ - lib/serial_scheduler/date_day_names_core_extension.rb
54
+ - lib/serial_scheduler/dsl.rb
55
+ - lib/serial_scheduler/runner.rb
56
+ - lib/serial_scheduler/time_table.rb
57
+ - serial-scheduler.gemspec
58
+ - test/converter_test.rb
59
+ - test/dsl_test.rb
60
+ - test/runner_test.rb
61
+ - test/serial_scheduler_test.rb
62
+ - test/test_helper.rb
63
+ has_rdoc: true
64
+ homepage: http://github.com/thyphoon/serial-scheduler
65
+ licenses: []
66
+
67
+ post_install_message:
68
+ rdoc_options:
69
+ - --charset=UTF-8
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.3.6
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: "Schedule Task \xE2\x80\x93 execute all tasks at the same time one after another"
93
+ test_files:
94
+ - test/converter_test.rb
95
+ - test/dsl_test.rb
96
+ - test/runner_test.rb
97
+ - test/serial_scheduler_test.rb
98
+ - test/test_helper.rb