archipelago 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -39,7 +39,7 @@ module Archipelago
39
39
  # The known chests by service id to speed up
40
40
  # recovery by Dubloons having lost their Chest.
41
41
  #
42
- CHESTS_BY_SERVICE_ID = {}
42
+ CHEST_BY_SERVICE_ID = {}
43
43
 
44
44
  #
45
45
  # Raised whenever the optimistic locking of the serializable transaction isolation level
@@ -55,8 +55,12 @@ module Archipelago
55
55
  # Raised whenever a method is called on an object that we dont know about.
56
56
  #
57
57
  class UnknownObjectException < RuntimeError
58
- def initialize(chest, key, transaction)
59
- super("#{chest} does not contain #{key} under #{transaction}")
58
+ def initialize(chest, key, transaction = nil)
59
+ if transaction
60
+ super("#{chest} does not contain #{key} under #{transaction}")
61
+ else
62
+ super("#{chest} does not contain #{key}")
63
+ end
60
64
  end
61
65
  end
62
66
 
@@ -95,19 +99,42 @@ module Archipelago
95
99
  # Remove all methods so that we look like our target.
96
100
  #
97
101
  instance_methods.each do |method|
98
- undef_method method unless method =~ /^__/
102
+ undef_method method unless (method =~ /^__/ || method == "respond_to?")
103
+ end
104
+ #
105
+ # This Dubloon will always have the same hash, based on
106
+ # <b>object_id</b>.
107
+ #
108
+ def hash
109
+ self.object_id.hash
110
+ end
111
+ #
112
+ # Defers to Dubloon#==.
113
+ #
114
+ def eql?(o)
115
+ self.==(o)
116
+ end
117
+ #
118
+ # If o is a Dubloon, will return true if it has the same Dubloon#object_id.
119
+ #
120
+ # Otherwise will defer to Dubloon#method_missing.
121
+ #
122
+ def ==(o)
123
+ if Dubloon === o
124
+ return true if self.object_id == o.object_id
125
+ end
126
+ return self.method_missing(:==, o)
99
127
  end
100
128
  #
101
129
  # Initialize us with knowledge of our +chest+, the +key+ to our
102
130
  # target in the +chest+, the known +public_methods+ of our target
103
131
  # and any +transaction+ we are associated with.
104
132
  #
105
- def initialize(key, chest, transaction, chest_id, public_methods)
133
+ def initialize(key, chest, transaction, chest_id)
106
134
  @key = key
107
135
  @chest = chest
108
136
  @transaction = transaction
109
137
  @chest_id = chest_id
110
- @public_methods = public_methods
111
138
  end
112
139
  #
113
140
  # A more or less normal dump of all our instance variables.
@@ -117,8 +144,7 @@ module Archipelago
117
144
  @key,
118
145
  @chest,
119
146
  @transaction,
120
- @chest_id,
121
- @public_methods
147
+ @chest_id
122
148
  ])
123
149
  end
124
150
  #
@@ -126,24 +152,12 @@ module Archipelago
126
152
  # it actually is not correct.
127
153
  #
128
154
  def self._load(s)
129
- key, chest, transaction, chest_id, public_methods = Marshal.load(s)
130
- instance = self.allocate
131
- instance.instance_variable_set(:@key, key)
132
- instance.instance_variable_set(:@transaction, transaction)
133
- instance.instance_variable_set(:@chest_id, chest_id)
134
- instance.instance_variable_set(:@public_methods, public_methods)
155
+ key, chest, transaction, chest_id = Marshal.load(s)
135
156
  if CHEST_BY_SERVICE_ID.include?(chest_id)
136
- instance.instance_variable_set(:@chest, CHEST_BY_SERVICE_ID[chest_id])
137
- else
138
- instance.instance_variable_set(:@chest, chest)
157
+ chest = CHEST_BY_SERVICE_ID[chest_id]
139
158
  end
140
- return instance
141
- end
142
- #
143
- # The public_methods of our target.
144
- #
145
- def public_methods
146
- return @public_methods.clone
159
+
160
+ return self.new(key, chest, transaction, chest_id)
147
161
  end
148
162
  #
149
163
  # Return a clone of myself that is joined to
