updater 0.9.4 → 0.10.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/Rakefile +8 -9
- data/VERSION +1 -1
- data/lib/updater/fork_worker.rb +1 -1
- data/lib/updater/orm/activerocord.rb +23 -0
- data/lib/updater/orm/datamapper.rb +28 -8
- data/lib/updater/orm/mock.rb +155 -0
- data/lib/updater/orm/mongo.rb +50 -15
- data/lib/updater/orm/orm.rb +3 -1
- data/lib/updater/setup.rb +24 -7
- data/lib/updater/thread_worker.rb +5 -0
- data/lib/updater/update.rb +8 -5
- data/spec/chained_spec.rb +3 -2
- data/spec/datamapper_orm_spec.rb +7 -0
- data/spec/errors_spec.rb +1 -1
- data/spec/fooclass.rb +42 -11
- data/spec/fooclass_spec.rb +38 -0
- data/spec/fork_worker_instance_spec.rb +0 -19
- data/spec/fork_worker_spec.rb +1 -0
- data/spec/mock_orm_spec.rb +7 -0
- data/spec/mongo_orm_spec.rb +7 -0
- data/spec/named_request_spec.rb +1 -4
- data/spec/orm_lint.rb +292 -0
- data/spec/params_sub_spec.rb +2 -1
- data/spec/results.html +1567 -0
- data/spec/schedule_spec.rb +18 -9
- data/spec/spec_helper.rb +7 -8
- data/spec/thread_worker_spec.rb +0 -37
- data/spec/update_runner_spec.rb +4 -6
- data/spec/update_spec.rb +1 -1
- data/spec/util_spec.rb +0 -2
- metadata +16 -15
- data/lib/updater/orm/mongo.rb~ +0 -188
- data/lib/updater/setup.rb~ +0 -175
- data/lib/updater/simulated.db +0 -0
- data/lib/updater/thread_worker.rb~ +0 -92
- data/lib/updater/update_dm.rb +0 -298
- data/spec/lock_spec.rb +0 -64
- data/spec/spec_helper.rb~ +0 -23
data/spec/fooclass.rb
CHANGED
@@ -1,18 +1,49 @@
|
|
1
|
-
|
2
|
-
class
|
3
|
-
|
1
|
+
class Foo
|
2
|
+
class << self
|
3
|
+
def index
|
4
|
+
@index ||= 0
|
5
|
+
@index += 1
|
6
|
+
end
|
7
|
+
|
8
|
+
def create(*args)
|
9
|
+
new(*args).tap {|r| r.save}
|
10
|
+
end
|
4
11
|
|
5
|
-
|
6
|
-
|
12
|
+
def storage
|
13
|
+
@storage ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def find(id)
|
17
|
+
storage[id]
|
18
|
+
end
|
7
19
|
|
8
|
-
def
|
9
|
-
|
20
|
+
def reset
|
21
|
+
@storage = {}
|
10
22
|
end
|
11
23
|
|
12
|
-
def
|
13
|
-
|
24
|
+
def count
|
25
|
+
storage.length
|
14
26
|
end
|
15
27
|
|
16
28
|
end
|
17
|
-
|
18
|
-
|
29
|
+
attr_reader :id
|
30
|
+
attr_accessor :name
|
31
|
+
|
32
|
+
def bar(*args)
|
33
|
+
Foo.bar(:instance,*args)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.bar(*args)
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(hash = {})
|
41
|
+
@id = Foo.index
|
42
|
+
@name = hash[:name]
|
43
|
+
end
|
44
|
+
|
45
|
+
def save
|
46
|
+
Foo.storage[self.id] = self
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), "spec_helper" )
|
2
|
+
|
3
|
+
describe Foo do
|
4
|
+
before :each do
|
5
|
+
Foo.reset
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have an unique index function" do
|
9
|
+
i1 = Foo.index
|
10
|
+
i2 = Foo.index
|
11
|
+
i1.should_not be_nil
|
12
|
+
i2.should_not be_nil
|
13
|
+
i1.should_not == i2
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should instantiate a new instance with an id" do
|
17
|
+
foo = Foo.new
|
18
|
+
foo.id.should_not be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should create saved instances" do
|
22
|
+
foo = Foo.create
|
23
|
+
Foo.find(foo.id).should be(foo)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have a name I can set" do
|
27
|
+
foo = Foo.create(:name=>'bar')
|
28
|
+
foo.name.should == 'bar'
|
29
|
+
foo.name = 'baz'
|
30
|
+
foo.name.should == 'baz'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have a count" do
|
34
|
+
Foo.count.should == 0
|
35
|
+
foo = Foo.create(:name=>'bar')
|
36
|
+
Foo.count.should == 1
|
37
|
+
end
|
38
|
+
end
|
@@ -34,23 +34,4 @@ describe "Fork Worker Instance" do
|
|
34
34
|
|
35
35
|
end
|
36
36
|
|
37
|
-
describe "#wait_for" do
|
38
|
-
|
39
|
-
it "should have specs"
|
40
|
-
|
41
|
-
describe "when there are pending jobs" do
|
42
|
-
|
43
|
-
it "should NOT wait for a signal"
|
44
|
-
|
45
|
-
it "should smoke the pipe"
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should wake as soon as a new job signal is placed on the pipe"
|
50
|
-
|
51
|
-
|
52
|
-
it "should run the heartbeat every 'timeout' seconds"
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
37
|
end
|
data/spec/fork_worker_spec.rb
CHANGED
@@ -175,6 +175,7 @@ describe ForkWorker do
|
|
175
175
|
|
176
176
|
it "should do maintance when the queue is empty" do
|
177
177
|
ForkWorker.should_receive(:murder_lazy_workers)
|
178
|
+
ForkWorker.should_receive(:antisipate_workload)
|
178
179
|
ForkWorker.should_receive(:maintain_worker_count)
|
179
180
|
ForkWorker.should_receive(:master_sleep)
|
180
181
|
|
data/spec/named_request_spec.rb
CHANGED
@@ -2,12 +2,10 @@ require File.join( File.dirname(__FILE__), "spec_helper" )
|
|
2
2
|
|
3
3
|
include Updater
|
4
4
|
|
5
|
-
require File.join( File.dirname(__FILE__), "fooclass" )
|
6
|
-
|
7
5
|
describe "named request" do
|
8
6
|
|
9
7
|
before(:each) do
|
10
|
-
Foo.
|
8
|
+
Foo.reset
|
11
9
|
Update.clear_all
|
12
10
|
end
|
13
11
|
|
@@ -34,7 +32,6 @@ describe "named request" do
|
|
34
32
|
it "should not include locked updates" do
|
35
33
|
u = Update.immidiate(Foo,:bar,[:named],:name=>'Now')
|
36
34
|
u.orm.lock(Struct.new(:name).new('test_worker'))
|
37
|
-
u.orm.should be_locked
|
38
35
|
Update.for(Foo).should_not include(u)
|
39
36
|
Update.for(Foo).should be_empty
|
40
37
|
end
|
data/spec/orm_lint.rb
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
shared_examples_for "an orm" do |test_setup|
|
2
|
+
|
3
|
+
before :each do
|
4
|
+
@target = Foo.create
|
5
|
+
@opts = {
|
6
|
+
:time =>Updater::Update.time.now.to_i,
|
7
|
+
:target=>Foo, :finder=>'find', :finder_args=>[@target.id],
|
8
|
+
:method=>'bar', :method_args=>['baz'],
|
9
|
+
:persistant=>false
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:instance) { described_class.create(@opts) }
|
14
|
+
let(:delayed) { described_class.create(@opts.merge(:time =>Updater::Update.time.now.to_i + 25000)) }
|
15
|
+
["","1","2","3"].each do |c|
|
16
|
+
let("chained#{c}".to_sym) { Updater::Update.new(described_class.create(@opts.merge(:time =>nil, :persistant=>true))) }
|
17
|
+
end
|
18
|
+
%w{tom dick harry}.each do |name|
|
19
|
+
let("#{name}_job".to_sym) { Updater::Update.new(described_class.create(@opts.merge(:name=>name))) }
|
20
|
+
end
|
21
|
+
|
22
|
+
before :all do
|
23
|
+
test_setup ||= {}
|
24
|
+
test_setup[:logger] ||= Logger.new(STDOUT).tap {|l| l.level = 99}
|
25
|
+
described_class.setup(test_setup)
|
26
|
+
@old_orm = Updater::Update.orm
|
27
|
+
Updater::Update.orm = described_class
|
28
|
+
end
|
29
|
+
|
30
|
+
after :all do
|
31
|
+
Updater::Update.orm = @old_orm
|
32
|
+
end
|
33
|
+
|
34
|
+
#Class Methods
|
35
|
+
describe "class methods" do
|
36
|
+
%w{get create current current_load delayed future queue_time lock_next clear_locks
|
37
|
+
clear_all setup for logger logger=}.each do |m|
|
38
|
+
it "should have a class method: #{m}" do
|
39
|
+
described_class.should respond_to(m)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "instance methods" do
|
45
|
+
%w{id time time= target target= finder finder= finder_args finder_args=
|
46
|
+
method method= method_args method_args= name name= persistant persistant=
|
47
|
+
save destroy lock}.each do |m|
|
48
|
+
it "should have an instance method: #{m}" do
|
49
|
+
instance.should respond_to(m)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "constants" do
|
55
|
+
%w{FINDER ID}.each do |c|
|
56
|
+
it "should have a constant: #{c}" do
|
57
|
+
described_class.const_get(c).should be_kind_of Symbol
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
describe "clear_all" do
|
65
|
+
it "should remove all jobs" do
|
66
|
+
described_class.clear_all
|
67
|
+
(described_class.current_load + described_class.delayed).should == 0
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "an instance" do
|
72
|
+
before :each do
|
73
|
+
described_class.clear_all
|
74
|
+
instance
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should have an id" do
|
78
|
+
instance.id.should_not be_nil
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "getters" do
|
82
|
+
%w{time finder finder_args method method_args target persistant}.each do |m|
|
83
|
+
specify "#{m} should be set to the correct value" do
|
84
|
+
instance.send(m.to_s).should == @opts[m.to_sym]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should be in the current list" do
|
90
|
+
described_class.current.should include(instance)
|
91
|
+
described_class.current_load.should == 1
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should be retrieved with 'get'" do
|
95
|
+
described_class.get(instance.id).should == instance
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should be removed with 'destroy'" do
|
99
|
+
instance.destroy
|
100
|
+
described_class.get(instance.id).should be_nil
|
101
|
+
described_class.current_load.should == 0
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "locking" do
|
107
|
+
before :each do
|
108
|
+
@worker1 = Struct.new(:name).new('foo')
|
109
|
+
@worker2 = Struct.new(:name).new('bar')
|
110
|
+
@worker1.stub(:say)
|
111
|
+
@worker2.stub(:say)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "an instance should lock" do
|
115
|
+
instance.lock(@worker1).should be_true
|
116
|
+
end
|
117
|
+
|
118
|
+
it "an instance should lock again with the same worker" do
|
119
|
+
instance.lock(@worker1).should be_true
|
120
|
+
instance.lock(@worker1).should be_true
|
121
|
+
end
|
122
|
+
|
123
|
+
it "an instance should lock if it has been locked" do
|
124
|
+
instance.lock(@worker1).should be_true
|
125
|
+
instance.lock(@worker2).should be_false
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "lock_next" do
|
130
|
+
before :each do
|
131
|
+
described_class.clear_all
|
132
|
+
@worker1 = Struct.new(:name).new('foo')
|
133
|
+
@worker2 = Struct.new(:name).new('bar')
|
134
|
+
@worker1.stub(:say)
|
135
|
+
@worker2.stub(:say)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should return the next current instance locked to the worker" do
|
139
|
+
instance
|
140
|
+
job = described_class.lock_next(@worker1)
|
141
|
+
job.should == instance
|
142
|
+
job.lock(@worker2).should be_false
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should return nil if there are no current jobs without a lock" do
|
146
|
+
described_class.lock_next(@worker1).should be_nil
|
147
|
+
delayed
|
148
|
+
described_class.lock_next(@worker1).should be_nil
|
149
|
+
instance.lock(@worker2)
|
150
|
+
described_class.lock_next(@worker1).should be_nil
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "clear locks" do
|
156
|
+
before :each do
|
157
|
+
described_class.clear_all
|
158
|
+
@worker1 = Struct.new(:name).new('foo')
|
159
|
+
@worker2 = Struct.new(:name).new('bar')
|
160
|
+
@worker1.stub(:say)
|
161
|
+
@worker2.stub(:say)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should clear every lock held by a worker" do
|
165
|
+
instance.lock(@worker1)
|
166
|
+
described_class.clear_locks(@worker1)
|
167
|
+
instance.lock(@worker2).should be_true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "queue_time" do
|
172
|
+
before :each do
|
173
|
+
described_class.clear_all
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should be nil if the queue is empty" do
|
177
|
+
described_class.queue_time.should be_nil
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should be 0 if there is a current job" do
|
181
|
+
instance
|
182
|
+
described_class.queue_time.should == 0
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should be the time to the next job" do
|
186
|
+
Timecop.freeze do
|
187
|
+
delayed
|
188
|
+
described_class.queue_time.should == 25000
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "with method chaining:" do
|
194
|
+
before :each do
|
195
|
+
described_class.clear_all
|
196
|
+
end
|
197
|
+
|
198
|
+
%w{success failure ensure}.each do |mode|
|
199
|
+
describe mode do
|
200
|
+
it "should initially be empty" do
|
201
|
+
instance.send(mode).should be_empty
|
202
|
+
end
|
203
|
+
end
|
204
|
+
describe "#{mode}=" do
|
205
|
+
it "should add an Update instance" do
|
206
|
+
instance.send("#{mode}=", chained).should == chained
|
207
|
+
instance.send(mode).should_not be_empty
|
208
|
+
instance.send(mode).should include chained
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should add a #{described_class.to_s} instance" do
|
212
|
+
instance.send("#{mode}=", chained.orm).should == chained.orm
|
213
|
+
instance.send(mode).should_not be_empty
|
214
|
+
instance.send(mode).map{|x| x.orm}.should include chained.orm
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should add an id" do
|
218
|
+
instance.send("#{mode}=", chained.id).should == chained.id
|
219
|
+
instance.send(mode).should_not be_empty
|
220
|
+
instance.send(mode).should include chained
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should add multiple items from an array" do
|
224
|
+
instance.send("#{mode}=", [chained,chained1,chained2])
|
225
|
+
instance.send(mode).length.should == 3
|
226
|
+
instance.send(mode).should == [chained,chained1,chained2]
|
227
|
+
end
|
228
|
+
|
229
|
+
specify "nested arrays should set param" do
|
230
|
+
instance.send("#{mode}=", [chained,[chained1, :foo],chained2])
|
231
|
+
puts "%s (%s:%s)" % [instance.send(mode),__FILE__,__LINE__] if instance.send(mode)[1].nil?
|
232
|
+
instance.send(mode)[1].params.should == :foo
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should add multiple items from a hash" do
|
236
|
+
instance.send("#{mode}=", {chained=>:foo,chained1=>:bar,chained2=>:baz})
|
237
|
+
instance.send(mode).length.should == 3
|
238
|
+
instance.send(mode).should == [chained,chained1,chained2]
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should set the parameters from a hash" do
|
242
|
+
instance.send("#{mode}=", {chained=>:foo})
|
243
|
+
instance.send(mode)[0].params.should == :foo
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should clear the chain with nil" do
|
247
|
+
instance.send("#{mode}=", [chained,chained1,chained2])
|
248
|
+
instance.send(mode).length.should == 3
|
249
|
+
instance.send("#{mode}=", nil).should be_nil
|
250
|
+
instance.send(mode).length.should == 0
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should NOT be a destructive assignment" do
|
254
|
+
instance.send("#{mode}=", [chained,chained1,chained2])
|
255
|
+
instance.send(mode).length.should == 3
|
256
|
+
instance.send("#{mode}=", {chained3=>:foo})
|
257
|
+
instance.send(mode).length.should == 4
|
258
|
+
instance.send(mode)[3].should == chained3
|
259
|
+
end
|
260
|
+
|
261
|
+
end # mode=
|
262
|
+
end # {success, failure, ensure}
|
263
|
+
end #chaining
|
264
|
+
|
265
|
+
describe " #for" do
|
266
|
+
before :each do
|
267
|
+
described_class.clear_all
|
268
|
+
tom_job; dick_job; harry_job
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should find all jobs" do
|
272
|
+
described_class.for(@target.class, @opts[:finder], [@target.id]).should include(tom_job.orm, dick_job.orm, harry_job.orm)
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should find a job by name" do
|
276
|
+
described_class.for(@target.class, @opts[:finder], [@target.id], "dick").first.should == dick_job.orm
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should return an empty array if no job is found" do
|
280
|
+
foo = Foo.create
|
281
|
+
described_class.for(@target.class, @opts[:finder], [@target.id], "john").should be_empty
|
282
|
+
described_class.for(@target.class, @opts[:finder], [foo.id]).should be_empty
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should not return a locked record" do
|
286
|
+
described_class.for(@target.class, @opts[:finder], [@target.id]).should include(tom_job.orm, dick_job.orm, harry_job.orm)
|
287
|
+
tom_job.orm.lock(Struct.new(:name).new('test_worker'))
|
288
|
+
described_class.for(@target.class, @opts[:finder], [@target.id]).should_not include(tom_job.orm)
|
289
|
+
end
|
290
|
+
|
291
|
+
end #for
|
292
|
+
end
|
data/spec/params_sub_spec.rb
CHANGED
@@ -17,7 +17,8 @@ describe "Special Parameter Substitution" do
|
|
17
17
|
|
18
18
|
it "should substitute __params__ with params" do
|
19
19
|
Foo.should_receive(:chained).with(anything(),:arg2,anything(), 'job params')
|
20
|
-
@u.
|
20
|
+
@u.params = :arg2
|
21
|
+
@u.run(:arg1)
|
21
22
|
end
|
22
23
|
|
23
24
|
it "should substitute __self__ with the current job" do
|