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 CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'rake/gempackagetask'
3
- gem 'rspec', '=1.3.0'
4
- require 'spec/rake/spectask'
3
+ require 'rspec/core/rake_task'
5
4
 
6
5
 
7
6
  VERSION_FILE = File.join(File.dirname(__FILE__), 'VERSION')
@@ -26,7 +25,7 @@ spec = Gem::Specification.new do |s|
26
25
  s.email = EMAIL
27
26
  s.homepage = HOMEPAGE
28
27
  s.add_development_dependency('datamapper', '>= 0.10.2')
29
- s.add_development_dependency('rspec', '=1.3.0')
28
+ s.add_development_dependency('rspec', '>= 2.0.0')
30
29
  s.add_development_dependency('timecop', '>= 0.2.1')
31
30
  s.add_development_dependency('chronic', '>= 0.2.3')
32
31
  s.require_path = 'lib'
@@ -40,21 +39,21 @@ Rake::GemPackageTask.new(spec) do |pkg|
40
39
  pkg.gem_spec = spec
41
40
  end
42
41
 
43
- Spec::Rake::SpecTask.new do |t|
44
- t.warning = false
42
+ RSpec::Core::RakeTask.new do |t|
43
+ ruby_opts="-w"
45
44
  t.rcov = false
46
45
  end
47
46
 
48
- Spec::Rake::SpecTask.new do |t|
47
+ RSpec::Core::RakeTask.new do |t|
49
48
  t.name="failing"
50
49
  #todo Make this run only failing specs
51
- t.warning = false
50
+ ruby_opts="-w"
52
51
  t.rcov = false
53
52
  end
54
53
 
55
- Spec::Rake::SpecTask.new do |t|
54
+ RSpec::Core::RakeTask.new do |t|
56
55
  t.name="rcov"
57
- t.warning = false
56
+ ruby_opts="-w"
58
57
  t.rcov = true
59
58
  end
60
59
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.4
1
+ 0.10.0
@@ -231,7 +231,7 @@ module Updater
231
231
 
232
232
  def add_worker(worker_number)
233
233
  worker = WorkerMonitor.new(worker_number,Updater::Util.tempio)
234
- Update.orm.before_fork
234
+ Update.orm.before_fork if Update.orm.respond_to? :before_fork
235
235
  pid = Process.fork do
236
236
  fork_cleanup
237
237
  self.new(@pipe,worker).run
@@ -0,0 +1,23 @@
1
+ module Updater
2
+ module ORm
3
+
4
+ class ActiveRecord
5
+ raise NoImplimentationError
6
+ def lock(worker)
7
+ return true if locked? && locked_by == worker.name
8
+ #all this to make sure the check and the lock are simultanious:
9
+ ccnt = self.class.where(id: self.id, lock: nil).update_all(:lock=>worker.name)
10
+ if 0 != cnt
11
+ @lock_name = worker.name
12
+ true
13
+ else
14
+ worker.say( "Worker #{worker.name} Failed to aquire lock on job #{id}" )
15
+ false
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -1,5 +1,6 @@
1
1
  require "dm-core"
2
2
  require "dm-types"
3
+ require "dm-migrations"
3
4
 
4
5
  module Updater
5
6
  module ORM
@@ -31,6 +32,10 @@ module Updater
31
32
 
32
33
  has n, :chains, :model=>'Updater::ORM::DMChained', :child_key=>[:caller_id]
33
34
 
35
+ def method
36
+ self[:method]
37
+ end
38
+
34
39
  #attempt to lock this record for the worker
35
40
  def lock(worker)
36
41
  return true if locked? && locked_by == worker.name
@@ -55,28 +60,33 @@ module Updater
55
60
  define_method "#{mode}=" do |chain|
56
61
  case chain
57
62
  when self.class
58
- chains.new(:target=>chain,:occasion=>mode)
63
+ self.chains.new(:target=>chain,:occasion=>mode)
59
64
  when Updater::Update
60
- chains.new(:target=>chain.orm,:occasion=>mode)
65
+ self.chains.new(:target=>chain.orm,:occasion=>mode)
61
66
  when Hash
62
67
  chain.each do |target, params|
63
68
  target = target.orm if target.kind_of? Updater::Update
64
- chains.new(:target=>target,:params=>params, :occasion=>mode)
69
+ self.chains.new(:target=>target,:params=>params, :occasion=>mode)
65
70
  end