@@ -151,7 +165,7 @@ module Archipelago
151
165
  #
152
166
  def join(transaction)
153
167
  @chest.join!(transaction) if transaction
154
- return Dubloon.new(@key, @chest, transaction, @chest_id, @public_methods)
168
+ return Dubloon.new(@key, @chest, transaction, @chest_id)
155
169
  end
156
170
  #
157
171
  # Raises exception if the given +transaction+
@@ -161,7 +175,8 @@ module Archipelago
161
175
  raise UnknownTransactionException.new(self, transaction) unless transaction == @transaction
162
176
  end
163
177
  #
164
- # The object_id of our chest-held target.
178
+ # This Dubloon will always have the same object_id, based on
179
+ # @chest_id and @key and possibly @transaction.
165
180
  #
166
181
  def object_id
167
182
  id = "#{@chest_id}:#{@key}"
@@ -172,31 +187,29 @@ module Archipelago
172
187
  # Does our target respond to +meth+?
173
188
  #
174
189
  def respond_to?(meth)
175
- return @public_methods.include?(meth.to_sym) || @public_methods.include?(meth.to_s)
190
+ # This one will be called far too often, and it seems safe to ignore it.
191
+ return false if meth == :marshal_dump
192
+ return super(meth) || self.method_missing(:respond_to?, meth)
176
193
  end
177
194
  #
178
195
  # Call +meth+ with +args+ and +block+ on our target if it responds to
179
196
  # it.
180
197
  #
181
198
  def method_missing(meth, *args, &block)
182
- if respond_to?(meth)
183
- begin
184
- return @chest.call_instance_method(@key, meth, @transaction, *args, &block)
185
- rescue DRb::DRbConnError => e
186
- if defined?(Archipelago::Disco::MC)
187
- possible_replacements = Archipelago::Disco::MC.lookup(Archipelago::Disco::Query.new({:service_id => @chest_id}))
188
- raise e if possible_replacements.empty?
189
-
190
- @chest = possible_replacements[@chest_id][:service]
191
- CHESTS_BY_SERVICE_ID[@chest_id] = @chest
192
-
193
- retry
194
- else
195
- raise e
196
- end
199
+ begin
200
+ return @chest.call_instance_method(@key, meth, @transaction, *args, &block)
201
+ rescue DRb::DRbConnError => e
202
+ if defined?(Archipelago::Disco::MC)
203
+ possible_replacements = Archipelago::Disco::MC.lookup(Archipelago::Disco::Query.new({:service_id => @chest_id}))
204
+ raise e if possible_replacements.empty?
205
+
206
+ @chest = possible_replacements[@chest_id][:service]
207
+ CHEST_BY_SERVICE_ID[@chest_id] = @chest
208
+
209
+ retry
210
+ else
211
+ raise e
197
212
  end
198
- else
199
- return super(meth, *args)
200
213
  end
201
214
  end
202
215
 
@@ -268,7 +281,7 @@ module Archipelago
268
281
 
269
282
  initialize_prepared(options[:transaction_recovery_interval] || TRANSACTION_RECOVERY_INTERVAL)
270
283
 
271
- CHESTS_BY_SERVICE_ID[self.service_id] = self
284
+ CHEST_BY_SERVICE_ID[self.service_id] = self
272
285
  end
273
286
 
274
287
  #
@@ -278,6 +291,17 @@ module Archipelago
278
291
  @snapshot_by_transaction.keys.clone
279
292
  end
280
293
 
294
+ #
295
+ # Will do +callable+.call(key, value)
296
+ # for each key-and-value pair in this Chest.
297
+ #
298
+ # NB: This is totaly thread-unsafe, only do this
299
+ # for management or rescue!
300
+ #
301
+ def each(callable)
302
+ @db.each(callable)
303
+ end
304
+
281
305
  #
282
306
  # Evaluate +data+ if we have not already seen +label+ or if we have an earlier +timestamp+ than the one given.
283
307
  #
@@ -316,7 +340,7 @@ module Archipelago
316
340
  if Dubloon === instance
317
341
  return instance.join(transaction)
318
342
  else
