active_worker 0.50.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.
Files changed (55) hide show
  1. data/.document +5 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +22 -0
  4. data/Gemfile.lock +77 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +19 -0
  7. data/Rakefile +46 -0
  8. data/VERSION +1 -0
  9. data/active_worker.gemspec +108 -0
  10. data/lib/active_worker.rb +29 -0
  11. data/lib/active_worker/behavior/acts_as_root_object.rb +80 -0
  12. data/lib/active_worker/behavior/can_be_notified.rb +23 -0
  13. data/lib/active_worker/behavior/create_from_error.rb +21 -0
  14. data/lib/active_worker/behavior/execute_concurrently.rb +142 -0
  15. data/lib/active_worker/behavior/has_modes.rb +44 -0
  16. data/lib/active_worker/behavior/has_root_object.rb +50 -0
  17. data/lib/active_worker/behavior/hashable.rb +79 -0
  18. data/lib/active_worker/configuration.rb +143 -0
  19. data/lib/active_worker/controller.rb +112 -0
  20. data/lib/active_worker/event.rb +68 -0
  21. data/lib/active_worker/expandable.rb +77 -0
  22. data/lib/active_worker/failure_event.rb +16 -0
  23. data/lib/active_worker/finished_event.rb +9 -0
  24. data/lib/active_worker/host_information.rb +13 -0
  25. data/lib/active_worker/job_queue/job_executer.rb +52 -0
  26. data/lib/active_worker/job_queue/queue_manager.rb +46 -0
  27. data/lib/active_worker/job_queue/run_remotely.rb +52 -0
  28. data/lib/active_worker/modes_map.rb +37 -0
  29. data/lib/active_worker/notification_event.rb +9 -0
  30. data/lib/active_worker/parent_event.rb +5 -0
  31. data/lib/active_worker/started_event.rb +10 -0
  32. data/lib/active_worker/templatable.rb +46 -0
  33. data/lib/active_worker/template.rb +41 -0
  34. data/lib/active_worker/termination_event.rb +21 -0
  35. data/test/mongoid.yml +28 -0
  36. data/test/test_acts_as_root_object.rb +123 -0
  37. data/test/test_can_be_notified.rb +44 -0
  38. data/test/test_configuration.rb +281 -0
  39. data/test/test_controller.rb +205 -0
  40. data/test/test_event.rb +75 -0
  41. data/test/test_execute_concurrently.rb +134 -0
  42. data/test/test_expandable.rb +113 -0
  43. data/test/test_failure_event.rb +69 -0
  44. data/test/test_finished_event.rb +35 -0
  45. data/test/test_has_modes.rb +56 -0
  46. data/test/test_helper.rb +120 -0
  47. data/test/test_integration.rb +56 -0
  48. data/test/test_job_executer.rb +65 -0
  49. data/test/test_queue_manager.rb +106 -0
  50. data/test/test_run_remotely.rb +63 -0
  51. data/test/test_started_event.rb +23 -0
  52. data/test/test_templatable.rb +45 -0
  53. data/test/test_template.rb +29 -0
  54. data/test/test_termination_event.rb +28 -0
  55. metadata +201 -0
