archipelago 0.1.1 → 0.2.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.
@@ -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")