319
- return Dubloon.new(key, self, transaction, self.service_id, instance.public_methods)
343
+ return Dubloon.new(key, self, transaction, self.service_id)
320
344
  end
321
345
  end
322
346
 
@@ -623,7 +647,7 @@ module Archipelago
623
647
  def call_without_transaction(key, method, *arguments, &block)
624
648
  instance = @db[key]
625
649
 
626
- raise UnknownObjectException(self, key, transaction) unless instance
650
+ raise UnknownObjectException(self, key) unless instance
627
651
 
628
652
  begin
629
653
  return execute(instance, method, *arguments, &block)
@@ -721,7 +745,7 @@ module Archipelago
721
745
 
722
746
  return value if Dubloon === value
723
747
 
724
- return Dubloon.new(key, self, transaction, service_id, value.public_methods)
748
+ return Dubloon.new(key, self, transaction, service_id)
725
749
  end
726
750
 
727
751
  #
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  if ARGV.size < 1
4
- puts "Usage: #{$0} DB-PATH [DRB-URI]"
4
+ puts "Usage: #{$0} DB-PATH [EXTRA-LIBS]"
5
5
  exit 1
6
6
  end
7
7
 
@@ -9,11 +9,12 @@ $: << File.join(File.dirname(__FILE__), "..", "lib")
9
9
 
10
10
  require 'archipelago/treasure'
11
11
 
12
- if ARGV.size > 1
13
- DRb.start_service(ARGV[1])
14
- else
15
- DRb.start_service
12
+ ARGV[1..-1].each do |lib|
13
+ load lib
16
14
  end
15
+
16
+ DRb.start_service
17
+
17
18
  c = Archipelago::Treasure::Chest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(ARGV[0])))
18
19
  c.publish!
19
20
 
File without changes
@@ -0,0 +1,61 @@
1
+
2
+ #
3
+ # An overload of Archipelago::Hashish::BerkeleyHashish
4
+ # just to get a few nice debugging methods.
5
+ #
6
+ class Archipelago::Hashish::BerkeleyHashish
7
+ attr_reader :content
8
+ #
9
+ # Get the serialized value for +key+.
10
+ #
11
+ def get_serialized_value(key)
12
+ @content_db[Marshal.dump(key)]
13
+ end
14
+ #
15
+ # Yield to +block+ once for every key/value inside this BerkeleyHashish.
16
+ #
17
+ def each(&block)
18
+ @content_db.each do |serialized_key, serialized_value|
19
+ key = Marshal.load(serialized_key)
20
+ yield(key, self[key])
21
+ end
22
+ end
23
+ #
24
+ # Empties the BerkeleyHashish.
25
+ #
26
+ def clear
27
+ @content_db.clear
28
+ @content.clear
29
+ @timestamps_db.clear
30
+ @timestamps.clear
31
+ end
32
+ end
33
+
34
+ #
35
+ # An overload of Archipelago::Treasure::Chest just to
36
+ # get a few nice debugging methods.
37
+ #
38
+ class Archipelago::Treasure::Chest
39
+ #
40
+ # Yield to +block+ once for every key/value inside this Chest.
41
+ #
42
+ def each(&block)
43
+ @db.each do |key, value|
44
+ yield(key, value)
45
+ end
46
+ end
47
+ #
48
+ # Returns a Hash containing what we contain.
49
+ #
50
+ def all
51
+ @db.each do |key, value|
52
+ end
53
+ @db.content
54
+ end
55
+ #
56
+ # Empties the Chest.
57
+ #
58
+ def clear
59
+ @db.clear
60
+ end
61
+ end
data/script/pirate.rb ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'archipelago/pirate'
4
+
5
+ DRb.start_service
6
+ @p = Archipelago::Pirate::Captain.new
7
+ @p.evaluate!(File.join(File.dirname(__FILE__), 'overloads.rb'))
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.size < 1
4
+ puts "Usage: #{$0} DB-PATH [EXTRA-LIBS]"
5
+ exit 1
6
+ end
7
+
8
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
9
+
10
+ require 'archipelago/treasure'
11
+ require 'archipelago/tranny'
12
+
13
+ ARGV[1..-1].each do |lib|
14
+ load lib
15
+ end
16
+
17
+ DRb.start_service
18
+
19
+ t = Archipelago::Tranny::Manager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(File.join(ARGV[0], "tranny"))))
20
+ t.publish!
21
+ c = Archipelago::Treasure::Chest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(File.join(ARGV[0], "chest"))))
22
+ c.publish!
23
+
24
+ DRb.thread.join
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  if ARGV.size < 1
4
- puts "Usage: #{$0} DB-PATH DRB-URI"
4
+ puts "Usage: #{$0} DB-PATH [EXTRA-LIBS]"
5
5
  exit 1