66
71
  when Array
67
72
  chain.each do |target|
73
+ target, params = target
68
74
  target = target.orm if target.kind_of? Updater::Update
69
- chains.new(:target=>target,:occasion=>mode)
75
+ self.chains.new(:target=>target,:occasion=>mode, :params=>params)
70
76
  end
77
+ when Integer
78
+ self.chains.new(:target_id=>chain,:occasion=>mode)
71
79
  when nil
72
- chains=[]
80
+ self.chains=[]
73
81
  else
74
- raise ArgumentError
82
+ raise ArgumentError, "Cannot add #{chain.inspect} to a chain (%s:%s)" % [__FILE__,__LINE__]
75
83
  end
84
+ save
85
+ chain
76
86
  end
77
87
 
78
88
  define_method mode do
79
- chains.all(:occasion=>mode).map {|job| Updater.new(i.target).tap {|u| u.params = job.params}}
89
+ chains.all(:occasion=>mode).map {|job| Update.new(job.target).tap {|u| u.params = job.params}}
80
90
  end
81
91
  end
82
92
 
@@ -145,7 +155,7 @@ module Updater
145
155
  search = all(
146
156
  :target=>mytarget,
147
157
  :finder=>myfinder,
148
- :finder_args=>myfinder_args,
158
+ :finder_args=>myfinder_args.to_yaml,
149
159
  :lock_name=>nil
150
160
  )
151
161
  myname ? search.all(:name=>myname ) : search
@@ -154,7 +164,17 @@ module Updater
154
164
  #For the server only, setup the connection to the database
155
165
  def setup(options)
156
166
  ::DataMapper.logger = options.delete(:logger)
167
+ auto_migrate = options.delete(:auto_migrate)
157
168
  ::DataMapper.setup(:default,options)
169
+ ::DataMapper.auto_migrate! if auto_migrate
170
+ end
171
+
172
+ def logger
173
+ ::DataMapper.logger
174
+ end
175
+
176
+ def logger=(input)
177
+ ::DataMapper.logger = input
158
178
  end
159
179
 
160
180
  # For pooled connections it is necessary to empty the pool of the parents connections so that they