@@ -0,0 +1,37 @@
1
+ module ActiveWorker
2
+ class ModesMap
3
+
4
+ attr_reader :modes_hash
5
+
6
+ def initialize
7
+ @modes_hash = Hash.new do |hash, key|
8
+ inner_hash = {}
9
+ hash[key] = inner_hash
10
+ inner_hash
11
+ end
12
+ end
13
+
14
+ def add_mode(mode_name, field_maps)
15
+ modes_hash[normalize_mode_name(mode_name)].merge! field_maps
16
+ end
17
+
18
+ def normalize_mode_name(mode_name)
19
+ mode_name.to_sym
20
+ end
21
+
22
+ def modes
23
+ modes_hash.keys
24
+ end
25
+
26
+ def supports?(mode_name)
27
+ modes.include? normalize_mode_name(mode_name)
28
+ end
29
+
30
+ def mode(mode_name)
31
+ if supports? mode_name
32
+ modes_hash[normalize_mode_name(mode_name)]
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,9 @@
1
+ module ActiveWorker
2
+ class NotificationEvent < ActiveWorker::Event
3
+
4
+ def generate_message
5
+ "#{configuration.event_name} has been notified"
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveWorker
2
+ class ParentEvent < ActiveWorker::Event
3
+ extend Behavior::CreateFromError
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveWorker
2
+ class StartedEvent < ActiveWorker::Event
3
+ def generate_message
4
+ "#{configuration.event_name} started"
5
+ end
6
+
7
+ after_create :notify_root_of_child_started
8
+
9
+ end
10
+ end
@@ -0,0 +1,46 @@
1
+ module ActiveWorker
2
+ module Templatable
3
+
4
+ module ClassMethods
5
+ def templates_with_names
6
+ Template.with_names(self)
7
+ end
8
+ end
9
+
10
+ def self.included(base)
11
+ base.field :renderable, :type => Boolean, :default => true
12
+ base.field :template_name
13
+
14
+ base.extend(ClassMethods)
15
+ end
16
+
17
+ def find_template
18
+ child_template_ids = configurations.map(&:find_template).map(&:id)
19
+
20
+ attributes_for_template = {}
21
+ attributes_for_template[:configuration_type] = self.class.name
22
+
23
+ if child_template_ids.any?
24
+ attributes_for_template[:child_template_ids] = child_template_ids
25
+ end
26
+
27
+ self.class.template_fields.each do |field|
28
+ attributes_for_template[field] = read_attribute(field)
29
+ end
30
+
31
+ template = Template.find_or_create_by(attributes_for_template)
32
+ template.name = template_name if template_name && (! template_name.empty?)
33
+ template.save!
34
+ template
35
+ end
36
+
37
+ def template_name_or(input_string)
38
+ if template_name && (! template_name.empty?)
39
+ template_name
40
+ else
41
+ input_string
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,41 @@
1
+ module ActiveWorker
2
+ class Template
3
+ include Mongoid::Document
4
+
5
+ has_and_belongs_to_many :child_templates, :class_name => "ActiveWorker::Template", :inverse_of => :parent_templates
6
+
7
+ field :name
8
+ field :configuration_type
9
+
10
+ scope :with_names, ->(configuration_class) { where(:name.exists => true, :configuration_type => configuration_class.name)}
11
+
12
+ def name_for_display
13
+ if(name && !(name.empty?))
14
+ name
15
+ else
16
+ configuration_type.split("::")[0..-2].join(" ")
17
+ end
18
+ end
19
+
20
+ def build_configuration
21
+ configuration = configuration_class.new
22
+
23
+ configuration_class.template_fields.each do |field|
24
+ configuration.write_attribute(field,read_attribute(field))
25
+ end
26
+
27
+ configuration.template_name = name
28
+
29
+ child_template_ids.each do |child_id|
30
+ child = Template.find(child_id)
31
+ configuration.configurations << child.build_configuration
32
+ end
33
+
34
+ configuration
35
+ end
36
+
37
+ def configuration_class
38
+ configuration_type.constantize
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveWorker
2
+ class TerminationEvent < ActiveWorker::FinishedEvent
3
+
4
+ def self.from_termination(root_configuration)
5
+ events = []
6
+ root_configuration.configurations_for_events.each do |configuration|
7
+ events << create_termination_from_configuration(configuration) unless configuration.completed?
8
+ end
9
+ events
10
+ end
11
+
12
+ def self.create_termination_from_configuration(configuration)
13
+ constructor_options = {
14
+ :message => "#{configuration.event_name} was terminated",
15
+ :configuration => configuration,
16
+ }
17
+ create! constructor_options
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ test:
2
+ sessions:
3
+ default:
4
+ database: active_worker_test
5
+ hosts:
6
+ - localhost:27017
7
+ options:
8
+ consistency: :strong
9
+ safe: true
10
+ identity_map_enabled: true
11
+ options:
12
+ preload_models: true
13
+
14
+
15
+
16
+ #settings: &settings
17
+ # autocreate_indexes: true
18
+ # identity_map_enabled: true
19
+ #
20
+ #defaults: &defaults
21
+ # <<: *settings
22
+ # host: localhost
23
+ # port: 27017
24
+ #
25
+ #test:
26
+ # <<: *defaults
27
+ # database: active_worker_test
28
+ # logger: false
@@ -0,0 +1,123 @@
1
+ require_relative "test_helper"
2
+
3
+ module ActiveWorker
4
+ class ActsAsRootObjectTest < ActiveSupport::TestCase
5
+
6
+
7
+ test "renderable configuration hashes returns array of configuration hashes" do
8
+ root = Rootable.create
9
+ topconfig1 = root.configurations.create({}, TemplatableTopConfig)
10
+ topconfig2 = root.configurations.create({}, TemplatableTopConfig)
11
+ child_config1 = topconfig2.configurations.create({}, TemplatableChildConfig)
12
+
13
+ assert_equal 2, root.renderable_configuration_hashes.size
14
+ assert_equal 1, root.renderable_configuration_hashes[1]["configurations"].size
15
+
16
+ end
17
+
18
+ test "renderable configurations hashes only returns with renderable configurations" do
19
+
20
+ root = Rootable.create
21
+
22
+ topconfig1 = root.configurations.create({}, TemplatableTopConfig)
23
+ topconfig2 = root.configurations.create({}, TopConfig)
24
+ templatable_child_config1 = topconfig1.configurations.create({}, TemplatableChildConfig)
25
+ child_config1 = topconfig1.configurations.create({}, ChildConfig)
26
+
27
+ templatable_child_config2 = topconfig2.configurations.create({}, TemplatableChildConfig)
28
+ child_config2 = topconfig2.configurations.create({}, ChildConfig)
29
+
30
+ renderable_hashes = root.renderable_configuration_hashes
31
+
32
+ assert_equal 1, renderable_hashes.size
33
+ assert_equal 1, renderable_hashes[0]["configurations"].size
34
+
35
+ end
36
+
37
+ test "sets flags on immediate child configurations" do
38
+ root = Rootable.create flags: {"flag" => true}
39
+
40
+ topconfig1 = root.configurations.create({}, TemplatableTopConfig)
41
+ topconfig2 = root.configurations.create({}, TopConfig)
42
+ root.set_flags
43
+ topconfig1.reload
44
+ topconfig2.reload
45
+
46
+ templatable_child_config1 = topconfig1.configurations.create({}, TemplatableChildConfig)
47
+ child_config1 = topconfig1.configurations.create({}, ChildConfig)
48
+
49
+ templatable_child_config2 = topconfig2.configurations.create({}, TemplatableChildConfig)
50
+ child_config2 = topconfig2.configurations.create({}, ChildConfig)
51
+
52
+ assert topconfig1.flags["flag"]
53
+ assert topconfig2.flags["flag"]
54
+ assert templatable_child_config1.flags["flag"]
55
+ assert child_config1.flags["flag"]
56
+ assert templatable_child_config2.flags["flag"]
57
+ assert child_config2.flags["flag"]
58
+ end
59
+
60
+ test "is completed when configurations complete" do
61
+ root = Rootable.create
62
+ topconfig1 = root.configurations.create({}, TemplatableTopConfig)
63
+ topconfig2 = root.configurations.create({}, TemplatableTopConfig)
64
+
65
+ root.reload
66
+ assert_equal false, root.completed?
67
+
68
+ topconfig1.finished
69
+
70
+ root.reload
71
+ assert_equal false, root.completed?
72
+
73
+ topconfig2.finished
74
+
75
+ root.reload
76
+ assert_equal true, root.completed?
77
+
78
+ end
79
+
80
+ test "duration calculates when completed" do
81
+ root = Rootable.create
82
+ topconfig1 = root.configurations.create({}, TemplatableTopConfig)
83
+
84
+ initial_duration = root.duration
85
+
86
+ assert initial_duration > 0
87
+
88
+ topconfig1.finished
89
+
90
+ final_duration = root.duration
91
+
92
+ assert initial_duration < final_duration
93
+ end
94
+
95
+ test "duration returns 0 if completed but missing finished_at" do
96
+ root = Rootable.create
97
+
98
+ root.root_object_finished = true
99
+
100
+ duration = root.duration
101
+
102
+ assert_equal 0, duration
103
+ end
104
+
105
+
106
+ test "sets finished_at correctly" do
107
+ root = Rootable.create
108
+ topconfig1 = TemplatableTopConfig.create
109
+ root.configurations << topconfig1
110
+
111
+ root.reload
112
+ assert_nil root.finished_at
113
+
114
+ topconfig1.finished
115
+ root.reload
116
+
117
+ assert root.completed?
118
+ assert root.finished_at.to_i > 0
119
+ end
120
+
121
+ end
122
+
123
+ end
@@ -0,0 +1,44 @@
1
+ require_relative "test_helper"
2
+
3
+ module ActiveWorker
4
+
5
+ class CanBeNotifiedTest < ActiveSupport::TestCase
6
+
7
+ class Configuration < ActiveWorker::Configuration
8
+ include Expandable
9
+ config_field :wait_for_notifications, default: true
10
+ config_field :nodes
11
+
12
+ def expansion_maps_for_threads
13
+ nodes.split(",").map { |node| {nodes: node} }
14
+ end
15
+ end
16
+
17
+ class Controller < ActiveWorker::Controller
18
+ include Behavior::CanBeNotified
19
+
20
+ def execute
21
+ sleep 0.1 until configuration.notified?
22
+ end
23
+ end
24
+
25
+ test "controller forwards notifications" do
26
+ Controller::ClassMethods::SLEEP_DURATION = 0.1
27
+
28
+ nodes = "thread1, thread2, thread3"
29
+ configuration = CanBeNotifiedTest::Configuration.create nodes: nodes
30
+
31
+ configuration.launch
32
+ sleep 0.1 until (StartedEvent.count == nodes.split(",").size)
33
+ configuration.notify
34
+
35
+ wait_for_all_configurations
36
+ assert_no_failures
37
+
38
+ assert_equal 3, ActiveWorker::FinishedEvent.count
39
+ end
40
+
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,281 @@
1
+ require_relative "test_helper"
2
+
3
+
4
+ module ActiveWorker
5
+ class ConfigurationTest < ActiveSupport::TestCase
6
+
7
+ test "can scope a child configuration type using mine" do
8
+ parent_config = TopConfig.create(top_field: "top field")
9
+ child_config0 = ChildConfig.create(child_field: "child field", parent_configuration: parent_config)
10
+ child_config1 = ChildConfig.create(child_field: "different child field")
11
+
12
+ assert_equal 1, parent_config.child_configs.count
13
+ assert_equal child_config0, parent_config.child_configs.first
14
+
15
+ end
16
+
17
+ test "Child Config is of the correct type" do
18
+ parent_config = TopConfig.create(top_field: "top field")
19
+ child_config0 = ChildConfig.create(child_field: "child field", parent_configuration: parent_config)
20
+
21
+ assert_equal TopConfig, parent_config.class
22
+
23
+ child_config = ChildConfig.where(parent_configuration_id: parent_config.to_param).first
24
+ assert_equal ChildConfig, child_config.class
25
+
26
+ end
27
+
28
+ test "completed?" do
29
+ config = TopConfig.create
30
+ assert_equal false, config.completed?
31
+ FinishedEvent.create configuration: config
32
+ assert config.completed?
33
+ end
34
+
35
+ test "passses down root object when saved" do
36
+ root = Rootable.create
37
+ config = TopConfig.new
38
+ root.configurations << config
39
+ config2 = ChildConfig.new parent_configuration: config
40
+
41
+ config.save!
42
+ config2.save!
43
+ assert_equal root, config2.root_object
44
+ end
45
+
46
+ test "passes down flags when saved" do
47
+ root = Rootable.create flags: {"analyze_performance" => true}
48
+ config = TopConfig.new flags: root.flags
49
+ root.configurations << config
50
+ config2 = ChildConfig.new parent_configuration: config
51
+
52
+ config.save!
53
+ config2.save!
54
+ assert config2.flags["analyze_performance"]
55
+ end
56
+
57
+ test "can get configuration hierarchy" do
58
+ config = TopConfig.create
59
+ config2 = ChildConfig.create parent_configuration: config
60
+ config3 = ChildConfig.create parent_configuration: config
61
+ config4 = ChildConfig.create parent_configuration: config3
62
+ config5 = ChildConfig.create parent_configuration: config3
63
+
64
+ root = Rootable.create
65
+ root.configurations << config
66
+
67
+ top_config = Configuration.get_as_hash_by_root_object(root).first
68
+
69
+ assert_equal config.to_param, top_config["_id"]
70
+ assert_equal config2.to_param, top_config["configurations"][0]["_id"]
71
+ assert_equal config3.to_param, top_config["configurations"][1]["_id"]
72
+
73
+ assert_equal config4.to_param, top_config["configurations"][1]["configurations"][0]["_id"]
74
+ assert_equal config5.to_param, top_config["configurations"][1]["configurations"][1]["_id"]
75
+ end
76
+
77
+ test "can get configurations as flat array" do
78
+ config = TopConfig.create
79
+ config2 = ChildConfig.create parent_configuration: config
80
+ config3 = ChildConfig.create parent_configuration: config
81
+ config4 = ChildConfig.create parent_configuration: config3
82
+ config5 = ChildConfig.create parent_configuration: config3
83
+
84
+ root = Rootable.create
85
+ root.configurations << config
86
+
87
+ configs = Configuration.get_as_flat_hash_by_root_object(root)
88
+
89
+ assert_equal 5, configs.size
90
+ end
91
+
92
+ test "can get renderable configuration hierarchy" do
93
+ root = Rootable.create
94
+ config = TopConfig.create renderable: true
95
+ root.configurations << config
96
+ config2 = ChildConfig.create parent_configuration: config, renderable: true
97
+ config3 = ChildConfig.create parent_configuration: config, renderable: false
98
+ config4 = ChildConfig.create parent_configuration: config3, renderable: true
99
+ config5 = ChildConfig.create parent_configuration: config3, renderable: false
100
+ config6 = ChildConfig.create parent_configuration: config2, renderable: true
101
+ config7 = ChildConfig.create parent_configuration: config6, renderable: false
102
+ config8 = ChildConfig.create parent_configuration: config6, renderable: true
103
+
104
+ top_config = Configuration.get_renderable_hash_by_root_object(root).first
105
+ assert_equal config.to_param, top_config["_id"]
106
+ assert_equal 1, top_config["configurations"].size
107
+ assert_equal config2.to_param, top_config["configurations"][0]["_id"]
108
+
109
+ assert_equal config6.to_param, top_config["configurations"][0]["configurations"][0]["_id"]
110
+ assert_equal 1, top_config["configurations"][0]["configurations"].size
111
+ assert_equal config8.to_param, top_config["configurations"][0]["configurations"][0]["configurations"][0]["_id"]
112
+ end
113
+
114
+ test "can get renderable hash for given configuration" do
115
+ config = TopConfig.create renderable: true
116
+ config2 = ChildConfig.create parent_configuration: config, renderable: true
117
+ config3 = ChildConfig.create parent_configuration: config, renderable: false
118
+
119
+ top_config = Configuration.renderable_hash_for_configuration(config.id)
120
+
121
+ assert_equal config.to_param, top_config["_id"]
122
+ assert_equal 1, top_config["configurations"].size
123
+ assert_equal config2.to_param, top_config["configurations"][0]["_id"]
124
+ assert_equal "ActiveWorker::TopConfig", top_config["_type"]
125
+ end
126
+
127
+ test "Base Configurations can be hashable with type" do
128
+ config = Configuration.create renderable: true
129
+ config2 = Configuration.create parent_configuration: config, renderable: true
130
+ config3 = Configuration.create parent_configuration: config, renderable: false
131
+
132
+ top_config = Configuration.renderable_hash_for_configuration(config.id)
133
+
134
+ assert_equal config.to_param.to_s, top_config["_id"]
135
+ assert_equal 1, top_config["configurations"].size
136
+ assert_equal config2.to_param.to_s, top_config["configurations"][0]["_id"]
137
+
138
+ assert_equal "ActiveWorkerConfiguration", top_config["_type"]
139
+ assert_equal "ActiveWorkerConfiguration", top_config["configurations"][0]["_type"]
140
+
141
+ end
142
+
143
+ test "can load hashes from configurations that no longer exist" do
144
+ module SoonToNotExist
145
+ class TopConfig < Configuration
146
+ field :top_field
147
+
148
+ def child_configs
149
+ ChildConfig.mine(self).all
150
+ end
151
+ end
152
+
153
+ class ChildConfig < Configuration
154
+ field :child_field
155
+ end
156
+ end
157
+ root = Rootable.create
158
+ config = SoonToNotExist::TopConfig.create
159
+ root.configurations << config
160
+ config2 = SoonToNotExist::ChildConfig.create parent_configuration: config
161
+ id1 = config.to_param
162
+ id2 = config2.to_param
163
+
164
+ ActiveWorker::ConfigurationTest::SoonToNotExist.send(:remove_const, :TopConfig)
165
+ ActiveWorker::ConfigurationTest::SoonToNotExist.send(:remove_const, :ChildConfig)
166
+
167
+ assert_raise NameError do
168
+ SoonToNotExist::TopConfig
169
+ end
170
+ assert_raise NameError do
171
+ SoonToNotExist::ChildConfig
172
+ end
173
+
174
+ top_config = Configuration.get_as_hash_by_root_object(root).first
175
+ assert_equal id1, top_config["_id"]
176
+ assert_equal id2, top_config["configurations"][0]["_id"]
177
+
178
+ end
179
+
180
+ test "can create started event" do
181
+ configuration = Configuration.create
182
+
183
+ configuration.started
184
+ assert_equal 1, StartedEvent.where(configuration_id: configuration.to_param).size
185
+ assert_match /#{configuration.event_name}/, StartedEvent.where(configuration_id: configuration.to_param).first.message
186
+ end
187
+
188
+ test "can create finished event" do
189
+ configuration = Configuration.create
190
+
191
+ configuration.finished
192
+ assert_equal 1, FinishedEvent.where(configuration_id: configuration.to_param).size
193
+ assert_match /#{configuration.event_name}/, FinishedEvent.where(configuration_id: configuration.to_param).first.message
194
+ end
195
+
196
+ test "can be notified" do
197
+ configuration = Configuration.create
198
+ assert_equal false, configuration.notified?
199
+ configuration.notify
200
+ assert configuration.notified?
201
+ end
202
+
203
+ test "can treat as hash" do
204
+ config = Configuration.create value: "value"
205
+
206
+ assert_equal "value", config[:value]
207
+
208
+ config[:value]= "value2"
209
+
210
+ assert_equal "value2", config[:value]
211
+
212
+ assert_nil config[:bad_method]
213
+
214
+ end
215
+
216
+ test "can retrieve hash of config fields" do
217
+ class TestConfig < Configuration
218
+ config_field :config_field
219
+ template_field :template_field
220
+ field :other_field
221
+ end
222
+
223
+ config = TestConfig.create config_field: "config_field",
224
+ template_field: "template_field",
225
+ other_field: "other_field"
226
+
227
+ expected_config_fields = {"config_field" => "config_field",
228
+ "template_field" => "template_field"}
229
+ assert_equal expected_config_fields, config.defined_fields
230
+ end
231
+
232
+ test "launch calls after launch methods" do
233
+ config = AfterLaunchConfig.create
234
+ config.expects(:after_launch_method).with([config])
235
+ config.stubs(:enqueue_job)
236
+ config.launch
237
+ end
238
+
239
+ test "launch returns configurations" do
240
+ config = AfterLaunchConfig.create
241
+ AfterLaunchConfig.any_instance.stubs(:enqueue_job)
242
+ after_launch_configs = ["after launch 1", "after launch 2"]
243
+
244
+ config.stubs(:after_launch_method).returns(after_launch_configs)
245
+
246
+ configs = config.launch
247
+ assert_equal 3, configs.size
248
+
249
+ assert_equal [config] + after_launch_configs, configs
250
+ end
251
+
252
+ test "can create configuration with root object directly" do
253
+ root = Rootable.create
254
+ configuration = nil
255
+ assert_nothing_raised Mongoid::Errors::InvalidSetPolymorphicRelation do
256
+ configuration = TopConfig.create root_object: root
257
+ end
258
+
259
+ assert_equal root, configuration.root_object
260
+ assert_equal 1, root.configurations.size
261
+ assert_equal configuration, root.configurations.first
262
+
263
+ end
264
+
265
+ test "can create create config with root object directly" do
266
+ root = Rootable.create
267
+ config = TopConfig.create root_object: root
268
+
269
+ assert_equal 1, root.configurations.count
270
+ assert_equal config, root.configurations.first
271
+
272
+ root.reload
273
+ config.reload
274
+
275
+ assert_equal 1, root.configurations.count
276
+ assert_equal config, root.configurations.first
277
+
278
+ end
279
+
280
+ end
281
+ end