acts_as_executor 1.0.0.beta2 → 1.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/acts_as_executor.gemspec +8 -1
  2. data/lib/acts_as_executor.rb +18 -31
  3. data/lib/acts_as_executor/common/future_task.rb +2 -2
  4. data/lib/acts_as_executor/common/instance_support_methods.rb +15 -0
  5. data/lib/acts_as_executor/executor/factory.rb +18 -22
  6. data/lib/acts_as_executor/executor/model/class_methods.rb +33 -0
  7. data/lib/acts_as_executor/executor/model/instance_methods.rb +87 -0
  8. data/lib/acts_as_executor/executor/model/instance_support_methods.rb +36 -0
  9. data/lib/acts_as_executor/task/clazz.rb +26 -0
  10. data/lib/acts_as_executor/task/model/class_methods.rb +13 -0
  11. data/lib/acts_as_executor/task/model/instance_methods.rb +64 -0
  12. data/lib/acts_as_executor/task/model/instance_support_methods.rb +32 -0
  13. data/lib/acts_as_executor/validators/class_exists_validator.rb +1 -1
  14. data/lib/acts_as_executor/validators/class_includes_validator.rb +10 -0
  15. data/lib/acts_as_executor/version.rb +1 -1
  16. data/lib/generators/{executor_generator.rb → acts_as_executor_generator.rb} +1 -5
  17. data/lib/generators/templates/migration/create_executors.rb +2 -2
  18. data/spec/acts_as_executor_spec.rb +22 -0
  19. data/spec/common/future_task_spec.rb +21 -0
  20. data/spec/common/instance_support_methods_spec.rb +25 -0
  21. data/spec/common/units_spec.rb +19 -0
  22. data/spec/executor/factory_spec.rb +31 -0
  23. data/spec/executor/model/class_methods_spec.rb +49 -0
  24. data/spec/executor/model/instance_methods_spec.rb +150 -0
  25. data/spec/executor/model/instance_support_methods_spec.rb +70 -0
  26. data/spec/spec_helper.rb +8 -0
  27. data/spec/support/blueprints.rb +20 -0
  28. data/spec/support/classes.rb +55 -0
  29. data/spec/support/custom_matchers.rb +26 -0
  30. data/spec/support/database_connection.rb +4 -0
  31. data/spec/task/clazz_spec.rb +42 -0
  32. data/spec/task/model/class_methods_spec.rb +13 -0
  33. data/spec/task/model/instance_methods_spec.rb +80 -0
  34. data/spec/task/model/instance_support_methods_spec.rb +56 -0
  35. data/spec/task/schedules_spec.rb +11 -0
  36. data/spec/validators/class_exists_validator_spec.rb +21 -0
  37. data/spec/validators/class_includes_validator_spec.rb +21 -0
  38. metadata +88 -21
  39. data/README.rdoc +0 -67
  40. data/lib/acts_as_executor/executor/kinds.rb +0 -16
  41. data/lib/acts_as_executor/executor/model/actions.rb +0 -65
  42. data/lib/acts_as_executor/executor/model/associations.rb +0 -11
  43. data/lib/acts_as_executor/executor/model/attributes.rb +0 -16
  44. data/lib/acts_as_executor/executor/model/base.rb +0 -24
  45. data/lib/acts_as_executor/executor/model/helpers.rb +0 -25
  46. data/lib/acts_as_executor/executor/model/validations.rb +0 -13
  47. data/lib/acts_as_executor/task/model/actions.rb +0 -34
  48. data/lib/acts_as_executor/task/model/associations.rb +0 -11
  49. data/lib/acts_as_executor/task/model/attributes.rb +0 -16
  50. data/lib/acts_as_executor/task/model/base.rb +0 -15
  51. data/lib/acts_as_executor/task/model/helpers.rb +0 -14
  52. data/lib/acts_as_executor/task/model/validations.rb +0 -16
  53. data/lib/generators/templates/initializer/acts_as_executor.rb +0 -4
@@ -1,7 +1,7 @@
1
1
  class ClassExistsValidator < ActiveModel::EachValidator
2
2
  def validate_each record, attribute, value
3
3
  begin
4
- value.constantize.new
4
+ Object.const_get(value).new
5
5
  rescue NameError
