lalala 4.0.0.dev.136 → 4.0.0.dev.141
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.
- checksums.yaml +4 -4
- data/.gitmodules +0 -3
- data/lalala.gemspec +2 -6
- data/lib/lalala/version.rb +1 -1
- data/lib/lalala.rb +0 -1
- metadata +19 -53
- data/vendor/deps/closure_tree/.gitignore +0 -12
- data/vendor/deps/closure_tree/.travis.yml +0 -22
- data/vendor/deps/closure_tree/.yardopts +0 -3
- data/vendor/deps/closure_tree/Gemfile +0 -2
- data/vendor/deps/closure_tree/MIT-LICENSE +0 -19
- data/vendor/deps/closure_tree/README.md +0 -641
- data/vendor/deps/closure_tree/Rakefile +0 -26
- data/vendor/deps/closure_tree/ci/Gemfile.rails-3.0.x +0 -5
- data/vendor/deps/closure_tree/ci/Gemfile.rails-3.1.x +0 -4
- data/vendor/deps/closure_tree/ci/Gemfile.rails-3.2.x +0 -4
- data/vendor/deps/closure_tree/closure_tree.gemspec +0 -31
- data/vendor/deps/closure_tree/lib/closure_tree/acts_as_tree.rb +0 -55
- data/vendor/deps/closure_tree/lib/closure_tree/columns.rb +0 -123
- data/vendor/deps/closure_tree/lib/closure_tree/deterministic_ordering.rb +0 -49
- data/vendor/deps/closure_tree/lib/closure_tree/model.rb +0 -386
- data/vendor/deps/closure_tree/lib/closure_tree/numeric_deterministic_ordering.rb +0 -93
- data/vendor/deps/closure_tree/lib/closure_tree/version.rb +0 -3
- data/vendor/deps/closure_tree/lib/closure_tree/with_advisory_lock.rb +0 -18
- data/vendor/deps/closure_tree/lib/closure_tree.rb +0 -8
- data/vendor/deps/closure_tree/spec/cuisine_type_spec.rb +0 -30
- data/vendor/deps/closure_tree/spec/db/database.yml +0 -19
- data/vendor/deps/closure_tree/spec/db/schema.rb +0 -109
- data/vendor/deps/closure_tree/spec/fixtures/labels.yml +0 -55
- data/vendor/deps/closure_tree/spec/fixtures/tags.yml +0 -98
- data/vendor/deps/closure_tree/spec/hash_tree_spec.rb +0 -91
- data/vendor/deps/closure_tree/spec/label_spec.rb +0 -356
- data/vendor/deps/closure_tree/spec/namespace_type_spec.rb +0 -13
- data/vendor/deps/closure_tree/spec/parallel_prepend_sibling_spec.rb +0 -45
- data/vendor/deps/closure_tree/spec/parallel_spec.rb +0 -59
- data/vendor/deps/closure_tree/spec/spec_helper.rb +0 -57
- data/vendor/deps/closure_tree/spec/support/models.rb +0 -74
- data/vendor/deps/closure_tree/spec/tag_spec.rb +0 -469
- data/vendor/deps/closure_tree/spec/user_spec.rb +0 -136
- data/vendor/deps/closure_tree/tests.sh +0 -19
@@ -1,356 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
def delete_all_labels
|
4
|
-
LabelHierarchy.delete_all
|
5
|
-
Label.delete_all
|
6
|
-
end
|
7
|
-
|
8
|
-
def create_label_tree
|
9
|
-
@d1 = Label.find_or_create_by_path %w(a1 b1 c1 d1)
|
10
|
-
@c1 = @d1.parent
|
11
|
-
@b1 = @c1.parent
|
12
|
-
@a1 = @b1.parent
|
13
|
-
@d2 = Label.find_or_create_by_path %w(a1 b1 c2 d2)
|
14
|
-
@c2 = @d2.parent
|
15
|
-
@d3 = Label.find_or_create_by_path %w(a2 b2 c3 d3)
|
16
|
-
@c3 = @d3.parent
|
17
|
-
@b2 = @c3.parent
|
18
|
-
@a2 = @b2.parent
|
19
|
-
Label.update_all("sort_order = id")
|
20
|
-
end
|
21
|
-
|
22
|
-
def create_preorder_tree(suffix = "")
|
23
|
-
%w(
|
24
|
-
a/l/n/r
|
25
|
-
a/l/n/q
|
26
|
-
a/l/n/p
|
27
|
-
a/l/n/o
|
28
|
-
a/l/m
|
29
|
-
a/b/h/i/j/k
|
30
|
-
a/b/c/d/g
|
31
|
-
a/b/c/d/f
|
32
|
-
a/b/c/d/e
|
33
|
-
).shuffle.each { |ea| Label.find_or_create_by_path(ea.split('/').collect { |ea| "#{ea}#{suffix}" }) }
|
34
|
-
|
35
|
-
Label.roots.each_with_index do |root, root_idx|
|
36
|
-
root.order_value = root_idx
|
37
|
-
root.save!
|
38
|
-
root.self_and_descendants.each do |ea|
|
39
|
-
ea.children.to_a.sort_by(&:name).each_with_index do |ea, idx|
|
40
|
-
ea.order_value = idx
|
41
|
-
ea.save!
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe Label do
|
48
|
-
|
49
|
-
context "destruction" do
|
50
|
-
it "properly destroys descendents" do
|
51
|
-
c = Label.find_or_create_by_path %w(a b c)
|
52
|
-
b = c.parent
|
53
|
-
a = c.root
|
54
|
-
a.destroy
|
55
|
-
Label.exists?(a).should be_false
|
56
|
-
Label.exists?(b).should be_false
|
57
|
-
Label.exists?(c).should be_false
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
context "Base Label class" do
|
62
|
-
it "should find or create by path" do
|
63
|
-
# class method:
|
64
|
-
c = Label.find_or_create_by_path(%w{grandparent parent child})
|
65
|
-
c.ancestry_path.should == %w{grandparent parent child}
|
66
|
-
c.name.should == "child"
|
67
|
-
c.parent.name.should == "parent"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
context "DateLabel" do
|
72
|
-
it "should find or create by path" do
|
73
|
-
date = DateLabel.find_or_create_by_path(%w{2011 November 23})
|
74
|
-
date.ancestry_path.should == %w{2011 November 23}
|
75
|
-
date.parent
|
76
|
-
date.self_and_ancestors.each { |ea| ea.class.should == DateLabel }
|
77
|
-
date.name.should == "23"
|
78
|
-
date.parent.name.should == "November"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context "DirectoryLabel" do
|
83
|
-
it "should find or create by path" do
|
84
|
-
dir = DirectoryLabel.find_or_create_by_path(%w{grandparent parent child})
|
85
|
-
dir.ancestry_path.should == %w{grandparent parent child}
|
86
|
-
dir.name.should == "child"
|
87
|
-
dir.parent.name.should == "parent"
|
88
|
-
dir.parent.parent.name.should == "grandparent"
|
89
|
-
dir.root.name.should == "grandparent"
|
90
|
-
dir.id.should_not == Label.find_or_create_by_path(%w{grandparent parent child})
|
91
|
-
dir.self_and_ancestors.each { |ea| ea.class.should == DirectoryLabel }
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
context "Mixed class tree" do
|
96
|
-
it "should support mixed type ancestors" do
|
97
|
-
[Label, DateLabel, DirectoryLabel, EventLabel].permutation do |classes|
|
98
|
-
delete_all_labels
|
99
|
-
classes.each { |c| c.all.should(be_empty, "class #{c} wasn't cleaned out") }
|
100
|
-
names = ('A'..'Z').to_a.first(classes.size)
|
101
|
-
instances = classes.collect { |clazz| clazz.new(:name => names.shift) }
|
102
|
-
a = instances.first
|
103
|
-
a.save!
|
104
|
-
a.name.should == "A"
|
105
|
-
instances[1..-1].each_with_index do |ea, idx|
|
106
|
-
instances[idx].children << ea
|
107
|
-
end
|
108
|
-
roots = classes.first.roots
|
109
|
-
i = instances.shift
|
110
|
-
roots.should =~ [i]
|
111
|
-
while (!instances.empty?) do
|
112
|
-
child = instances.shift
|
113
|
-
i.children.should =~ [child]
|
114
|
-
i = child
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
it "supports children << and add_child" do
|
120
|
-
a = EventLabel.create!(:name => "a")
|
121
|
-
b = DateLabel.new(:name => "b")
|
122
|
-
a.children << b
|
123
|
-
c = Label.new(:name => "c")
|
124
|
-
b.add_child(c)
|
125
|
-
|
126
|
-
a.self_and_descendants.collect do |ea|
|
127
|
-
ea.class
|
128
|
-
end.should == [EventLabel, DateLabel, Label]
|
129
|
-
|
130
|
-
a.self_and_descendants.collect do |ea|
|
131
|
-
ea.name
|
132
|
-
end.should == %w(a b c)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
context "find_all_by_generation" do
|
137
|
-
before :all do
|
138
|
-
delete_all_labels
|
139
|
-
create_label_tree
|
140
|
-
end
|
141
|
-
|
142
|
-
it "finds roots from the class method" do
|
143
|
-
Label.find_all_by_generation(0).to_a.should == [@a1, @a2]
|
144
|
-
end
|
145
|
-
|
146
|
-
it "finds roots from themselves" do
|
147
|
-
@a1.find_all_by_generation(0).to_a.should == [@a1]
|
148
|
-
end
|
149
|
-
|
150
|
-
it "finds itself for non-roots" do
|
151
|
-
@b1.find_all_by_generation(0).to_a.should == [@b1]
|
152
|
-
end
|
153
|
-
|
154
|
-
it "finds children for roots" do
|
155
|
-
Label.find_all_by_generation(1).to_a.should == [@b1, @b2]
|
156
|
-
end
|
157
|
-
|
158
|
-
it "finds children" do
|
159
|
-
@a1.find_all_by_generation(1).to_a.should == [@b1]
|
160
|
-
@b1.find_all_by_generation(1).to_a.should == [@c1, @c2]
|
161
|
-
end
|
162
|
-
|
163
|
-
it "finds grandchildren for roots" do
|
164
|
-
Label.find_all_by_generation(2).to_a.should == [@c1, @c2, @c3]
|
165
|
-
end
|
166
|
-
|
167
|
-
it "finds grandchildren" do
|
168
|
-
@a1.find_all_by_generation(2).to_a.should == [@c1, @c2]
|
169
|
-
@b1.find_all_by_generation(2).to_a.should == [@d1, @d2]
|
170
|
-
end
|
171
|
-
|
172
|
-
it "finds great-grandchildren for roots" do
|
173
|
-
Label.find_all_by_generation(3).to_a.should == [@d1, @d2, @d3]
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
context "loading through self_and_ scopes" do
|
178
|
-
before :all do
|
179
|
-
delete_all_labels
|
180
|
-
create_label_tree
|
181
|
-
end
|
182
|
-
|
183
|
-
it "self_and_descendants should result in one select" do
|
184
|
-
DB_QUERIES.clear
|
185
|
-
a1_array = @a1.self_and_descendants
|
186
|
-
a1_array.collect { |ea| ea.name }.should == %w(a1 b1 c1 c2 d1 d2)
|
187
|
-
DB_QUERIES.size.should == 1
|
188
|
-
end
|
189
|
-
|
190
|
-
it "self_and_ancestors should result in one select" do
|
191
|
-
DB_QUERIES.clear
|
192
|
-
d1_array = @d1.self_and_ancestors
|
193
|
-
d1_array.collect { |ea| ea.name }.should == %w(d1 c1 b1 a1)
|
194
|
-
DB_QUERIES.size.should == 1
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
context "deterministically orders with polymorphic siblings" do
|
199
|
-
before :each do
|
200
|
-
@parent = Label.create!(:name => "parent")
|
201
|
-
@a = EventLabel.new(:name => "a")
|
202
|
-
@b = DirectoryLabel.new(:name => "b")
|
203
|
-
@c = DateLabel.new(:name => "c")
|
204
|
-
@parent.children << @a
|
205
|
-
@a.append_sibling(@b)
|
206
|
-
@b.append_sibling(@c)
|
207
|
-
end
|
208
|
-
|
209
|
-
it "when inserted before" do
|
210
|
-
@b.append_sibling(@a)
|
211
|
-
# Have to reload because the sort_order will have changed out from under the references:
|
212
|
-
@b.reload.sort_order.should be < @a.reload.sort_order
|
213
|
-
@a.reload.sort_order.should be < @c.reload.sort_order
|
214
|
-
end
|
215
|
-
|
216
|
-
it "when inserted before" do
|
217
|
-
@b.append_sibling(@a, use_update_all = false)
|
218
|
-
# Have to reload because the sort_order will have changed out from under the references:
|
219
|
-
@b.reload.sort_order.should be < @a.reload.sort_order
|
220
|
-
@a.reload.sort_order.should be < @c.reload.sort_order
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
it "behaves like the readme" do
|
225
|
-
root = Label.create(:name => "root")
|
226
|
-
a = Label.create(:name => "a", :parent => root)
|
227
|
-
b = Label.create(:name => "b")
|
228
|
-
c = Label.create(:name => "c")
|
229
|
-
|
230
|
-
a.append_sibling(b)
|
231
|
-
root.reload.children.collect(&:name).should == %w(a b)
|
232
|
-
|
233
|
-
a.prepend_sibling(b)
|
234
|
-
root.reload.children.collect(&:name).should == %w(b a)
|
235
|
-
|
236
|
-
a.append_sibling(c)
|
237
|
-
root.reload.children.collect(&:name).should == %w(b a c)
|
238
|
-
|
239
|
-
b.append_sibling(c)
|
240
|
-
root.reload.children.collect(&:name).should == %w(b c a)
|
241
|
-
end
|
242
|
-
|
243
|
-
context "Deterministic siblings sort with custom integer column" do
|
244
|
-
delete_all_labels
|
245
|
-
fixtures :labels
|
246
|
-
|
247
|
-
before :each do
|
248
|
-
Label.rebuild!
|
249
|
-
end
|
250
|
-
|
251
|
-
it "orders siblings_before and siblings_after correctly" do
|
252
|
-
labels(:c16).self_and_siblings.to_a.should == [labels(:c16), labels(:c17), labels(:c18), labels(:c19)]
|
253
|
-
labels(:c16).siblings_before.to_a.should == []
|
254
|
-
labels(:c16).siblings_after.to_a.should == [labels(:c17), labels(:c18), labels(:c19)]
|
255
|
-
end
|
256
|
-
|
257
|
-
it "should prepend a node as a sibling of another node" do
|
258
|
-
labels(:c16).prepend_sibling(labels(:c17))
|
259
|
-
labels(:c16).self_and_siblings.to_a.should == [labels(:c17), labels(:c16), labels(:c18), labels(:c19)]
|
260
|
-
labels(:c19).prepend_sibling(labels(:c16))
|
261
|
-
labels(:c16).self_and_siblings.to_a.should == [labels(:c17), labels(:c18), labels(:c16), labels(:c19)]
|
262
|
-
labels(:c16).siblings_before.to_a.should == [labels(:c17), labels(:c18)]
|
263
|
-
labels(:c16).siblings_after.to_a.should == [labels(:c19)]
|
264
|
-
end
|
265
|
-
|
266
|
-
it "should prepend a node as a sibling of another node (!update_all)" do
|
267
|
-
labels(:c16).prepend_sibling(labels(:c17), false)
|
268
|
-
labels(:c16).self_and_siblings.to_a.should == [labels(:c17), labels(:c16), labels(:c18), labels(:c19)]
|
269
|
-
labels(:c19).reload.prepend_sibling(labels(:c16).reload, false)
|
270
|
-
labels(:c16).self_and_siblings.to_a.should == [labels(:c17), labels(:c18), labels(:c16), labels(:c19)]
|
271
|
-
labels(:c16).siblings_before.to_a.should == [labels(:c17), labels(:c18)]
|
272
|
-
labels(:c16).siblings_after.to_a.should == [labels(:c19)]
|
273
|
-
end
|
274
|
-
|
275
|
-
it "appends a node as a sibling of another node" do
|
276
|
-
labels(:c19).append_sibling(labels(:c17))
|
277
|
-
labels(:c16).self_and_siblings.to_a.should == [labels(:c16), labels(:c18), labels(:c19), labels(:c17)]
|
278
|
-
labels(:c16).append_sibling(labels(:c19))
|
279
|
-
labels(:c16).self_and_siblings.to_a.should == [labels(:c16), labels(:c19), labels(:c18), labels(:c17)]
|
280
|
-
labels(:c16).siblings_before.to_a.should == []
|
281
|
-
labels(:c16).siblings_after.to_a.should == labels(:c16).siblings.to_a
|
282
|
-
end
|
283
|
-
|
284
|
-
it "should move a node before another node (update_all)" do
|
285
|
-
labels(:c2).ancestry_path.should == %w{a1 b2 c2}
|
286
|
-
labels(:b2).prepend_sibling(labels(:c2))
|
287
|
-
labels(:c2).ancestry_path.should == %w{a1 c2}
|
288
|
-
labels(:c2).self_and_siblings.to_a.should == [labels(:b1), labels(:c2), labels(:b2)]
|
289
|
-
labels(:c2).siblings_before.to_a.should == [labels(:b1)]
|
290
|
-
labels(:c2).siblings_after.to_a.should == [labels(:b2)]
|
291
|
-
labels(:b1).siblings_after.to_a.should == [labels(:c2), labels(:b2)]
|
292
|
-
end
|
293
|
-
|
294
|
-
it "should move a node after another node (update_all)" do
|
295
|
-
labels(:c2).ancestry_path.should == %w{a1 b2 c2}
|
296
|
-
labels(:b2).append_sibling(labels(:c2))
|
297
|
-
labels(:c2).ancestry_path.should == %w{a1 c2}
|
298
|
-
labels(:c2).self_and_siblings.to_a.should == [labels(:b1), labels(:b2), labels(:c2)]
|
299
|
-
end
|
300
|
-
|
301
|
-
it "should move a node before another node" do
|
302
|
-
labels(:c2).ancestry_path.should == %w{a1 b2 c2}
|
303
|
-
labels(:b2).prepend_sibling(labels(:c2), false)
|
304
|
-
labels(:c2).ancestry_path.should == %w{a1 c2}
|
305
|
-
labels(:c2).self_and_siblings.to_a.should == [labels(:b1), labels(:c2), labels(:b2)]
|
306
|
-
end
|
307
|
-
|
308
|
-
it "should move a node before another node which has an uninitialized sort_order" do
|
309
|
-
labels(:f3).ancestry_path.should == %w{f3}
|
310
|
-
labels(:e2).children << labels(:f3)
|
311
|
-
labels(:f3).reload.ancestry_path.should == %w{a1 b2 c2 d2 e2 f3}
|
312
|
-
labels(:f3).self_and_siblings.to_a.should == [labels(:f3)]
|
313
|
-
labels(:f3).prepend_sibling labels(:f4)
|
314
|
-
labels(:f3).siblings_before.to_a.should == [labels(:f4)]
|
315
|
-
labels(:f3).self_and_siblings.to_a.should == [labels(:f4), labels(:f3)]
|
316
|
-
end
|
317
|
-
|
318
|
-
it "should move a node after another node which has an uninitialized sort_order" do
|
319
|
-
labels(:f3).ancestry_path.should == %w{f3}
|
320
|
-
labels(:e2).children << labels(:f3)
|
321
|
-
labels(:f3).reload.ancestry_path.should == %w{a1 b2 c2 d2 e2 f3}
|
322
|
-
labels(:f3).self_and_siblings.to_a.should == [labels(:f3)]
|
323
|
-
labels(:f3).append_sibling labels(:f4)
|
324
|
-
labels(:f3).siblings_after.to_a.should == [labels(:f4)]
|
325
|
-
labels(:f3).self_and_siblings.to_a.should == [labels(:f3), labels(:f4)]
|
326
|
-
end
|
327
|
-
|
328
|
-
it "should move a node after another node" do
|
329
|
-
labels(:c2).ancestry_path.should == %w{a1 b2 c2}
|
330
|
-
labels(:b2).append_sibling(labels(:c2), false)
|
331
|
-
labels(:c2).ancestry_path.should == %w{a1 c2}
|
332
|
-
labels(:c2).self_and_siblings.to_a.should == [labels(:b1), labels(:b2), labels(:c2)]
|
333
|
-
labels(:c2).append_sibling(labels(:e2), false)
|
334
|
-
labels(:e2).self_and_siblings.to_a.should == [labels(:b1), labels(:b2), labels(:c2), labels(:e2)]
|
335
|
-
labels(:a1).self_and_descendants.collect(&:name).should == %w(a1 b1 b2 c2 e2 d2 c1-six c1-seven c1-eight c1-nine)
|
336
|
-
labels(:a1).leaves.collect(&:name).should == %w(b2 e2 d2 c1-six c1-seven c1-eight c1-nine)
|
337
|
-
end
|
338
|
-
end
|
339
|
-
|
340
|
-
context "preorder" do
|
341
|
-
it "returns descendants in proper order" do
|
342
|
-
delete_all_labels
|
343
|
-
create_preorder_tree
|
344
|
-
a = Label.root
|
345
|
-
a.name.should == "a"
|
346
|
-
expected = ('a'..'r').to_a
|
347
|
-
a.self_and_descendants_preordered.collect { |ea| ea.name }.should == expected
|
348
|
-
Label.roots_and_descendants_preordered.collect { |ea| ea.name }.should == expected
|
349
|
-
create_preorder_tree("1")
|
350
|
-
# Should be no change:
|
351
|
-
a.reload.self_and_descendants_preordered.collect { |ea| ea.name }.should == expected
|
352
|
-
expected += ('a'..'r').collect { |ea| "#{ea}1" }
|
353
|
-
Label.roots_and_descendants_preordered.collect { |ea| ea.name }.should == expected
|
354
|
-
end
|
355
|
-
end unless ENV["DB"] == "sqlite"
|
356
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Namespace::Type do
|
4
|
-
|
5
|
-
context "class injection" do
|
6
|
-
it "should build hierarchy classname correctly" do
|
7
|
-
Namespace::Type.hierarchy_class.to_s.should == "Namespace::TypeHierarchy"
|
8
|
-
Namespace::Type.hierarchy_class_name.should == "Namespace::TypeHierarchy"
|
9
|
-
Namespace::Type.short_hierarchy_class_name.should == "TypeHierarchy"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'securerandom'
|
3
|
-
|
4
|
-
describe "threadhot" do
|
5
|
-
|
6
|
-
before :each do
|
7
|
-
LabelHierarchy.delete_all
|
8
|
-
Label.delete_all
|
9
|
-
@iterations = 5
|
10
|
-
@workers = 8
|
11
|
-
end
|
12
|
-
|
13
|
-
def prepend_sibling_at_even_second(run_at)
|
14
|
-
ActiveRecord::Base.connection.reconnect!
|
15
|
-
sibling = Label.new(:name => SecureRandom.hex(10))
|
16
|
-
target = Label.find(@target.id)
|
17
|
-
sleep(run_at - Time.now.to_f)
|
18
|
-
target.prepend_sibling sibling
|
19
|
-
end
|
20
|
-
|
21
|
-
def run_workers
|
22
|
-
start_time = Time.now.to_i + 2
|
23
|
-
@times = @iterations.times.collect { |ea| start_time + (ea * 2) }
|
24
|
-
@names = @times.collect { |ea| ea.to_s }
|
25
|
-
@threads = @workers.times.collect do
|
26
|
-
Thread.new do
|
27
|
-
@times.each { |ea| prepend_sibling_at_even_second(ea) }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
@threads.each { |ea| ea.join }
|
31
|
-
end
|
32
|
-
|
33
|
-
it "prepend_sibling on a non-root node doesn't cause deadlocks" do
|
34
|
-
@target = Label.find_or_create_by_path %w(root parent)
|
35
|
-
run_workers
|
36
|
-
children = Label.roots
|
37
|
-
uniq_sort_orders = children.collect { |ea| ea.sort_order }.uniq
|
38
|
-
children.size.should == uniq_sort_orders.size
|
39
|
-
|
40
|
-
# The only non-root node should be "root":
|
41
|
-
Label.all.select { |ea| ea.root? }.should == [@target.parent]
|
42
|
-
end
|
43
|
-
|
44
|
-
# SQLite doesn't like parallelism, and Rails 3.0 and 3.1 have known threading issues. SKIP.
|
45
|
-
end if ((ENV["DB"] != "sqlite3") && (ActiveRecord::VERSION::STRING =~ /^3.2/))
|
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "threadhot" do
|
4
|
-
|
5
|
-
before :each do
|
6
|
-
TagHierarchy.delete_all
|
7
|
-
Tag.delete_all
|
8
|
-
@iterations = 5
|
9
|
-
@workers = 8
|
10
|
-
@parent = nil
|
11
|
-
end
|
12
|
-
|
13
|
-
def find_or_create_at_even_second(run_at)
|
14
|
-
sleep(run_at - Time.now.to_f)
|
15
|
-
ActiveRecord::Base.connection.reconnect!
|
16
|
-
(@parent || Tag).find_or_create_by_path([run_at.to_s, :a, :b, :c].compact)
|
17
|
-
end
|
18
|
-
|
19
|
-
def run_workers
|
20
|
-
start_time = Time.now.to_i + 2
|
21
|
-
@times = @iterations.times.collect { |ea| start_time + (ea * 2) }
|
22
|
-
@names = @times.collect { |ea| ea.to_s }
|
23
|
-
@threads = @workers.times.collect do
|
24
|
-
Thread.new do
|
25
|
-
@times.each { |ea| find_or_create_at_even_second(ea) }
|
26
|
-
end
|
27
|
-
end
|
28
|
-
@threads.each { |ea| ea.join }
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
it "class method will not create dupes" do
|
33
|
-
run_workers
|
34
|
-
Tag.roots.collect { |ea| ea.name.to_i }.should =~ @times
|
35
|
-
# No dupe children:
|
36
|
-
%w(a b c).each do |ea|
|
37
|
-
Tag.find_all_by_name(ea).size.should == @iterations
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
it "instance method will not create dupes" do
|
42
|
-
@parent = Tag.create!(:name => "root")
|
43
|
-
run_workers
|
44
|
-
@parent.reload.children.collect { |ea| ea.name.to_i }.should =~ @times
|
45
|
-
Tag.find_all_by_name(@names).size.should == @iterations
|
46
|
-
%w(a b c).each do |ea|
|
47
|
-
Tag.find_all_by_name(ea).size.should == @iterations
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
it "creates dupe roots without advisory locks" do
|
52
|
-
# disable with_advisory_lock:
|
53
|
-
Tag.should_receive(:with_advisory_lock).any_number_of_times { |lock_name, &block| block.call }
|
54
|
-
run_workers
|
55
|
-
Tag.find_all_by_name(@names).size.should > @iterations
|
56
|
-
end
|
57
|
-
|
58
|
-
# SQLite doesn't like parallelism, and Rails 3.0 and 3.1 have known threading issues. SKIP.
|
59
|
-
end if ((ENV["DB"] != "sqlite") && (ActiveRecord::VERSION::STRING =~ /^3.2/))
|
@@ -1,57 +0,0 @@
|
|
1
|
-
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
-
plugin_test_dir = File.dirname(__FILE__)
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'bundler/setup'
|
6
|
-
|
7
|
-
require 'rspec'
|
8
|
-
require 'logger'
|
9
|
-
|
10
|
-
require 'action_controller' # rspec-rails needs this :(
|
11
|
-
require 'closure_tree'
|
12
|
-
require 'tmpdir'
|
13
|
-
|
14
|
-
#log = Logger.new(STDOUT)
|
15
|
-
#log.sev_threshold = Logger::DEBUG
|
16
|
-
#ActiveRecord::Base.logger = log
|
17
|
-
|
18
|
-
require 'yaml'
|
19
|
-
require 'erb'
|
20
|
-
ENV["DB"] ||= "mysql"
|
21
|
-
ActiveRecord::Base.table_name_prefix = ENV['DB_PREFIX'].to_s
|
22
|
-
ActiveRecord::Base.table_name_suffix = ENV['DB_SUFFIX'].to_s
|
23
|
-
ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(plugin_test_dir + "/db/database.yml")).result)
|
24
|
-
ActiveRecord::Base.establish_connection(ENV["DB"])
|
25
|
-
ActiveRecord::Migration.verbose = false
|
26
|
-
require 'db/schema'
|
27
|
-
require 'support/models'
|
28
|
-
require 'rspec/rails' # TODO: clean this up-- I don't want to pull the elephant through the mouse hole just for fixture support
|
29
|
-
|
30
|
-
DB_QUERIES = []
|
31
|
-
|
32
|
-
ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
|
33
|
-
def log_with_query_append(query, *args, &block)
|
34
|
-
DB_QUERIES << query
|
35
|
-
log_without_query_append(query, *args, &block)
|
36
|
-
end
|
37
|
-
|
38
|
-
alias_method_chain :log, :query_append
|
39
|
-
end
|
40
|
-
|
41
|
-
Thread.abort_on_exception = true
|
42
|
-
|
43
|
-
RSpec.configure do |config|
|
44
|
-
config.fixture_path = "#{plugin_test_dir}/fixtures"
|
45
|
-
# true runs the tests 1 second faster, but then you can't
|
46
|
-
# see what's going on while debuggering with different db connections.
|
47
|
-
config.use_transactional_fixtures = false
|
48
|
-
config.after(:each) do
|
49
|
-
DB_QUERIES.clear
|
50
|
-
end
|
51
|
-
config.before(:all) do
|
52
|
-
ENV['FLOCK_DIR'] = Dir.mktmpdir
|
53
|
-
end
|
54
|
-
config.after(:all) do
|
55
|
-
FileUtils.remove_entry_secure ENV['FLOCK_DIR']
|
56
|
-
end
|
57
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'uuidtools'
|
2
|
-
|
3
|
-
class Tag < ActiveRecord::Base
|
4
|
-
acts_as_tree :dependent => :destroy, :order => "name"
|
5
|
-
before_destroy :add_destroyed_tag
|
6
|
-
attr_accessible :name
|
7
|
-
|
8
|
-
def to_s
|
9
|
-
name
|
10
|
-
end
|
11
|
-
|
12
|
-
def add_destroyed_tag
|
13
|
-
# Proof for the tests that the destroy rather than the delete method was called:
|
14
|
-
DestroyedTag.create(:name => name)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class DestroyedTag < ActiveRecord::Base
|
19
|
-
attr_accessible :name
|
20
|
-
end
|
21
|
-
|
22
|
-
class User < ActiveRecord::Base
|
23
|
-
acts_as_tree :parent_column_name => "referrer_id",
|
24
|
-
:name_column => 'email',
|
25
|
-
:hierarchy_class_name => 'ReferralHierarchy',
|
26
|
-
:hierarchy_table_name => 'referral_hierarchies'
|
27
|
-
|
28
|
-
has_many :contracts
|
29
|
-
|
30
|
-
def indirect_contracts
|
31
|
-
Contract.where(:user_id => descendant_ids)
|
32
|
-
end
|
33
|
-
|
34
|
-
attr_accessible :email, :referrer
|
35
|
-
|
36
|
-
def to_s
|
37
|
-
email
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class Contract < ActiveRecord::Base
|
42
|
-
belongs_to :user
|
43
|
-
end
|
44
|
-
|
45
|
-
class Label < ActiveRecord::Base
|
46
|
-
attr_accessible :name # < - make sure order doesn't matter
|
47
|
-
acts_as_tree :order => "sort_order",
|
48
|
-
:parent_column_name => "mother_id",
|
49
|
-
:dependent => :destroy
|
50
|
-
|
51
|
-
def to_s
|
52
|
-
"#{self.class}: #{name}"
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
class EventLabel < Label
|
57
|
-
end
|
58
|
-
|
59
|
-
class DateLabel < Label
|
60
|
-
end
|
61
|
-
|
62
|
-
class DirectoryLabel < Label
|
63
|
-
end
|
64
|
-
|
65
|
-
class CuisineType < ActiveRecord::Base
|
66
|
-
acts_as_tree
|
67
|
-
end
|
68
|
-
|
69
|
-
module Namespace
|
70
|
-
class Type < ActiveRecord::Base
|
71
|
-
acts_as_tree :dependent => :destroy
|
72
|
-
attr_accessible :name
|
73
|
-
end
|
74
|
-
end
|