6
6
  end
7
7
 
@@ -9,11 +9,12 @@ $: << File.join(File.dirname(__FILE__), "..", "lib")
9
9
 
10
10
  require 'archipelago/treasure'
11
11
 
12
- if ARGV.size > 1
13
- DRb.start_service(ARGV[1])
14
- else
15
- DRb.start_service
12
+ ARGV[1..-1].each do |lib|
13
+ load lib
16
14
  end
15
+
16
+ DRb.start_service
17
+
17
18
  t = Archipelago::Tranny::Manager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(ARGV[0])))
18
19
  t.publish!
19
20
 
@@ -0,0 +1,28 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'test_helper')
3
+
4
+ class CurrentBenchmark < Test::Unit::TestCase
5
+
6
+ def test_synchronize
7
+ s = "hehu"
8
+ s2 = "oj"
9
+ s.extend(Archipelago::Current::Synchronized)
10
+ bm("Synchronized#synchronize", :n => 10000) do
11
+ s.synchronize do
12
+ end
13
+ end
14
+ bm("Synchronized#synchronize_on", :n => 10000) do
15
+ s.synchronize_on(s2) do
16
+ end
17
+ end
18
+ bm("Synchronized#lock/unlock", :n => 100000) do
19
+ s.lock
20
+ s.unlock
21
+ end
22
+ bm("Synchronized#lock_on/unlock_on", :n => 10000) do
23
+ s.lock_on(s2)
24
+ s.unlock_on(s2)
25
+ end
26
+ end
27
+
28
+ end
@@ -24,4 +24,33 @@ class CurrentTest < Test::Unit::TestCase
24
24
  end
25
25
  end
26
26
 
27
+ def test_threaded_collection
28
+ a = Array(10)
29
+ a.extend(Archipelago::Current::ThreadedCollection)
30
+
31
+ assert_equal(a.select do |e| e == nil end,
32
+ a.t_select do |e| e == nil end)
33
+ assert_equal(a.reject do |e| e == nil end,
34
+ a.t_reject do |e| e == nil end)
35
+ assert_equal(a.collect do |e| e == nil end,
36
+ a.t_collect do |e| e == nil end)
37
+ b = []
38
+ a.t_each do |e| b << e end
39
+ assert_equal(b, a)
40
+
41
+ a = {1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5}
42
+ a.extend(Archipelago::Current::ThreadedCollection)
43
+
44
+ assert_equal(a.select do |k,v| k == nil end,
45
+ a.t_select do |k,v| k == nil end)
46
+ assert_equal(a.to_a.reject do |k,v| k == nil end,
47
+ a.t_reject do |k,v| k == nil end)
48
+ assert_equal(a.collect do |k,v| k == nil end,
49
+ a.t_collect do |k,c| k == nil end)
50
+
51
+ b = {}
52
+ a.t_each do |k,v| b[k] = v end
53
+ assert_equal(b,a)
54
+ end
55
+
27
56
  end