6
6
  record.errors[attribute] << "does not exist as a Class"
7
7
  end
@@ -0,0 +1,10 @@
1
+ class ClassIncludesValidator < ActiveModel::EachValidator
2
+ def validate_each record, attribute, value
3
+ begin
4
+ throw TypeError unless Object.const_get(value).new.kind_of? options[:includes]
5
+ rescue NameError
6
+ rescue TypeError
7
+ record.errors[attribute] << "does not include " + options[:includes].to_s
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module ActsAsExecutor
2
- VERSION = "1.0.0.beta2"
2
+ VERSION = "1.0.0.rc1"
3
3
  end
@@ -1,12 +1,8 @@
1
- class ExecutorGenerator < Rails::Generators::NamedBase
1
+ class ActsAsExecutorGenerator < Rails::Generators::NamedBase
2
2
  include Rails::Generators::Migration
3
3
 
4
4
  source_root File.expand_path("../templates", __FILE__)
5
5
 
6
- def initializer
7
- template File.join("initializer", "acts_as_executor.rb"), File.join("config", "initializers", "acts_as_executor.rb")
8
- end
9
-
10
6
  def models
11
7
  template File.join("models", "executor.rb"), File.join("app", "models", file_name + ".rb")
12
8
  template File.join("models", "executor_task.rb"), File.join("app", "models", file_name + "_task.rb")
@@ -2,8 +2,8 @@ class Create<%= class_name.pluralize %> < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :<%= table_name %> do |t|
4
4
  t.string :name
5
- t.string :kind
6
- t.integer :size
5
+ t.integer :max_tasks
6
+ t.boolean :schedulable
7
7
  t.timestamps
8
8
  end