@@ -0,0 +1,155 @@
1
+ module Updater
2
+ module ORM
3
+ class Mock
4
+
5
+ FINDER = :find
6
+
7
+ ID = :id
8
+
9
+ class << self
10
+ attr_accessor :logger
11
+
12
+ def index
13
+ @index ||= 0
14
+ @index += 1
15
+ end
16
+
17
+ def get(id)
18
+ storage[id]
19
+ end
20
+
21
+ def create(hash)
22
+ new(hash).tap {|n| storage[n.id] = n}
23
+ end
24
+
25
+ def current
26
+ storage.values.find_all{|x|
27
+ x.time && x.time <= tnow && !x.lock_name
28
+ }.sort{|a,b| a.time <=> b.time}
29
+ end
30
+
31
+ def current_load
32
+ current.length
33
+ end
34
+
35
+ def _delayed
36
+ storage.values.find_all{|x|
37
+ x.time && x.time > tnow
38
+ }.sort{|a,b| a.time <=> b.time}
39
+ end
40
+
41
+ def delayed
42
+ _delayed.length
43
+ end
44
+
45
+ def future(start, finish)
46
+ _delayed.find_all{|x| x.time >= start+tnow && x.time < finish+tnow}
47
+ end
48
+
49
+ def queue_time
50
+ return 0 unless current.empty?
51
+ return nil if (d = _delayed).empty? #tricky assignment in conditional
52
+ d.first.time - tnow
53
+ end
54
+
55
+ def lock_next(worker)
56
+ job = current.first
57
+ job.lock(worker) if job
58
+ job
59
+ end
60
+
61
+ def clear_locks(worker)
62
+ storage.values.each{|x| x.lock_name = nil if x.lock_name == worker.name}
63
+ end
64
+
65
+
66
+ def clear_all
67
+ @storage = {}
68
+ end
69
+
70
+ def setup(options)
71
+ @storage = {}
72
+ end
73
+
74
+ def for(target, finder, finder_args, name=nil)
75
+ @storage.values.find_all do |x|
76
+ naming = name ? x.name == name : true
77
+ naming && x.finder == finder && x.finder_args == finder_args && x.target == target && !x.lock_name
78
+ end
79
+ end
80
+
81
+ def storage
82
+ @storage ||= {}
83
+ end
84
+
85
+ private
86
+ def tnow
87
+ Updater::Update.time.now.to_i
88
+ end
89
+ end #class << self
90
+
91
+ attr_reader :id
92
+
93
+ attr_accessor :time, :target, :finder, :finder_args, :method, :method_args, :name, :lock_name, :persistant
94
+
95
+ def initialize(hash = {})
96
+ @id = self.class.index
97
+ hash.each do |k,v|
98
+ self.send("#{k}=",v)
99
+ end
100
+ end
101
+
102
+ def lock(worker)
103
+ return false if @lock_name && @lock_name != worker.name
104
+ @lock_name = worker.name
105
+ end
106
+
107
+ def save
108
+ self.class.storage[id] = self
109
+ end
110
+
111
+ def destroy
112
+ self.class.storage.delete(id)
113
+ end
114
+
115
+ %w{failure success ensure}.each do |mode|
116
+ eval(<<-EOF, binding ,__FILE__, __LINE__+1)
117
+ def #{mode}
118
+ @#{mode} ||= []
119
+ end
120
+
121
+ def #{mode}=(chain)
122
+ return @#{mode} = nil if chain.nil?
123
+ @#{mode} ||= []
124
+ mchain = chain.kind_of?(Array) ? chain : [chain]
125
+ @#{mode} += mchain.map { |x| rationalize_instance(x) }.flatten
126
+ # attach_intellegent_insertion(@#{mode},:#{mode},self) if @#{mode}
127
+ chain
128
+ end
129
+ EOF
130
+ end
131
+
132
+ private
133
+
134
+ def rationalize_instance(val)
135
+ case val
136
+ when Updater::Update
137
+ val
138
+ when self.class
139
+ Updater::Update.new(val)
140
+ when Integer
141
+ Updater::Update.new(self.class.storage[val])
142
+ when Hash
143
+ val.map do |target, params|
144
+ rationalize_instance(target).tap{|u| u.params = params}
145
+ end
146
+ when Array #an array within an array
147
+ rationalize_instance(val[0]).tap {|u| u.params = val[1]}
148
+ else
149
+ raise ArgumentError, "Cannot add #{val.inspect} to a chain (%s:%s)" % [__FILE__,__LINE__]
150
+ end
151
+ end
152
+
153
+ end
154
+ end
155
+ end
@@ -71,7 +71,16 @@ module Updater
71
71
  end
72
72
 
73
73
  def lock(worker)
74
- raise NotImplimentedError, "Use lock_next"
74
+ return true if @lock_name && @lock_name == worker.name
75
+ hash = Hash.new
76
+ hash['findandmodify'] = self.class.collection.name
77
+ hash['query'] = {:_id=>id,:lock_name=>nil}
78
+ hash['update'] = {'$set'=>{:lock_name=>worker.name}}
79
+ hash['new'] = true
80
+
81
+ ret = self.class.db.command hash, :check_response=>false
82
+ @lock_name = worker.name if ret['ok'] == 1
83
+ return ret['ok'] == 1
75
84
  end
76
85
 
77
86
  # Non API Standard. This method returns the collection used by this instance.
@@ -97,23 +106,32 @@ module Updater
97
106
  end
98
107
 
99
108
  def #{mode}=(chain)