@@ -0,0 +1,21 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'test_helper')
3
+
4
+ class DiscoBenchmark < Test::Unit::TestCase
5
+
6
+ def test_lookup
7
+ dj1 = TestJockey.new
8
+ dj2 = TestJockey.new
9
+ x = 0
10
+ bm("Jockey#publish/lookup", :n => 10) do
11
+ dj1.publish(Archipelago::Disco::Record.new({:service_id => x, :validator => Archipelago::Disco::MockValidator.new}))
12
+ assert(!dj2.lookup(Archipelago::Disco::Query.new({:service_id => x})).empty?)
13
+ x += 1
14
+ end
15
+ dj1.publish(Archipelago::Disco::Record.new({:service_id => "brappa", :validator => Archipelago::Disco::MockValidator.new}))
16
+ bm("Jockey#lookup", :n => 10) do
17
+ assert(!dj2.lookup(Archipelago::Disco::Query.new({:service_id => "brappa"})).empty?)
18
+ end
19
+ end
20
+
21
+ end
data/tests/evaltest ADDED
@@ -0,0 +1,3 @@
1
+ class Evaltest
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class Evaltestmore
2
+
3
+ end
data/tests/pirate_test.rb CHANGED
@@ -11,24 +11,38 @@ class PirateTest < Test::Unit::TestCase
11
11
  @c.publish!
12
12
  @c2 = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest2.db")))
13
13
  @c2.publish!
14
- @tm = TestManager.new
14
+ @tm = TestManager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("tranny.db")))
15
15
  @tm.publish!
16
+ @p.update_services!
16
17
  assert_within(10) do
17
- !@p.chests.empty?
18
+ @p.chests.keys.sort == [@c.service_id, @c2.service_id].sort
18
19
  end
19
20
  assert_within(10) do
20
- !@p.trannies.empty?
21
+ @p.trannies.keys == [@tm.service_id]
21
22
  end
22
23
  end
23
24
 
24
25
  def teardown
25
26
  @p.stop!
27
+ @c.stop!
26
28
  @c.persistence_provider.unlink
29
+ @c2.stop!
27
30
  @c2.persistence_provider.unlink
31
+ @tm.stop!
28
32
  @tm.persistence_provider.unlink
29
33
  DRb.stop_service
30
34
  end
31
35
 
36
+ def test_each
37
+ @p["oj"] = "bla"
38
+ @p["brunt"] = "ja"
39
+ h = {}
40
+ @p.each(Proc.new do |k,v|
41
+ h[k] = v
42
+ end)
43
+ assert_equal({"oj" => "bla", "brunt" => "ja"}, h)
44
+ end
45
+
32
46
  def test_evaluate
33
47
  assert_raise(NameError) do
34
48
  e = Evaltest.new
data/tests/test_helper.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  home = File.expand_path(File.dirname(__FILE__))
3
3
  $: << File.join(home, "..", "lib")
4
4
 
5
- MC_DISABLED = true
5
+ MC_DISABLED = true unless defined?(MC_ENABLED) && MC_ENABLED
6
6
 
7
7
  require 'pp'
8
8
  require 'drb'
@@ -37,20 +37,20 @@ class TestChest < Archipelago::Treasure::Chest
37
37
  attr_reader :persistence_provider
38
38
  end
39
39
 
40
- class Test::Unit::TestCase
41
-
42
- def bm(label, options = {})
43
- n = options[:n] || 1000
44
- width = options[:width] || 50
45
- Benchmark.benchmark(" " * width + Benchmark::Tms::CAPTION, width, Benchmark::Tms::FMTSTR, "ms/call") do |b|
46
- times = b.report("#{n}x#{label}") do
47
- n.times do
48
- yield
49
- end
40
+ def bm(label = "", options = {})
41
+ n = options[:n] || 1000
42
+ width = options[:width] || 50
43
+ Benchmark.benchmark(" " * width + Benchmark::Tms::CAPTION, width, Benchmark::Tms::FMTSTR, "ms/call") do |b|
44
+ times = b.report("#{n}x#{label}") do
45
+ n.times do
46
+ yield
50
47
  end
51
- [times * 1000 / n.to_f]
52
48
  end
49
+ [times * 1000 / n.to_f]
53
50
  end
51
+ end
52
+
53
+ class Test::Unit::TestCase
54
54
 
55
55
  def assert_within(timeout, &block)
56
56
  t = Time.new