9
9
 
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ describe ActsAsExecutor do
4
+ it { ActsAsExecutor::VERSION.should == "1.0.0.rc1" }
5
+
6
+ describe "#rails_initialized?" do
7
+ context "when rails initialized" do
8
+ it "should return true" do
9
+ $0 = "rails"
10
+
11
+ ActsAsExecutor.rails_initialized?.should be_true
12
+ end
13
+ end
14
+ context "when rails not initialized" do
15
+ it "should return false" do
16
+ $0 = "rake"
17
+
18
+ ActsAsExecutor.rails_initialized?.should be_false
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ describe ActsAsExecutor::Common::FutureTask do
4
+ before(:each) { @model = ActsAsExecutor::Common::FutureTask.new Clazz.make, nil }
5
+
6
+ it { @model.should be_a Java::java.util.concurrent.FutureTask }
7
+
8
+ describe "#done" do
9
+ context "when done handler exists" do
10
+ it "should invoke handler" do
11
+ handler = double "Handler"
12
+ handler.stub :done_handler
13
+ @model.done_handler = handler.method :done_handler
14
+
15
+ handler.should_receive :done_handler
16
+
17
+ @model.done
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ describe ActsAsExecutor::Common::InstanceSupportMethods do
4
+ before(:each) { @model = InstanceSupportMethods.make }
5
+
6
+ it { @model.should_not allow_public_access_for_methods :log_statement, :log_message }
7
+
8
+ describe "#log_statement" do
9
+ it "should return a string" do
10
+ @model.send(:log_statement, "name", "statement").should == log_statement("name", "statement")
11
+ end
12
+ end
13
+
14
+ describe "#log_message" do
15
+ it "should return a string" do
16
+ @model.send(:log_message, "name", "doing", 1.to_s, "clazz", "message").should == log_message("name", "doing", 1.to_s, "clazz", "message")
17
+ end
18
+
19
+ context "when message is a hash" do
20
+ it "should return a string" do
21
+ @model.send(:log_message, "name", "doing", 1.to_s, "clazz", {:attribute_one => "attribute_one_value", :attribute_two => "attribute_two_value"}).should == log_message("name", "doing", 1.to_s, "clazz", {:attribute_one => "attribute_one_value", :attribute_two => "attribute_two_value"})
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ describe ActsAsExecutor::Common::Units do
4
+ it { ActsAsExecutor::Common::Units::NANOSECONDS.should == "nanoseconds" }
5
+ it { ActsAsExecutor::Common::Units::MICROSECONDS.should == "microseconds" }
6
+ it { ActsAsExecutor::Common::Units::MILLISECONDS.should == "milliseconds" }
7
+ it { ActsAsExecutor::Common::Units::SECONDS.should == "seconds" }
8
+ it { ActsAsExecutor::Common::Units::MINUTES.should == "minutes" }
9
+ it { ActsAsExecutor::Common::Units::HOURS.should == "hours" }
10
+ it { ActsAsExecutor::Common::Units::DAYS.should == "days" }
11
+ it { ActsAsExecutor::Common::Units::ALL.should include ActsAsExecutor::Common::Units::NANOSECONDS,
12
+ ActsAsExecutor::Common::Units::MICROSECONDS,
13
+ ActsAsExecutor::Common::Units::MILLISECONDS,
14
+ ActsAsExecutor::Common::Units::SECONDS,
15
+ ActsAsExecutor::Common::Units::MINUTES,
16
+ ActsAsExecutor::Common::Units::HOURS,
17
+ ActsAsExecutor::Common::Units::DAYS
18
+ }
19
+ end
@@ -0,0 +1,31 @@
1
+ require "spec_helper"
2
+
3
+ describe ActsAsExecutor::Executor::Factory do
4
+ describe "#create" do
5
+ it "should return a scheduled executor" do
6
+ executor = ActsAsExecutor::Executor::Factory.create 5, true
7
+
8
+ executor.should be_a Java::java.util.concurrent.ScheduledExecutorService
9
+ executor.core_pool_size.should == 5
10
+ end
11
+
12
+ it "should return a single scheduled executor" do
13
+ ActsAsExecutor::Executor::Factory.create(1, true).should be_a Java::java.util.concurrent.ScheduledExecutorService
14
+ end
15
+
16
+ it "should return a cached executor" do
17
+ ActsAsExecutor::Executor::Factory.create(nil, nil).should be_a Java::java.util.concurrent.ExecutorService
18
+ end
19
+
20
+ it "should return a fixed executor" do
21
+ executor = ActsAsExecutor::Executor::Factory.create 5, nil
22
+
23
+ executor.should be_a Java::java.util.concurrent.ExecutorService
24
+ executor.core_pool_size.should == 5
25
+ end
26
+
27
+ it "should return a single executor" do
28
+ ActsAsExecutor::Executor::Factory.create(1, nil).should be_a Java::java.util.concurrent.ExecutorService
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ require "spec_helper"
2
+
3
+ describe ActsAsExecutor::Executor::Model::ClassMethods do
4
+ subject { ActiveRecord::Base }
5
+ it { should be_a ActsAsExecutor::Executor::Model::ClassMethods }
6
+
7
+ describe "#acts_as_executor" do
8
+ subject { Executor }
9
+ it { should include ActsAsExecutor::Common::InstanceSupportMethods }
10
+ it { should include ActsAsExecutor::Executor::Model::InstanceMethods }
11
+ it { should include ActsAsExecutor::Executor::Model::InstanceSupportMethods }
12
+
13
+ context "when arguments exist" do
14
+ before :all do
15
+ @log = Logger.new
16
+
17
+ ExecutorWithoutActsAsExecutor.acts_as_executor :log => @log
18
+ end
19
+
20
+ it "should set log" do
21
+ Rails.should_not_receive(:logger)
22
+ ExecutorWithoutActsAsExecutor.log.should == @log
23
+ end
24
+ end
25
+ end
26
+
27
+ describe "#log" do
28
+ after(:each) { Executor.log = Logger.new }
29
+
30
+ it "should return log" do
31
+ log = Logger.new
32
+ Executor.log = log
33
+
34
+ Rails.should_not_receive(:logger)
35
+ Executor.log.should == log
36
+ end
37
+
38
+ context "when log has not been set" do
39
+ it "should return Rails.logger" do
40
+ log = Logger.new
41
+
42
+ Executor.log = nil
43
+
44
+ Rails.should_receive(:logger).at_most(:twice).and_return log
45
+ Executor.log.should == Rails.logger
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,150 @@
1
+ require "spec_helper"
2
+
3
+ describe ActsAsExecutor::Executor::Model::InstanceMethods do
4
+ before(:each) { @model = Executor.make }
5
+
6
+ it { @model.should_not allow_public_access_for_methods :startup, :execute, :shutdown, :forced_shutdown }
7
+
8
+ describe "#startup" do
9
+ it "should create executor" do
10
+ @model.send(:executor).should be_nil
11
+
12
+ @model.send(:log).should_receive(:debug).with log_statement(@model.name, "startup triggered")
13
+ @model.send(:log).should_receive(:info).with log_statement(@model.name, "started")
14
+
15
+ @model.send :startup
16
+
17
+ @model.send(:executor).should_not be_nil
18
+ end
19
+ end
20
+
21
+ describe "#execute" do
22
+ before(:each) { @clazz = Clazz.make }
23
+ after(:each) { @model.send(:executor).shutdown }
24
+
25
+ it "should execute a task" do
26
+ @model.send :startup
27
+
28
+ @model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @clazz.class.name, "for execution (one time)")
29
+ @model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @clazz.class.name)
30
+
31
+ future = @model.send :execute, @clazz, 1.to_s
32
+ future.get
33
+
34
+ future.is_done.should be_true
35
+ end
36
+
37
+ it "should execute a one shot task" do
38
+ @model = Executor.make :max_tasks => 1, :schedulable => true
39
+ @model.send :startup
40
+
41
+ @model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @clazz.class.name, "for execution (one shot)")
42
+ @model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @clazz.class.name)
43
+
44
+ future = @model.send :execute, @clazz, 1.to_s, ActsAsExecutor::Task::Schedules::ONE_SHOT, 0, nil, ActsAsExecutor::Common::Units::SECONDS
45
+ future.get
46
+
47
+ future.is_done.should be_true
48
+ end
49
+
50
+ it "should execute a fixed delay task" do
51
+ @model = Executor.make :max_tasks => 1, :schedulable => true
52
+ @model.send :startup
53
+
54
+ @model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @clazz.class.name, "for execution (fixed delay)")
55
+ @model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @clazz.class.name)
56
+
57
+ future = @model.send :execute, @clazz, 1.to_s, ActsAsExecutor::Task::Schedules::FIXED_DELAY, 0, 2, ActsAsExecutor::Common::Units::SECONDS
58
+
59
+ future.should_not be_nil
60
+ end
61
+
62
+ it "should execute a fixed rate task" do
63
+ @model = Executor.make :max_tasks => 1, :schedulable => true
64
+ @model.send :startup
65
+
66
+ @model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @clazz.class.name, "for execution (fixed rate)")
67
+ @model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @clazz.class.name)
68
+
69
+ future = @model.send :execute, @clazz, 1.to_s, ActsAsExecutor::Task::Schedules::FIXED_RATE, 0, 2, ActsAsExecutor::Common::Units::SECONDS
70
+
71
+ future.should_not be_nil
72
+ end
73
+
74
+ context "when rejected execution exception is thrown" do
75
+ it "should log exception" do
76
+ @model.send :startup
77
+
78
+ @model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @clazz.class.name, "for execution (one time)")
79
+ @model.send(:executor).should_receive(:execute).and_raise Java::java.util.concurrent.RejectedExecutionException.new
80
+ @model.send(:log).should_receive(:warn).with log_message(@model.name, "preparing", 1.to_s, @clazz.class.name, "encountered a rejected execution exception")
81
+
82
+ @model.send :execute, @clazz, 1.to_s
83
+ end
84
+ end
85
+
86
+ context "when any other exception is thrown" do
87
+ it "should log exception" do
88
+ @model = Executor.make :max_tasks => 1, :schedulable => true
89
+ @model.send :startup
90
+
91
+ @model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @clazz.class.name, "for execution (one time)")
92
+ @model.send(:log).should_receive(:error).with log_message(@model.name, "preparing", 1.to_s, @clazz.class.name, "encountered an unexpected exception. java.lang.IllegalArgumentException: No enum const class java.util.concurrent.TimeUnit.RANDOM")
93
+
94
+ @model.send :execute, @clazz, 1.to_s, nil, nil, nil, "random"
95
+ end
96
+ end
97
+ end
98
+
99
+ describe "#shutdown" do
100
+ before(:each) { @model.send :startup }
101
+
102
+ it "should shutdown executor" do
103
+ @model.send(:log).should_receive(:debug).with log_statement(@model.name, "shutdown triggered")
104
+ @model.send(:executor).should_receive :shutdown
105
+ @model.send(:log).should_receive(:info).with log_statement(@model.name, "shutdown")
106
+
107
+ @model.send :shutdown
108
+
109
+ @model.send(:executor).should be_nil
110
+ end
111
+
112
+ context "when security exception is thrown" do
113
+ it "should force shutdown executor" do
114
+ @model.send(:log).should_receive(:debug).with log_statement(@model.name, "shutdown triggered")
115
+ @model.send(:executor).should_receive(:shutdown).and_raise Java::java.lang.SecurityException.new
116
+ @model.send(:log).should_receive(:warn).with log_statement(@model.name, "shutdown encountered a security exception")
117
+ @model.should_receive :forced_shutdown
118
+
119
+ @model.send :shutdown
120
+ end
121
+ end
122
+ end
123
+
124
+ describe "#forced_shutdown" do
125
+ before(:each) { @model.send :startup }
126
+
127
+ it "should shutdown executor" do
128
+ @model.send(:log).should_receive(:debug).with log_statement(@model.name, "forced shutdown triggered")
129
+ @model.send(:executor).should_receive :shutdown_now
130
+ @model.send(:log).should_receive(:info).with log_statement(@model.name, "forced shutdown")
131
+
132
+ @model.send :forced_shutdown
133
+
134
+ @model.send(:executor).should be_nil
135
+ end
136
+
137
+ context "when security exception is thrown" do
138
+ it "should log exception" do
139
+ @model.send(:log).should_receive(:debug).with log_statement(@model.name, "forced shutdown triggered")
140
+ @model.send(:executor).should_receive(:shutdown_now).and_raise Java::java.lang.SecurityException.new
141
+ @model.send(:log).should_receive(:error).with log_statement(@model.name, "forced shutdown encountered a security exception")
142
+ @model.send(:log).should_receive(:fatal).with log_statement(@model.name, "forced shutdown failure")
143
+
144
+ @model.send :forced_shutdown
145
+
146
+ @model.send(:executor).should be_nil
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,70 @@
1
+ require "spec_helper"
2
+
3
+ describe ActsAsExecutor::Executor::Model::InstanceSupportMethods do
4
+ before(:each) { @model = Executor.make }
5
+
6
+ it { @model.should_not allow_public_access_for_methods :executor, :executor=, :startupable?, :shutdownable?, :log }
7
+
8
+ describe "#executor" do
9
+ it "should return executor" do
10
+ executor = double "Executor"
11
+ @model.send :executor=, executor
12
+
13
+ @model.send(:executor).should == executor
14
+ end
15
+
16
+ context "when id has not been set" do
17
+ it "should raise an argument error" do
18
+ @model.id = nil
19
+
20
+ expect { @model.send :executor=, true }.to raise_error ArgumentError, "cannot reference executor against nil id"
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "#startupable?" do
26
+ context "when rails initialized" do
27
+ before(:each) { ActsAsExecutor.should_receive(:rails_initialized?).at_most(:once).and_return true }
28
+
29
+ context "when executor has not been set" do
30
+ it "should return true" do
31
+ @model.should be_startupable
32
+ end
33
+ end
34
+
35
+ context "when executor has been set" do
36
+ it "should return false" do
37
+ @model.send :startup
38
+
39
+ @model.should_not be_startupable
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "#shutdownable?" do
46
+ context "when rails initialized" do
47
+ before(:each) { ActsAsExecutor.should_receive(:rails_initialized?).at_most(:once).and_return true }
48
+
49
+ context "when executor has been set" do
50
+ it "should return true" do
51
+ @model.send :startup
52
+
53
+ @model.should be_shutdownable
54
+ end
55
+ end
56
+
57
+ context "when executor has not been set" do
58
+ it "should return false" do
59
+ @model.should_not be_shutdownable
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ describe "#log" do
66
+ it "should return class log" do
67
+ @model.send(:log).should == Executor.log
68
+ end
69
+ end
70
+ end