100
- chain = [chain] unless chain.kind_of? Array
101
- @#{mode} , @hash[:#{mode}] = build_chain_arrays(chain)
109
+ return @#{mode} = @hash[:#{mode}] = nil if chain.nil?
110
+ mchain = chain.kind_of?(Array) ? chain : [chain]
111
+ inst, hsh = build_chain_arrays(mchain)
112
+ @#{mode} = (@#{mode} || [] ) + inst if inst
113
+ @hash[:#{mode}] = (@hash[:#{mode}] || []) + hsh
102
114
  attach_intellegent_insertion(@#{mode},:#{mode},self) if @#{mode}
115
+ chain
103
116
  end
104
117
  EOF
105
118
  end
106
119
 
120
+ def ==(other)
121
+ other.class == self.class && id == other.id
122
+ end
123
+
107
124
  private
108
- # this method is calld from he chain asignment methods eg. failure=(chain)
125
+ # This method is calleppd from he chain asignment methods eg. failure=(chain)
109
126
  # chain is an array which may contain BSON::ObjectId's or Updater::Update's or both
110
- # For BSON::ObjectId's we cannot initialize them as this could leed to infinate loops.
127
+ # For BSON::ObjectId's we cannot initialize them as this could lead to infinate loops.
111
128
  # (an object pool would solve this problem, but feels like overkill)
112
129
  # The final result must be a @hash containing all the BSON::ObjectId' (forign keys)
113
130
  # and possibly @failure containting all instanciated UpdaterUpdates read to be called
114
131
  # or @failure set to nil with the chain instanciated on first use.
115
132
  def build_chain_arrays(arr, build = false)
116
- build ||= arr.any? {|j| k,_ = j; Updater::Update === k || Hash === k}
133
+ arr = arr[0].to_a if arr[0].is_a? Hash
134
+ build ||= arr.any? {|j| k,_ = j; Updater::Update === k || self.class === k}
117
135
  output = arr.inject({:ids=>[],:instances=>[]}) do |accl,j|
118
136
  inst, id = rationalize_instance(j)
119
137
  if inst.nil? && build
@@ -134,7 +152,7 @@ module Updater
134
152
  # This method takes something that may be a reference to an instance(BSON::ObjectId/String),
135
153
  # an instance its self (Updater::Update), or a Hash
136
154
  # and returns a touple of the Updater::Update,BSON::ObjectId.
137
- # This method will bot instanciate object from BSON::ObjectId's
155
+ # This method will not instanciate object from BSON::ObjectId's
138
156
  # nor will it save Hashes inorder to obtain an ID (it will creat a new Updater::Update from the hash).
139
157
  # Instead it will return nil in the appropriate place.
140
158
  def rationalize_instance(val)
@@ -142,8 +160,10 @@ module Updater
142
160
  case val #aval is the actual runable object, hval is a BSON::ObjectId that we can put into the Database
143
161
  when Updater::Update
144
162
  val.params ? [val,[val.id,val.params]] : [val,val.id]
145
- when Hash
146
- [Updater::Update.new(val),val['_id']]
163
+ #~ when Hash # I think this ought to be deleted outright, but I whant to pass the functional test before I delete it.
164
+ #~ [Updater::Update.new(val),val['_id']]
165
+ when self.class
166
+ [Updater::Update.new(val), val.id]
147
167
  when BSON::ObjectId
148
168
  [nil,val]
149
169
  when Array
@@ -228,11 +248,15 @@ module Updater
228
248
 
229
249
  def get(id)
230
250
  id = BSON::ObjectId.from_string(id) if id.kind_of? String
231
- new(@collection.find_one(id))
251
+ inst = @collection.find_one(id)
252
+ inst && new(inst)
232
253
  end
233
254
 
234
255
  def current
235
- raise NotImplementedError, "Mongo does not support lazy evaluation"
256
+ # raise NotImplementedError, "Mongo does not support lazy evaluation"
257
+ @collection.find(:time=>{'$lte'=>tnow}).map do |x|
258
+ new(x)
259
+ end
236
260
  end
237
261
 
238
262
  def current_load
@@ -268,12 +292,23 @@ module Updater
268
292
  @collection.update({:lock_name=>worker.name},{'$unset'=>{:lock_name=>1}},:multi=>true)
269
293
  end
270
294
 
271
- def for(target,finder,args,name)
295
+ def for(target,finder,args,name=nil)
272
296
  if name
273
- @collection.find(:target=>target.to_s, :finder_args=>args,:name=>name)
297
+ @collection.find(
298
+ :target=>target.to_s,
299
+ :finder_args=>args,
300
+ :finder=>finder,
301
+ :lock_name=>nil,
302
+ :name=>name
303
+ )
274
304
  else
275
- @collection.find(:target=>target.to_s, :finder_args=>args)
276
- end
305
+ @collection.find(
306
+ :target=>target.to_s,
307
+ :finder_args=>args,
308
+ :finder=>finder,
309
+ :lock_name=>nil,
310
+ )
311
+ end.map {|x| new(x) }
277
312
  end
278
313
 
279
314
  private
@@ -30,7 +30,7 @@ module Updater
30
30
  # always in reference to Updater::Update.time (by default Time). This value will be
31
31
  # nil for chained methods.
32
32
  #
33
- # target [Class]: The class of the target for this job. the API spesifies that it must be
33
+ # target [Class]: The class of the target for this job. The API spesifies that it must be
34
34
  # a Ruby class currently in scope in both the workers' and clients' frames of reference.
35
35
  # (see configuration documentation for how to achieve this.) The writer must accept an
36
36
  # actual class, which it may store in the datastore as a string (by calling to_s on it). The
@@ -232,6 +232,8 @@ module Updater
232
232
  end
233
233
 
234
234
  def after_fork
235
+
236
+ end
235
237
 
236
238
  # Optional, but strongly recomended.
237
239
  #
data/lib/updater/setup.rb CHANGED
@@ -6,6 +6,7 @@ require 'erb'
6
6
  module Updater
7
7
  class Setup
8
8
  class << self
9
+ attr_accessor :init
9
10
  #start a new server
10
11
  def start(options={})
11
12
  new(config_file(options), options).start
@@ -27,6 +28,10 @@ module Updater
27
28
  new(config_file(options), options).client_setup
28
29
  end
29
30
 
31
+ def test_setup(options = {})
32
+ new(options).test_setup
33
+ end
34
+
30
35
  # pendeing
31
36
  def monitor
32
37
 
@@ -83,14 +88,14 @@ module Updater
83
88
  end
84
89
 
85
90
  # The client is responcible for loading classes and making connections. We will simply setup the Updater spesifics.
86
- def client_setup
87
- @logger.info "Updater Client is being initialized..."
91
+ def client_setup(init = true)
92
+ @logger.info "Updater Client is being initialized... (#{__FILE__}:#{__LINE__})"
93
+ @logger.debug " Call Stack:\n - #{caller[0..3].join("\n - ")}"
88
94
  set_orm
89
95
 
90
96
  Updater::Update.socket = socket_for_client
91
97
 
92
-
93
- init_orm
98
+ init_orm if init
94
99
 
95
100
  #set PID
96
101
  if File.exists? @options[:pid_file]
@@ -101,6 +106,16 @@ module Updater
101
106
  self
102
107
  end
103
108
 
109
+ def test_setup
110
+ @options[:orm] ||= 'mock'
111
+ set_orm
112
+ init_orm
113
+
114
+ Updater::Update.socket = @options[:socket] ||= File.open('/dev/null','w')
115
+
116
+ self
117
+ end
118
+
104
119
  def socket_for_client
105
120
  if @options[:socket] && File.exists?(@options[:socket])
106
121
  @logger.debug "Using UNIX Socket \"#{@options[:socket]}\""
@@ -145,13 +160,15 @@ module Updater
145
160
  require 'updater/orm/activerecord'
146
161
  Updater::Update.orm = ORM::ActiveRecord
147
162
  else
148
- require "update/orm/#{orm}"
149
- Updater::Update.orm = Object.const_get("ORM").const_get(orm.capitalize)
163
+ require "updater/orm/#{orm}"
164
+ Updater::Update.orm = Updater::ORM.const_get(orm.capitalize)
150
165
  end
151
166
  @logger.info "Data store '#{orm}' selected"
152
167
  end
153
168
 
154
169
  def init_orm
170
+ return false if self.class.init
171
+ self.class.init = true
155
172
  default_options = {:adapter=>'sqlite3', :database=>'./default.db'}
156
173
  Updater::Update.orm.setup((@options[:database] || @options[:orm_setup] || default_options).merge(:logger=>@logger))
157
174
  end
@@ -206,7 +223,7 @@ module Updater
206
223
  #Log PID
207
224
  File.open(@options[:pid_file],'w') { |f| f.write(Process.pid.to_s)}
208
225
 
209
- client_setup
226
+ client_setup(false)
210
227
 
211
228
  #start Worker
212
229
  worker = @options[:worker] || 'fork' #todo make this line windows safe
@@ -9,6 +9,7 @@ module Updater
9
9
  class ThreadWorker
10
10
  attr_accessor :pid
11
11
  attr_accessor :name
12
+ attr_accessor :logger
12
13
 
13
14
  def initialize(options={})
14
15
  @quiet = options[:quiet]
@@ -53,6 +54,10 @@ module Updater
53
54
  end
54
55
  end
55
56
 
57
+ def logger
58
+ @logger ||= Logger.new(nil)
59
+ end
60
+
56
61
  private
57
62
 
58
63
  def run_job_loop
@@ -53,14 +53,17 @@ module Updater
53
53
  # (or the recreation of an object) on EACH invocation. Methods that need to refer to the target more then once should
54
54
  # take care to store this value locally after initial retreavel.
55
55
  def target
56
- target = @orm.finder.nil? ? @orm.target : @orm.target.send(@orm.finder,@orm.finder_args)
56
+ target = @orm.finder.nil? ? @orm.target : @orm.target.send(@orm.finder,*@orm.finder_args)
57
57
  raise TargetMissingError, "Target missing --Class:'#{@orm.target}' Finder:'#{@orm.finder}', Args:'#{@orm.finder_args.inspect}'" unless target
58
58
  target
59
59
  end
60
60
 
61
61
  # orm_inst must be set to an instacne of the class Update.orm
62
62
  def initialize(orm_inst)
63
- raise ArgumentError if orm_inst.nil? || !orm_inst.kind_of?(self.class.orm)
63
+ if orm_inst.nil? || !orm_inst.kind_of?(self.class.orm)
64
+ raise ArgumentError,
65
+ "Update has been set to use %s but recieved a %s (%s:%s)\n recieved %s." % [self.class.orm.inspect, orm_inst.class.inspect, __FILE__,__LINE__-1,orm_inst.inspect]
66
+ end
64
67
  @orm = orm_inst
65
68
  end
66
69
 
@@ -80,7 +83,7 @@ module Updater
80
83
  end
81
84
 
82
85
  def ==(other)
83
- id = other.id
86
+ other.kind_of?(self.class) && id == other.id
84
87
  end
85
88
 
86
89
  # If this is true, the job will NOT be removed after it is run. This is usually true for chained Jobs.
@@ -172,7 +175,7 @@ module Updater
172
175
  #
173
176
  # MongoDB is one significant exception to this rule. The Updater Mongo ORM layer uses the
174
177
  # 10gen MongoDB dirver directly without an ORM such as Mongoid or Mongo_Mapper. If the
175
- # application uses ond of thes ORMs #finder_method and #finder_id should be explicitly set.
178
+ # application uses one of thes ORMs #finder_method and #finder_id should be explicitly set.
176
179
  attr_accessor :finder_method
177
180
 
178
181
  # This is the application level default method to call on an instance type target. It should
@@ -480,7 +483,7 @@ module Updater
480
483
 
481
484
  # Given some instance return the information needed to recreate that target
482
485
  def target_for(inst,options = {})
483
- return [inst, nil, nil] if (inst.kind_of?(Class) || inst.kind_of?(Module))
486
+ return [inst, options[:finder], options[:finder_args]] if (inst.kind_of?(Class) || inst.kind_of?(Module))
484
487
  [ inst.class, #target's class
485
488
  options[:finder] || @finder_method || orm::FINDER, #method to call on targets class to find/create target
486
489
  options[:finder_args] || inst.send(@finder_id || orm::ID) #value to pass to above method
data/spec/chained_spec.rb CHANGED
@@ -8,15 +8,16 @@ describe "Chained Methods:" do
8
8
 
9
9
  before :each do
10
10
  Update.clear_all
11
- Foo.all.destroy!
11
+ Foo.reset
12
12
  @u = Update.chain(Foo,:chained,[:__job__,:__params__])
13
13
  @v = Update.chain(Foo,:chained2,[:__job__,:__params__])
14
+ #pending "Chained Worker not implimented in datamapper, Waiting form ORM code refactor"
14
15
  end
15
16
 
16
17
  [:failure, :success, :ensure].each do |mode|
17
18
  specify "adding '#{mode.to_s}' chain" do
18
19
  v = Update.immidiate(Foo,:method1,[],mode=>@u)
19
- v.orm.send(mode).should_not be_empty
20
+ v.send(mode).should_not be_empty
20
21
  end
21
22
  end
22
23
 
@@ -0,0 +1,7 @@
1
+ require File.join( File.dirname(__FILE__), "spec_helper" )
2
+ require 'updater/orm/datamapper'
3
+
4
+ describe Updater::ORM::DataMapper do
5
+ it_behaves_like "an orm", :adapter=>'sqlite3',:database=>':memory:',:auto_migrate=>true
6
+
7
+ end
data/spec/errors_spec.rb CHANGED
@@ -6,7 +6,7 @@ require File.join( File.dirname(__FILE__), "fooclass" )
6
6
 
7
7
  describe "Job Error Handeling" do
8
8
  before(:each) do
9
- Foo.all.destroy!
9
+ Foo.reset
10
10
  end
11
11
 
12
12
  it "should return false when run" do