@@ -0,0 +1,85 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'test_helper')
3
+
4
+ class TreasureBenchmark < Test::Unit::TestCase
5
+
6
+ def setup
7
+ DRb.start_service
8
+ @c = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest.db")))
9
+ end
10
+
11
+ def teardown
12
+ @c.persistence_provider.unlink
13
+ DRb.stop_service
14
+ end
15
+
16
+ def test_outside_transaction
17
+ k = "hehu"
18
+ v = "ojoj"
19
+ bm("Chest#[]=", :n => 1000) do
20
+ @c[k] = v
21
+ k = k.next
22
+ end
23
+ k = "hehu"
24
+ bm("Chest#[]", :n => 1000) do
25
+ t = @c[k]
26
+ k = k.next
27
+ end
28
+ k = "hehu"
29
+ bm("Chest#delete", :n => 1000) do
30
+ t = @c.delete(k)
31
+ k = k.next
32
+ end
33
+ @c[k] = v
34
+ v = @c[k]
35
+ bm("Dubloon#method_missing") do
36
+ t = v.size
37
+ end
38
+ end
39
+
40
+ def test_inside_transaction
41
+ k = "hehu"
42
+ v = "ojoj"
43
+ tr = TestTransaction.new
44
+ bm("Chest#[]= (t)", :n => 1000) do
45
+ @c[k,tr] = v
46
+ k = k.next
47
+ end
48
+ k = "hehu"
49
+ bm("Chest#[] (t)", :n => 1000) do
50
+ t = @c[k,tr]
51
+ k = k.next
52
+ end
53
+ k = "hehu"
54
+ bm("Chest#delete (t)", :n => 1000) do
55
+ t = @c.delete(k,tr)
56
+ k = k.next
57
+ end
58
+ @c[k,tr] = v
59
+ v = @c[k,tr]
60
+ bm("Dubloon#method_missing (t)") do
61
+ t = v.upcase
62
+ end
63
+ end
64
+
65
+ def test_transaction_overhead
66
+ k = "hehu"
67
+ v = "ojoj"
68
+ tr = TestTransaction.new
69
+ bm("Chest#join!/[]=/prepare!/commit!", :n => 1000) do
70
+ @c[k, tr] = v
71
+ @c.prepare!(tr)
72
+ @c.commit!(tr)
73
+ end
74
+ bm("Chest#join!/[]=/abort!", :n => 1000) do
75
+ @c[k, tr] = v
76
+ @c.abort!(tr)
77
+ end
78
+ bm("Chest#join!/[]=/prepare!/abort!", :n => 1000) do
79
+ @c[k, tr] = v
80
+ @c.prepare!(tr)
81
+ @c.abort!(tr)
82
+ end
83
+ end
84
+
85
+ end
@@ -1,13 +1,23 @@
1
1
 
2
2
  require File.join(File.dirname(__FILE__), 'test_helper')
3
3
 
4
+ class A < String
5
+ def save_hook(old_value, &block)
6
+ $BURKMAT += 1
7
+ yield
8
+ $BURKMAT2 += 1
9
+ end
10
+ end
11
+
4
12
  class TreasureTest < Test::Unit::TestCase
5
13
 
6
14
  def setup
7
15
  DRb.start_service
8
16
  @c = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest.db")))
9
17
  @c2 = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest2.db")))
10
- @tm = TestManager.new
18
+ @tm = TestManager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("tranny1.db")))
19
+ $BURKMAT = 0
20
+ $BURKMAT2 = 0
11
21
  end
12
22
 
13
23
  def teardown
@@ -17,6 +27,26 @@ class TreasureTest < Test::Unit::TestCase
17
27
  DRb.stop_service
18
28
  end
19
29
 
30
+ def test_each
31
+ @c["oj"] = "bla"
32
+ @c["brunt"] = "ja"
33
+ h = {}
34
+ @c.each(Proc.new do |k,v|
35
+ h[k] = v
36
+ end)
37
+ assert_equal({"oj" => "bla", "brunt" => "ja"}, h)
38
+ end
39
+
40
+ def test_around_save
41
+ s = A.new("hehu")
42
+ @c["oj"] = s
43
+ assert_equal(1, $BURKMAT)
44
+ assert_equal(1, $BURKMAT2)
45
+ @c["oj"].upcase!
46
+ assert_equal(2, $BURKMAT)
47
+ assert_equal(2, $BURKMAT2)
48
+ end
49
+
20
50
  def test_eval
21
51
  t = Time.now
22
52
  @c.evaluate!("burk", t, "class Burk; end")