odba 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -0
- data/LICENSE +459 -0
- data/Manifest.txt +38 -0
- data/README.txt +32 -0
- data/Rakefile +28 -0
- data/install.rb +1098 -0
- data/lib/odba.rb +72 -0
- data/lib/odba/18_19_loading_compatibility.rb +71 -0
- data/lib/odba/cache.rb +603 -0
- data/lib/odba/cache_entry.rb +122 -0
- data/lib/odba/connection_pool.rb +87 -0
- data/lib/odba/drbwrapper.rb +88 -0
- data/lib/odba/id_server.rb +26 -0
- data/lib/odba/index.rb +395 -0
- data/lib/odba/index_definition.rb +24 -0
- data/lib/odba/marshal.rb +18 -0
- data/lib/odba/odba.rb +45 -0
- data/lib/odba/odba_error.rb +12 -0
- data/lib/odba/persistable.rb +621 -0
- data/lib/odba/storage.rb +628 -0
- data/lib/odba/stub.rb +187 -0
- data/sql/collection.sql +6 -0
- data/sql/create_tables.sql +6 -0
- data/sql/object.sql +8 -0
- data/sql/object_connection.sql +7 -0
- data/test/suite.rb +8 -0
- data/test/test_array.rb +108 -0
- data/test/test_cache.rb +725 -0
- data/test/test_cache_entry.rb +109 -0
- data/test/test_connection_pool.rb +77 -0
- data/test/test_drbwrapper.rb +102 -0
- data/test/test_hash.rb +144 -0
- data/test/test_id_server.rb +43 -0
- data/test/test_index.rb +371 -0
- data/test/test_marshal.rb +28 -0
- data/test/test_persistable.rb +625 -0
- data/test/test_storage.rb +829 -0
- data/test/test_stub.rb +226 -0
- metadata +134 -0
data/lib/odba/stub.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#-- Stub -- odba -- 29.04.2004 -- hwyss@ywesee.com rwaltert@ywesee.com mwalder@ywesee.com
|
3
|
+
|
4
|
+
require 'yaml'
|
5
|
+
require 'odba/odba_error'
|
6
|
+
|
7
|
+
module ODBA
|
8
|
+
class Stub # :nodoc: all
|
9
|
+
attr_accessor :odba_id, :odba_container
|
10
|
+
def initialize(odba_id, odba_container, receiver)
|
11
|
+
@odba_id = odba_id
|
12
|
+
@odba_container = odba_container
|
13
|
+
@odba_class = receiver.class unless receiver.nil?
|
14
|
+
@receiver_loaded = true
|
15
|
+
end
|
16
|
+
def class
|
17
|
+
@odba_class ||= odba_instance.class
|
18
|
+
end
|
19
|
+
def eql?(other)
|
20
|
+
@odba_id == other.odba_id || odba_instance.eql?(other)
|
21
|
+
end
|
22
|
+
def inspect
|
23
|
+
"#<ODBA::Stub:#{object_id}##@odba_id @odba_class=#@odba_class @odba_container=#{@odba_container.object_id}##{@odba_container.odba_id}>"
|
24
|
+
end
|
25
|
+
def is_a?(klass)
|
26
|
+
klass == Stub || klass == Persistable || klass == @odba_class \
|
27
|
+
|| odba_instance.is_a?(klass)
|
28
|
+
end
|
29
|
+
def odba_clear_receiver
|
30
|
+
@receiver = nil
|
31
|
+
@receiver_loaded = nil
|
32
|
+
end
|
33
|
+
def odba_dup
|
34
|
+
odba_isolated_stub
|
35
|
+
end
|
36
|
+
def odba_isolated_stub
|
37
|
+
Stub.new(@odba_id, nil, nil)
|
38
|
+
end
|
39
|
+
def odba_prefetch?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
def odba_receiver(name=nil)
|
43
|
+
if(@receiver && !@receiver_loaded)
|
44
|
+
warn "stub for #{@receiver.class}:#{@odba_id} was saved with receiver"
|
45
|
+
@receiver = nil
|
46
|
+
end
|
47
|
+
@receiver || begin
|
48
|
+
#begin
|
49
|
+
@receiver = ODBA.cache.fetch(@odba_id, @odba_container)
|
50
|
+
@receiver_loaded = true
|
51
|
+
if(@odba_container)
|
52
|
+
@odba_container.odba_replace_stubs(@odba_id, @receiver)
|
53
|
+
else
|
54
|
+
warn "Potential Memory-Leak: stub for #{@receiver.class}##{@odba_id} was saved without container"
|
55
|
+
end
|
56
|
+
@receiver
|
57
|
+
rescue OdbaError => e
|
58
|
+
warn "ODBA::Stub was unable to replace #{@odba_class}##{@odba_id} from #{@odba_container.class}:##{@odba_container.odba_id}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
alias :odba_instance :odba_receiver
|
62
|
+
# A stub always references a Persistable that has
|
63
|
+
# already been saved.
|
64
|
+
def odba_unsaved?(snapshot_level=nil)
|
65
|
+
false
|
66
|
+
end
|
67
|
+
def to_yaml_properties
|
68
|
+
['@odba_id', '@odba_container']
|
69
|
+
end
|
70
|
+
def to_yaml_type
|
71
|
+
"!ruby/object:ODBA::Stub"
|
72
|
+
end
|
73
|
+
def yaml_initialize(tag, val)
|
74
|
+
if RUBY_VERSION >= '1.9'
|
75
|
+
val.each { |key, value| instance_variable_set(:"@#{key}", value) }
|
76
|
+
else
|
77
|
+
val.each { |key, value| instance_variable_set("@#{key}", value) }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
no_override = [
|
81
|
+
"class", "is_a?", "__id__", "__send__", "inspect",
|
82
|
+
"eql?", "nil?", "respond_to?", "object_id",
|
83
|
+
"instance_variables", "instance_variable_get",
|
84
|
+
"instance_variable_set", "==",
|
85
|
+
## methods defined in persistable.rb:Object
|
86
|
+
"odba_id", "odba_instance", "odba_isolated_stub", "odba_prefetch?",
|
87
|
+
## yaml-methods
|
88
|
+
"to_yaml", "taguri", "to_yaml_style", "to_yaml_type",
|
89
|
+
"to_yaml_properties", "yaml_initialize",
|
90
|
+
]
|
91
|
+
NO_OVERRIDE = no_override.collect { |name| name.to_sym }
|
92
|
+
if RUBY_VERSION >= '1.9'
|
93
|
+
no_override = NO_OVERRIDE
|
94
|
+
end
|
95
|
+
override_methods = Object.public_methods - no_override
|
96
|
+
override_methods.each { |method|
|
97
|
+
src = (method[-1] == ?=) ? <<-EOW : <<-EOS
|
98
|
+
def #{method}(args)
|
99
|
+
odba_instance.#{method}(args)
|
100
|
+
end
|
101
|
+
EOW
|
102
|
+
def #{method}(*args)
|
103
|
+
odba_instance.#{method}(*args)
|
104
|
+
end
|
105
|
+
EOS
|
106
|
+
eval src
|
107
|
+
}
|
108
|
+
def method_missing(meth_symbol, *args, &block)
|
109
|
+
if(NO_OVERRIDE.include?(meth_symbol))
|
110
|
+
super
|
111
|
+
else
|
112
|
+
odba_instance.send(meth_symbol, *args, &block)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
def respond_to?(msg_id, *args)
|
116
|
+
case msg_id
|
117
|
+
when :_dump, :marshal_dump
|
118
|
+
false
|
119
|
+
when *NO_OVERRIDE
|
120
|
+
super
|
121
|
+
else
|
122
|
+
odba_instance.respond_to?(msg_id, *args)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
## FIXME
|
126
|
+
# implement full hash/array access - separate collection stub?
|
127
|
+
def [](*args, &block)
|
128
|
+
if(@odba_class == Hash \
|
129
|
+
&& !ODBA.cache.include?(@odba_id))
|
130
|
+
ODBA.cache.fetch_collection_element(@odba_id, args.first)
|
131
|
+
end || method_missing(:[], *args, &block)
|
132
|
+
end
|
133
|
+
def ==(other)
|
134
|
+
@odba_id == other.odba_id || odba_instance == other
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class Array # :nodoc: all
|
140
|
+
alias :_odba_amp :&
|
141
|
+
def &(stub)
|
142
|
+
self._odba_amp(stub.odba_instance)
|
143
|
+
end
|
144
|
+
alias :_odba_plus :+
|
145
|
+
def +(stub)
|
146
|
+
self._odba_plus(stub.odba_instance)
|
147
|
+
end
|
148
|
+
alias :_odba_minus :-
|
149
|
+
def -(stub)
|
150
|
+
self._odba_minus(stub.odba_instance)
|
151
|
+
end
|
152
|
+
alias :_odba_weight :<=>
|
153
|
+
def <=>(stub)
|
154
|
+
self._odba_weight(stub.odba_instance)
|
155
|
+
end
|
156
|
+
alias :_odba_equal? :==
|
157
|
+
def ==(stub)
|
158
|
+
self._odba_equal?(stub.odba_instance)
|
159
|
+
end
|
160
|
+
alias :_odba_union :|
|
161
|
+
def |(stub)
|
162
|
+
self._odba_union(stub.odba_instance)
|
163
|
+
end
|
164
|
+
['concat', 'replace', 'include?'].each { |method|
|
165
|
+
#['concat', 'replace'].each { |method|
|
166
|
+
eval <<-EOS
|
167
|
+
alias :_odba_#{method} :#{method}
|
168
|
+
def #{method}(stub)
|
169
|
+
self._odba_#{method}(stub.odba_instance)
|
170
|
+
end
|
171
|
+
EOS
|
172
|
+
}
|
173
|
+
end
|
174
|
+
class Hash # :nodoc: all
|
175
|
+
alias :_odba_equal? :==
|
176
|
+
def ==(stub)
|
177
|
+
self._odba_equal?(stub.odba_instance)
|
178
|
+
end
|
179
|
+
['merge', 'merge!', 'replace'].each { |method|
|
180
|
+
eval <<-EOS
|
181
|
+
alias :_odba_#{method} :#{method}
|
182
|
+
def #{method}(stub)
|
183
|
+
self._odba_#{method}(stub.odba_instance)
|
184
|
+
end
|
185
|
+
EOS
|
186
|
+
}
|
187
|
+
end
|
data/sql/collection.sql
ADDED
data/sql/object.sql
ADDED
data/test/suite.rb
ADDED
data/test/test_array.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# TestArray -- odba -- 30.01.2007 -- hwyss@ywesee.com
|
3
|
+
|
4
|
+
$: << File.dirname(__FILE__)
|
5
|
+
$: << File.expand_path('../lib', File.dirname(__FILE__))
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
require 'flexmock'
|
9
|
+
require 'odba/persistable'
|
10
|
+
require 'odba/stub'
|
11
|
+
require 'odba/odba'
|
12
|
+
|
13
|
+
module ODBA
|
14
|
+
class TestArray < Test::Unit::TestCase
|
15
|
+
include FlexMock::TestCase
|
16
|
+
class ODBAContainer
|
17
|
+
include ODBA::Persistable
|
18
|
+
attr_accessor :non_replaceable, :replaceable, :array, :odba_id
|
19
|
+
end
|
20
|
+
class Container
|
21
|
+
attr_accessor :content
|
22
|
+
end
|
23
|
+
def setup
|
24
|
+
@array = Array.new
|
25
|
+
ODBA.storage = flexmock("storage")
|
26
|
+
ODBA.marshaller = flexmock("marshaller")
|
27
|
+
ODBA.cache = flexmock("cache")
|
28
|
+
end
|
29
|
+
def test_odba_cut_connection
|
30
|
+
remove_obj = Object
|
31
|
+
remove_obj.extend(ODBA::Persistable)
|
32
|
+
remove_obj.instance_variable_set('@odba_id', 2)
|
33
|
+
receiver = ODBA::Stub.new(2,self, remove_obj)
|
34
|
+
array = Array.new
|
35
|
+
array.push(receiver)
|
36
|
+
assert_equal(0, array.odba_cut_connection(remove_obj).size)
|
37
|
+
end
|
38
|
+
def test_odba_unsaved_neighbors_array
|
39
|
+
rep1 = ODBAContainer.new
|
40
|
+
rep2 = ODBAContainer.new
|
41
|
+
@array.push(rep1)
|
42
|
+
@array.push(rep2)
|
43
|
+
result = @array.odba_unsaved_neighbors(1)
|
44
|
+
assert_equal([rep1, rep2], result)
|
45
|
+
end
|
46
|
+
def test_array_replacement
|
47
|
+
replacement = flexmock('replacement')
|
48
|
+
replacement2 = flexmock('replacement2')
|
49
|
+
stub = flexmock('stub')
|
50
|
+
stub2 = flexmock('stub2')
|
51
|
+
foo = flexmock("foo")
|
52
|
+
@array.push(stub)
|
53
|
+
@array.push(stub2)
|
54
|
+
@array.odba_restore([[0,replacement], [1,replacement2]])
|
55
|
+
assert_equal(replacement, @array[0])
|
56
|
+
assert_equal(replacement2, @array[1])
|
57
|
+
end
|
58
|
+
def test_odba_replace_persistables_array
|
59
|
+
replaceable = flexmock("replaceable")
|
60
|
+
replaceable2 = flexmock("replaceable2")
|
61
|
+
@array.push(replaceable)
|
62
|
+
@array.push(replaceable2)
|
63
|
+
@array.odba_replace_persistables
|
64
|
+
#size is 0 because we store empty array in the db
|
65
|
+
# content of the array is in the collection table
|
66
|
+
assert_equal(0, @array.size)
|
67
|
+
end
|
68
|
+
def test_odba_unsaved_array_true
|
69
|
+
val = flexmock("val")
|
70
|
+
@array.instance_variable_set("@odba_persistent", true)
|
71
|
+
@array.push(val)
|
72
|
+
val.should_receive(:is_a?).and_return { |klass| true }
|
73
|
+
val.should_receive(:odba_unsaved?).and_return { true }
|
74
|
+
assert_equal(true, @array.odba_unsaved?)
|
75
|
+
end
|
76
|
+
def test_odba_collection
|
77
|
+
@array.push('foo', 'bar')
|
78
|
+
assert_equal([[0,'foo'], [1, 'bar']], @array.odba_collection)
|
79
|
+
end
|
80
|
+
def test_odba_replace
|
81
|
+
modified = ['foo']
|
82
|
+
reloaded = modified.dup
|
83
|
+
modified.push('bar')
|
84
|
+
modified.odba_replace!(reloaded)
|
85
|
+
assert_equal(reloaded, modified)
|
86
|
+
end
|
87
|
+
def test_odba_target_ids
|
88
|
+
o = ODBAContainer.new
|
89
|
+
o.odba_id = 1
|
90
|
+
p = ODBAContainer.new
|
91
|
+
p.odba_id = 2
|
92
|
+
q = ODBAContainer.new
|
93
|
+
q.odba_id = 3
|
94
|
+
@array.push(p, q)
|
95
|
+
@array.instance_variable_set('@foo', o)
|
96
|
+
assert_equal([1,2,3], @array.odba_target_ids)
|
97
|
+
end
|
98
|
+
def test_stubize
|
99
|
+
item = ODBAContainer.new
|
100
|
+
@array.push(item)
|
101
|
+
@array.odba_stubize(item)
|
102
|
+
first = @array.first
|
103
|
+
assert_equal false, first.is_a?(ODBA::Stub)
|
104
|
+
assert @array.include?(item)
|
105
|
+
assert_equal false, first.is_a?(ODBA::Stub)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/test/test_cache.rb
ADDED
@@ -0,0 +1,725 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__)
|
4
|
+
$: << File.expand_path('../lib/', File.dirname(__FILE__))
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
require 'flexmock'
|
8
|
+
require 'odba/cache'
|
9
|
+
require 'odba/cache_entry'
|
10
|
+
require 'odba/persistable'
|
11
|
+
require 'odba/index'
|
12
|
+
require 'odba/index_definition'
|
13
|
+
require 'odba/odba_error'
|
14
|
+
require 'odba/odba'
|
15
|
+
|
16
|
+
module ODBA
|
17
|
+
class Cache
|
18
|
+
CLEANING_INTERVAL = 0
|
19
|
+
MAIL_RECIPIENTS = []
|
20
|
+
MAIL_FROM = "test@testfirst.local"
|
21
|
+
attr_accessor :cleaner, :fetched, :cache_entry_factory, :prefetched
|
22
|
+
attr_writer :indices
|
23
|
+
public :load_object
|
24
|
+
end
|
25
|
+
class TestCache < Test::Unit::TestCase
|
26
|
+
include FlexMock::TestCase
|
27
|
+
class ODBAContainer
|
28
|
+
include ODBA::Persistable
|
29
|
+
attr_accessor :odba_connection, :odba_id
|
30
|
+
end
|
31
|
+
def setup
|
32
|
+
@storage = ODBA.storage = flexmock("storage")
|
33
|
+
@marshal = ODBA.marshaller = flexmock("marshaller")
|
34
|
+
ODBA.cache = @cache = ODBA::Cache.instance
|
35
|
+
@cache.fetched = {}
|
36
|
+
@cache.prefetched = {}
|
37
|
+
@cache.indices = {}
|
38
|
+
end
|
39
|
+
def teardown
|
40
|
+
super
|
41
|
+
ODBA.storage = nil
|
42
|
+
ODBA.marshaller = nil
|
43
|
+
@cache.fetched.clear
|
44
|
+
@cache.prefetched.clear
|
45
|
+
@cache.indices.clear
|
46
|
+
end
|
47
|
+
def test_fetch_named_ok
|
48
|
+
obj = flexmock
|
49
|
+
obj.instance_variable_set("@odba_name", 'the_name')
|
50
|
+
obj.instance_variable_set("@odba_id", 2)
|
51
|
+
@marshal.should_receive(:load).with('dump2').and_return(obj)
|
52
|
+
@storage.should_receive(:restore_named).and_return('dump2')
|
53
|
+
@storage.should_receive(:restore_collection).and_return([])
|
54
|
+
load_1 = @cache.fetch_named('the_name', nil)
|
55
|
+
assert_instance_of(FlexMock, load_1)
|
56
|
+
assert_equal('the_name', load_1.odba_name)
|
57
|
+
assert_equal(2, load_1.odba_id)
|
58
|
+
load_2 = @cache.fetch_named('the_name', nil)
|
59
|
+
assert_equal(load_1, load_2)
|
60
|
+
load_3 = @cache.fetch(2, nil)
|
61
|
+
assert_equal(load_1, load_3)
|
62
|
+
end
|
63
|
+
def test_bulk_fetch_load_all
|
64
|
+
old_marshal = ODBA.marshaller
|
65
|
+
ODBA.marshaller = marshal = flexmock('Marshal')
|
66
|
+
array = [2, 3]
|
67
|
+
obj1 = Object.new
|
68
|
+
obj1.instance_variable_set("@odba_id", 2)
|
69
|
+
obj1.instance_variable_set("@odba_prefetch", false)
|
70
|
+
obj1.instance_variable_set("@odba_name", nil)
|
71
|
+
obj2 = Object.new
|
72
|
+
obj2.instance_variable_set("@odba_id", 3)
|
73
|
+
obj2.instance_variable_set("@odba_prefetch", true)
|
74
|
+
obj2.instance_variable_set("@odba_name", nil)
|
75
|
+
dump_1 = Marshal.dump(obj1)
|
76
|
+
dump_2 = Marshal.dump(obj2)
|
77
|
+
@storage.should_receive(:bulk_restore)\
|
78
|
+
.and_return([[2, dump_1],[3, dump_2]])
|
79
|
+
dumps = [dump_1, dump_2]
|
80
|
+
objs = [obj1, obj2]
|
81
|
+
marshal.should_receive(:load).and_return { |dump|
|
82
|
+
assert_equal(dumps.shift, dump)
|
83
|
+
objs.shift
|
84
|
+
}
|
85
|
+
@storage.should_receive(:restore_collection).and_return([])
|
86
|
+
loaded = @cache.bulk_fetch(array, nil)
|
87
|
+
assert_equal([obj1, obj2], loaded)
|
88
|
+
assert_equal([2], @cache.fetched.keys)
|
89
|
+
assert_equal([3], @cache.prefetched.keys)
|
90
|
+
assert_instance_of(CacheEntry, @cache.fetched[2])
|
91
|
+
assert_instance_of(CacheEntry, @cache.prefetched[3])
|
92
|
+
ensure
|
93
|
+
ODBA.marshaller = old_marshal
|
94
|
+
end
|
95
|
+
def test_bulk_fetch
|
96
|
+
old_marshal = ODBA.marshaller
|
97
|
+
ODBA.marshaller = marshal = flexmock('Marshal')
|
98
|
+
array = [2, 3, 7]
|
99
|
+
baz = flexmock('loaded')
|
100
|
+
baz.should_receive(:odba_add_reference).and_return { |odba_caller| }
|
101
|
+
baz.should_receive(:odba_object).and_return { 'foo' }
|
102
|
+
@cache.fetched = {
|
103
|
+
7 => baz
|
104
|
+
}
|
105
|
+
obj1 = Object.new
|
106
|
+
obj1.instance_variable_set("@odba_id", 2)
|
107
|
+
obj1.instance_variable_set("@odba_prefetch", false)
|
108
|
+
obj1.instance_variable_set("@odba_name", nil)
|
109
|
+
obj2 = Object.new
|
110
|
+
obj2.instance_variable_set("@odba_id", 3)
|
111
|
+
obj2.instance_variable_set("@odba_prefetch", false)
|
112
|
+
obj2.instance_variable_set("@odba_name", nil)
|
113
|
+
dump_1 = Marshal.dump(obj1)
|
114
|
+
dump_2 = Marshal.dump(obj2)
|
115
|
+
dumps = [dump_1, dump_2]
|
116
|
+
objs = [obj1, obj2]
|
117
|
+
marshal.should_receive(:load).and_return { |dump|
|
118
|
+
assert_equal(dumps.shift, dump)
|
119
|
+
objs.shift
|
120
|
+
}
|
121
|
+
@storage.should_receive(:bulk_restore).and_return([[2, dump_1],[3, dump_2]])
|
122
|
+
@storage.should_receive(:restore_collection).and_return([])
|
123
|
+
@cache.bulk_fetch(array, nil)
|
124
|
+
assert_equal(true, @cache.fetched.has_key?(2))
|
125
|
+
assert_equal(3, @cache.fetched.size)
|
126
|
+
assert_equal(true, @cache.fetched.has_key?(3))
|
127
|
+
ODBA.marshaller = old_marshal
|
128
|
+
end
|
129
|
+
def test_bulk_restore_in_fetchedadd_caller
|
130
|
+
obj = Object.new
|
131
|
+
cache_entry = flexmock('cache_entry')
|
132
|
+
cache_entry.should_receive(:odba_object).and_return {
|
133
|
+
obj
|
134
|
+
}
|
135
|
+
cache_entry.should_receive(:_odba_object).and_return {
|
136
|
+
obj
|
137
|
+
}
|
138
|
+
cache_entry.should_receive(:odba_add_reference).and_return {|caller|
|
139
|
+
#this assert_equal is interesting
|
140
|
+
assert_equal('Reference', caller)
|
141
|
+
}
|
142
|
+
@cache.fetched.store(1, cache_entry)
|
143
|
+
rows = [[1, '']]
|
144
|
+
retrieved = @cache.bulk_restore(rows, 'Reference')
|
145
|
+
end
|
146
|
+
def test_clean
|
147
|
+
obj1 = flexmock
|
148
|
+
obj2 = flexmock
|
149
|
+
@cache.fetched.store(2, obj1)
|
150
|
+
@cache.fetched.store(3, obj2)
|
151
|
+
assert_equal(2, @cache.fetched.size)
|
152
|
+
obj1.should_receive(:odba_old?).and_return { true }
|
153
|
+
obj1.should_receive(:odba_retire).and_return { }
|
154
|
+
obj2.should_receive(:odba_old?).and_return { false }
|
155
|
+
@cache.clean
|
156
|
+
assert_equal(2, @cache.fetched.size)
|
157
|
+
end
|
158
|
+
def test_clean__prefetched
|
159
|
+
obj1 = flexmock
|
160
|
+
obj2 = flexmock
|
161
|
+
@cache.prefetched.store(2, obj1)
|
162
|
+
@cache.prefetched.store(3, obj2)
|
163
|
+
assert_equal(2, @cache.prefetched.size)
|
164
|
+
obj1.should_receive(:ready_to_destroy?).and_return { false }
|
165
|
+
obj1.should_receive(:odba_old?).and_return { true }
|
166
|
+
obj1.should_receive(:odba_retire).and_return { }
|
167
|
+
obj2.should_receive(:ready_to_destroy?).and_return { false }
|
168
|
+
obj2.should_receive(:odba_old?).and_return { false }
|
169
|
+
@cache.clean_prefetched
|
170
|
+
assert_equal(2, @cache.prefetched.size)
|
171
|
+
end
|
172
|
+
def test_clear
|
173
|
+
value = flexmock("value")
|
174
|
+
obj = flexmock('object')
|
175
|
+
prefetched = flexmock('prefetched')
|
176
|
+
@cache.fetched.store(12, value)
|
177
|
+
@cache.prefetched.store(13, prefetched)
|
178
|
+
assert_equal(2, @cache.size)
|
179
|
+
@cache.clear
|
180
|
+
assert_equal(0, @cache.size)
|
181
|
+
end
|
182
|
+
def test_fetch_named_block
|
183
|
+
restore = flexmock("restore")
|
184
|
+
caller = flexmock("caller")
|
185
|
+
caller2 = flexmock("caller2")
|
186
|
+
@storage.should_receive(:restore_named).and_return { |name| }
|
187
|
+
restore.should_receive(:odba_name=).and_return { |name| }
|
188
|
+
restore.should_receive(:odba_store).and_return { |obj| }
|
189
|
+
result = @cache.fetch_named("foo", caller2) {
|
190
|
+
restore
|
191
|
+
}
|
192
|
+
assert_equal(restore, result)
|
193
|
+
end
|
194
|
+
def prepare_fetch(id, receiver)
|
195
|
+
@storage.should_receive(:restore).and_return { |odba_id|
|
196
|
+
assert_equal(id, odba_id)
|
197
|
+
odba_id
|
198
|
+
}
|
199
|
+
@marshal.should_receive(:load).and_return { receiver }
|
200
|
+
if(receiver.is_a?(FlexMock))
|
201
|
+
receiver.should_receive(:odba_restore).and_return {}
|
202
|
+
receiver.should_receive(:odba_name).and_return {}
|
203
|
+
end
|
204
|
+
end
|
205
|
+
def test_fetch_has_name
|
206
|
+
caller1 = flexmock('Caller1')
|
207
|
+
caller2 = flexmock('Caller2')
|
208
|
+
caller3 = flexmock('Caller3')
|
209
|
+
receiver = flexmock('Receiver')
|
210
|
+
@storage.should_receive(:restore).and_return { |odba_id|
|
211
|
+
assert_equal(23, odba_id)
|
212
|
+
odba_id
|
213
|
+
}
|
214
|
+
@marshal.should_receive(:load).and_return {|dump|
|
215
|
+
receiver
|
216
|
+
}
|
217
|
+
@storage.should_receive(:restore_collection).and_return {|*args|
|
218
|
+
[]
|
219
|
+
}
|
220
|
+
receiver.instance_variable_set("@odba_id", 23)
|
221
|
+
receiver.instance_variable_set("@odba_name", 'name')
|
222
|
+
first_fetch = @cache.fetch(23, caller1)
|
223
|
+
assert_equal(receiver, first_fetch)
|
224
|
+
assert_equal(2, @cache.fetched.size)
|
225
|
+
assert(@cache.fetched.include?('name'))
|
226
|
+
second_fetch = @cache.fetch(23, caller2)
|
227
|
+
assert_equal(receiver, second_fetch)
|
228
|
+
named_fetch = @cache.fetch_named('name', caller3)
|
229
|
+
assert_equal(receiver, named_fetch)
|
230
|
+
end
|
231
|
+
def test_fetch_error
|
232
|
+
receiver = flexmock
|
233
|
+
@storage.should_receive(:restore).and_return { |odba_id|
|
234
|
+
nil
|
235
|
+
}
|
236
|
+
assert_raises(OdbaError) {
|
237
|
+
@cache.load_object(23, receiver)
|
238
|
+
}
|
239
|
+
end
|
240
|
+
def test_fetch__adds_reference
|
241
|
+
obj = flexmock
|
242
|
+
obj.instance_variable_set("@odba_id", 23)
|
243
|
+
obj.instance_variable_set("@odba_prefetch", false)
|
244
|
+
@storage.should_receive(:restore).and_return { |id|
|
245
|
+
assert_equal(23, id)
|
246
|
+
'dump'
|
247
|
+
}
|
248
|
+
@storage.should_receive(:restore_collection).and_return { |id|
|
249
|
+
[]
|
250
|
+
}
|
251
|
+
@marshal.should_receive(:load).and_return { |dump|
|
252
|
+
assert_equal('dump', dump)
|
253
|
+
obj
|
254
|
+
}
|
255
|
+
callr = flexmock
|
256
|
+
res = @cache.fetch(23, callr)
|
257
|
+
cache_entry = @cache.fetched[23]
|
258
|
+
assert_instance_of(CacheEntry, cache_entry)
|
259
|
+
assert_equal([callr.object_id], cache_entry.accessed_by.keys)
|
260
|
+
assert_equal(obj, res)
|
261
|
+
## test for duplicates
|
262
|
+
@cache.fetch(23, callr)
|
263
|
+
assert_equal([callr.object_id], cache_entry.accessed_by.keys)
|
264
|
+
end
|
265
|
+
def test_store
|
266
|
+
cont = flexmock('CacheEntry')
|
267
|
+
@cache.fetched.store(3, cont)
|
268
|
+
save_obj = flexmock("save_obj")
|
269
|
+
save_obj.should_receive(:odba_target_ids).and_return([3])
|
270
|
+
save_obj.should_receive(:odba_observers).and_return { [] }
|
271
|
+
prepare_store([save_obj])
|
272
|
+
save_obj.should_receive(:odba_add_observer)
|
273
|
+
cont.should_receive(:odba_add_reference).with(save_obj)\
|
274
|
+
.and_return { assert(true) }
|
275
|
+
@cache.store(save_obj)
|
276
|
+
end
|
277
|
+
def test_store_collection_elements
|
278
|
+
old_mar = ODBA.marshaller
|
279
|
+
ODBA.marshaller = Marshal
|
280
|
+
|
281
|
+
old_collection = [['key1', 'val1'], ['key2', 'val2']]
|
282
|
+
new_collection = [['key2', 'val2'], ['key3', 'val3']]
|
283
|
+
|
284
|
+
cache_entry = flexmock('cache_entry')
|
285
|
+
cache_entry.should_receive(:collection).and_return { old_collection }
|
286
|
+
cache_entry.should_receive(:collection=).and_return { |col|
|
287
|
+
assert_equal(new_collection, col)
|
288
|
+
}
|
289
|
+
|
290
|
+
@storage.should_receive(:restore_collection).and_return {
|
291
|
+
old_collection.collect { |key, val|
|
292
|
+
[Marshal.dump(key.odba_isolated_stub),
|
293
|
+
Marshal.dump(val.odba_isolated_stub)]
|
294
|
+
}
|
295
|
+
}
|
296
|
+
@storage.should_receive(:collection_remove).and_return { |odba_id, key|
|
297
|
+
assert_equal(54, odba_id)
|
298
|
+
assert_equal(Marshal.dump('key1'.odba_isolated_stub), key)
|
299
|
+
}
|
300
|
+
@storage.should_receive(:collection_store).and_return { |odba_id, key, value|
|
301
|
+
assert_equal(54, odba_id)
|
302
|
+
assert_equal(Marshal.dump('key3'.odba_isolated_stub), key)
|
303
|
+
assert_equal(Marshal.dump('val3'.odba_isolated_stub), value)
|
304
|
+
}
|
305
|
+
|
306
|
+
@cache.fetched = {
|
307
|
+
54 => cache_entry
|
308
|
+
}
|
309
|
+
|
310
|
+
obj = flexmock('Obj')
|
311
|
+
obj.should_receive(:odba_id).and_return { 54 }
|
312
|
+
obj.should_receive(:odba_collection).and_return { new_collection }
|
313
|
+
@cache.store_collection_elements(obj)
|
314
|
+
ensure
|
315
|
+
ODBA.marshaller = old_mar
|
316
|
+
end
|
317
|
+
def test_store_object_connections
|
318
|
+
@storage.should_receive(:ensure_object_connections).and_return { |id,target_ids|
|
319
|
+
assert_equal(4, id)
|
320
|
+
assert_equal([1,2], target_ids)
|
321
|
+
}
|
322
|
+
@cache.store_object_connections(4, [1,2])
|
323
|
+
end
|
324
|
+
def test_load__and_restore_object
|
325
|
+
caller1 = flexmock
|
326
|
+
loaded = flexmock
|
327
|
+
@storage.should_receive(:restore).and_return { |odba_id|
|
328
|
+
assert_equal(23, odba_id)
|
329
|
+
'dump'
|
330
|
+
}
|
331
|
+
@marshal.should_receive(:load).and_return { |dump|
|
332
|
+
assert_equal('dump', dump)
|
333
|
+
loaded
|
334
|
+
}
|
335
|
+
@storage.should_receive(:restore_collection).and_return { [] }
|
336
|
+
|
337
|
+
loaded.instance_variable_set('@odba_id', 23)
|
338
|
+
@cache.load_object(23, caller1)
|
339
|
+
end
|
340
|
+
def test_prefetch
|
341
|
+
foo = flexmock("foo")
|
342
|
+
@storage.should_receive(:restore_prefetchable).and_return {
|
343
|
+
[[2, foo]]
|
344
|
+
}
|
345
|
+
prepare_bulk_restore([foo])
|
346
|
+
assert_nothing_raised {
|
347
|
+
@cache.prefetch
|
348
|
+
}
|
349
|
+
end
|
350
|
+
def test_fill_index
|
351
|
+
foo = flexmock("foo")
|
352
|
+
foo.should_receive(:fill).and_return { |target|
|
353
|
+
assert_equal("baz", target)
|
354
|
+
}
|
355
|
+
@cache.indices = {
|
356
|
+
"foo" => foo
|
357
|
+
}
|
358
|
+
@cache.fill_index("foo", "baz")
|
359
|
+
end
|
360
|
+
def test_create_index
|
361
|
+
df = IndexDefinition.new
|
362
|
+
df.index_name = 'index'
|
363
|
+
indices = flexmock('indices')
|
364
|
+
indices.should_receive(:store).and_return { |key, val|
|
365
|
+
assert_instance_of(Index, val)
|
366
|
+
}
|
367
|
+
indices.should_receive(:odba_store_unsaved).times(1)
|
368
|
+
@cache.instance_variable_set('@indices', indices)
|
369
|
+
@storage.should_receive(:transaction).and_return { |block| block.call }
|
370
|
+
@storage.should_receive(:create_index).times(1)
|
371
|
+
index = @cache.create_index(df, flexmock)
|
372
|
+
assert_instance_of(Index, index)
|
373
|
+
@cache.instance_variable_set('@indices', {})
|
374
|
+
end
|
375
|
+
def test_create_index__fulltext
|
376
|
+
df = IndexDefinition.new
|
377
|
+
df.index_name = 'index'
|
378
|
+
df.fulltext = true
|
379
|
+
indices = flexmock('indices')
|
380
|
+
indices.should_receive(:store).and_return { |key, val|
|
381
|
+
assert_instance_of(FulltextIndex, val)
|
382
|
+
}
|
383
|
+
indices.should_receive(:odba_store_unsaved).times(1)
|
384
|
+
@cache.instance_variable_set('@indices', indices)
|
385
|
+
@storage.should_receive(:transaction).and_return { |block| block.call }
|
386
|
+
@storage.should_receive(:create_fulltext_index).times(1)
|
387
|
+
index = @cache.create_index(df, flexmock)
|
388
|
+
assert_instance_of(FulltextIndex, index)
|
389
|
+
@cache.instance_variable_set('@indices', {})
|
390
|
+
end
|
391
|
+
def test_create_index__condition
|
392
|
+
df = IndexDefinition.new
|
393
|
+
df.index_name = 'index'
|
394
|
+
df.resolve_search_term = { }
|
395
|
+
indices = flexmock('indices')
|
396
|
+
indices.should_receive(:store).and_return { |key, val|
|
397
|
+
assert_instance_of(ConditionIndex, val)
|
398
|
+
}
|
399
|
+
indices.should_receive(:odba_store_unsaved).times(1)
|
400
|
+
@cache.instance_variable_set('@indices', indices)
|
401
|
+
@storage.should_receive(:transaction).and_return { |block| block.call }
|
402
|
+
@storage.should_receive(:create_condition_index).times(1)
|
403
|
+
index = @cache.create_index(df, flexmock)
|
404
|
+
assert_instance_of(ConditionIndex, index)
|
405
|
+
@cache.instance_variable_set('@indices', {})
|
406
|
+
end
|
407
|
+
def prepare_fetch_collection(obj)
|
408
|
+
end
|
409
|
+
def prepare_store(store_array, &block)
|
410
|
+
store_array.each { |mock|
|
411
|
+
# store
|
412
|
+
mock.should_receive(:odba_id).and_return { || }
|
413
|
+
mock.should_receive(:odba_name).and_return { || }
|
414
|
+
mock.should_receive(:odba_notify_observers).and_return { |key, id1, id2|
|
415
|
+
assert_equal(:store, key)
|
416
|
+
}
|
417
|
+
mock.should_receive(:odba_isolated_dump).and_return { || }
|
418
|
+
|
419
|
+
# store_collection_elements
|
420
|
+
mock.should_receive(:odba_id).and_return { || }
|
421
|
+
mock.should_receive(:odba_collection).and_return {|| []}
|
422
|
+
mock.should_receive(:odba_id).and_return { || }
|
423
|
+
|
424
|
+
# store
|
425
|
+
mock.should_receive(:odba_prefetch?).and_return { || }
|
426
|
+
|
427
|
+
# store_object_connections
|
428
|
+
mock.should_receive(:odba_target_ids).and_return { || [] }
|
429
|
+
|
430
|
+
# update_indices
|
431
|
+
mock.should_receive(:odba_indexable?).and_return {}
|
432
|
+
|
433
|
+
# store_cache_entry
|
434
|
+
mock.should_receive(:odba_prefetch?).and_return { || }
|
435
|
+
mock.should_receive(:odba_collection).and_return { || [] }
|
436
|
+
|
437
|
+
@storage.should_receive(:restore_collection).and_return { [] }
|
438
|
+
if(block)
|
439
|
+
@storage.should_receive(:store, &block).and_return
|
440
|
+
else
|
441
|
+
@storage.should_receive(:store).and_return {
|
442
|
+
assert(true)
|
443
|
+
}
|
444
|
+
end
|
445
|
+
@storage.should_receive(:ensure_object_connections).and_return {|*args|}
|
446
|
+
}
|
447
|
+
end
|
448
|
+
def test_delete
|
449
|
+
delete_item = ODBAContainer.new
|
450
|
+
delete_item.odba_id = 1
|
451
|
+
origin_obj = ODBAContainer.new
|
452
|
+
origin_obj.odba_id = 2
|
453
|
+
origin_obj.odba_connection = delete_item
|
454
|
+
@cache.fetched.store(1, delete_item)
|
455
|
+
@storage.should_receive(:retrieve_connected_objects).and_return { |id|
|
456
|
+
[[2]]
|
457
|
+
}
|
458
|
+
prepare_fetch(2, origin_obj)
|
459
|
+
@storage.should_receive(:restore_collection).and_return { |*args|
|
460
|
+
[]
|
461
|
+
}
|
462
|
+
@storage.should_receive(:store).and_return { |id, dump, name, prefetch, klass| }
|
463
|
+
@storage.should_receive(:ensure_object_connections).and_return { }
|
464
|
+
@storage.should_receive(:delete_persistable).and_return { |id| }
|
465
|
+
@marshal.should_receive(:dump).and_return { |ob| "foo"}
|
466
|
+
@cache.delete(delete_item)
|
467
|
+
assert_equal(1, @cache.fetched.size)
|
468
|
+
assert_equal(nil, origin_obj.odba_connection)
|
469
|
+
end
|
470
|
+
def prepare_delete(mock, name, id)
|
471
|
+
mock.should_receive(:odba_id).and_return { id }
|
472
|
+
mock.should_receive(:odba_name).and_return { name }
|
473
|
+
mock.should_receive(:odba_notify_observers).and_return { |key, id1, id2|
|
474
|
+
assert_equal(:delete, key)
|
475
|
+
}
|
476
|
+
@storage.should_receive(:retrieve_connected_objects).and_return { |id|
|
477
|
+
[]
|
478
|
+
}
|
479
|
+
mock.should_receive(:origin_class?).and_return { true }
|
480
|
+
mock.should_receive(:odba_id).and_return { id }
|
481
|
+
@storage.should_receive(:delete_persistable).and_return { |id_arg|
|
482
|
+
assert_equal(id, id_arg)
|
483
|
+
}
|
484
|
+
@storage.should_receive(:delete_index_element).and_return { }
|
485
|
+
end
|
486
|
+
def prepare_bulk_restore(rows)
|
487
|
+
rows.each { |odba_mock|
|
488
|
+
## according to recent changes, objects are extended with
|
489
|
+
# ODBA::Persistable after loading - this enables ad-hoc storing
|
490
|
+
# but messes up loads of tests
|
491
|
+
@marshal.should_receive(:load).and_return { |dump|
|
492
|
+
odba_mock.instance_variable_set('@odba_id', 2)
|
493
|
+
odba_mock.instance_variable_set('@odba_prefetch', true)
|
494
|
+
odba_mock
|
495
|
+
}
|
496
|
+
@storage.should_receive(:restore_collection).and_return {|*args|
|
497
|
+
[]
|
498
|
+
}
|
499
|
+
}
|
500
|
+
end
|
501
|
+
def test_retrieve_from_index
|
502
|
+
foo = flexmock
|
503
|
+
index = flexmock("bar_index")
|
504
|
+
@cache.indices["index_name"] = index
|
505
|
+
index.should_receive(:fetch_ids).and_return { |search_term, meta|
|
506
|
+
assert_equal('search term', search_term)
|
507
|
+
assert_nil(meta)
|
508
|
+
[2]
|
509
|
+
}
|
510
|
+
@storage.should_receive(:bulk_restore).and_return {
|
511
|
+
[[2, 'dump']]
|
512
|
+
}
|
513
|
+
prepare_bulk_restore([foo])
|
514
|
+
@cache.retrieve_from_index("index_name", "search term")
|
515
|
+
end
|
516
|
+
def test_update_indices
|
517
|
+
index = flexmock("index")
|
518
|
+
bar = flexmock("bar")
|
519
|
+
bar.should_receive(:odba_indexable?).and_return { true }
|
520
|
+
@cache.indices = {
|
521
|
+
"foo" => index
|
522
|
+
}
|
523
|
+
index.should_receive(:update).and_return { |obj|
|
524
|
+
assert_equal(bar, obj)
|
525
|
+
}
|
526
|
+
@cache.update_indices(bar)
|
527
|
+
end
|
528
|
+
def test_delete_index_element
|
529
|
+
foo = flexmock("foo")
|
530
|
+
bar = flexmock("bar")
|
531
|
+
@cache.indices = {
|
532
|
+
"foo" => foo
|
533
|
+
}
|
534
|
+
foo.should_receive(:delete).with(bar).times(1).and_return {
|
535
|
+
assert(true)
|
536
|
+
}
|
537
|
+
@cache.delete_index_element(bar)
|
538
|
+
end
|
539
|
+
def test_drop_index
|
540
|
+
@storage.should_receive(:transaction).and_return { |block| block.call }
|
541
|
+
@storage.should_receive(:drop_index).and_return { |index_name|
|
542
|
+
assert_equal("foo_index", index_name)
|
543
|
+
}
|
544
|
+
index = flexmock("index")
|
545
|
+
index.should_receive(:delete).with(index)
|
546
|
+
prepare_delete(index, "foo", 2)
|
547
|
+
@cache.indices.store("foo_index", index)
|
548
|
+
@cache.drop_index("foo_index")
|
549
|
+
end
|
550
|
+
def test_drop_indices
|
551
|
+
@storage.should_receive(:transaction).and_return { |block| block.call}
|
552
|
+
@storage.should_receive(:drop_index).and_return {|index_name|
|
553
|
+
assert_equal("foo_index", index_name)
|
554
|
+
}
|
555
|
+
index = flexmock("index")
|
556
|
+
index.should_receive(:delete).with(index)
|
557
|
+
prepare_delete(index, "foo", 2)
|
558
|
+
@cache.indices.store("foo_index", index)
|
559
|
+
@cache.drop_indices
|
560
|
+
end
|
561
|
+
def test_fetch_collection_element
|
562
|
+
key_dump = Marshal.dump('foo')
|
563
|
+
@storage.should_receive(:collection_fetch).and_return { |odba_id, key|
|
564
|
+
assert_equal(12, odba_id)
|
565
|
+
assert_equal(key_dump, key)
|
566
|
+
'val_dump'
|
567
|
+
}
|
568
|
+
@marshal.should_receive(:dump).and_return { |key|
|
569
|
+
assert_equal('foo', key)
|
570
|
+
key_dump
|
571
|
+
}
|
572
|
+
@marshal.should_receive(:load).and_return { |dump|
|
573
|
+
assert_equal('val_dump', dump)
|
574
|
+
'val'
|
575
|
+
}
|
576
|
+
res = @cache.fetch_collection_element(12, 'foo')
|
577
|
+
assert_equal('val', res)
|
578
|
+
end
|
579
|
+
def test_transaction
|
580
|
+
o1 = Object.new
|
581
|
+
o1.instance_variable_set('@odba_id', 1)
|
582
|
+
o2 = Object.new
|
583
|
+
o3 = Object.new
|
584
|
+
o1.extend(ODBA::Persistable)
|
585
|
+
o2.extend(ODBA::Persistable)
|
586
|
+
o2.odba_name = 'name2'
|
587
|
+
o3.extend(ODBA::Persistable)
|
588
|
+
o4 = o1.odba_dup
|
589
|
+
@storage.should_receive(:transaction).and_return { |block| block.call }
|
590
|
+
|
591
|
+
## store o1
|
592
|
+
@marshal.should_receive(:dump).times(3).and_return { |obj|
|
593
|
+
"dump%i" % obj.odba_id
|
594
|
+
}
|
595
|
+
next_id = 1
|
596
|
+
@storage.should_receive(:next_id).and_return { next_id += 1 }
|
597
|
+
@storage.should_receive(:store).with(1,'dump1',nil,nil,Object)\
|
598
|
+
.times(1).and_return { assert(true) }
|
599
|
+
@storage.should_receive(:ensure_object_connections)\
|
600
|
+
.with(1,[2]).times(1).and_return { assert(true) }
|
601
|
+
|
602
|
+
## store o2
|
603
|
+
@storage.should_receive(:restore_collection).with(2)\
|
604
|
+
.times(1).and_return([])
|
605
|
+
@storage.should_receive(:store)\
|
606
|
+
.with(2,'dump2','name2',nil,Object)\
|
607
|
+
.times(1).and_return { assert(true) }
|
608
|
+
@storage.should_receive(:ensure_object_connections)\
|
609
|
+
.with(2,[3]).times(1).and_return { assert(true) }
|
610
|
+
|
611
|
+
## store o3 and raise
|
612
|
+
@storage.should_receive(:restore_collection).with(3)\
|
613
|
+
.times(1).and_return([])
|
614
|
+
## at this stage 1 and 2 (and 'name2') are stored:
|
615
|
+
@storage.should_receive(:store)\
|
616
|
+
.with(3,'dump3',nil,nil,Object)\
|
617
|
+
.times(1).and_return { raise "trigger rollback" }
|
618
|
+
|
619
|
+
## rollback
|
620
|
+
@storage.should_receive(:restore).with(2)\
|
621
|
+
.times(1).and_return(nil)
|
622
|
+
@storage.should_receive(:restore).with(1)\
|
623
|
+
.times(1).and_return('dump1')
|
624
|
+
@storage.should_receive(:restore_collection).with(1)\
|
625
|
+
.times(2).and_return([])
|
626
|
+
@marshal.should_receive(:load).with('dump1')\
|
627
|
+
.times(1).and_return(o4)
|
628
|
+
@cache.fetched.store(1, ODBA::CacheEntry.new(o1))
|
629
|
+
assert_raises(RuntimeError) {
|
630
|
+
ODBA.transaction {
|
631
|
+
o2.instance_variable_set('@other', o3)
|
632
|
+
o1.instance_variable_set('@other', o2)
|
633
|
+
o1.odba_store
|
634
|
+
}
|
635
|
+
}
|
636
|
+
assert_equal(1, @cache.size)
|
637
|
+
assert_nil(o1.instance_variable_get('@other'))
|
638
|
+
end
|
639
|
+
def test_extent
|
640
|
+
o1 = flexmock('O1')
|
641
|
+
o1.should_receive(:odba_id).and_return(1)
|
642
|
+
o2 = flexmock('O2')
|
643
|
+
o2.should_receive(:odba_id).and_return(2)
|
644
|
+
clr = flexmock('Caller')
|
645
|
+
@storage.should_receive(:extent_ids).and_return([1,2])
|
646
|
+
@storage.should_receive(:restore_collection).and_return([])
|
647
|
+
@storage.should_receive(:bulk_restore).with([1,2])\
|
648
|
+
.and_return([[1, 'dump1'],[2,'dump2']])
|
649
|
+
@marshal.should_receive(:load).with('dump1')\
|
650
|
+
.times(1).and_return(o1)
|
651
|
+
@marshal.should_receive(:load).with('dump2')\
|
652
|
+
.times(1).and_return(o2)
|
653
|
+
assert_equal([o1, o2], @cache.extent(ODBAContainer, clr))
|
654
|
+
end
|
655
|
+
def test_fetch_collection
|
656
|
+
obj = flexmock('Object')
|
657
|
+
obj.should_receive(:odba_id).and_return(1)
|
658
|
+
restored = flexmock('Restored')
|
659
|
+
restored.should_receive(:odba_id).and_return(7)
|
660
|
+
i1 = flexmock('Item1')
|
661
|
+
i2 = flexmock('Item2')
|
662
|
+
i1.should_receive(:is_a?).with(Stub).and_return(false)
|
663
|
+
i2.should_receive(:is_a?).with(Stub).and_return(true)
|
664
|
+
i2.should_receive(:odba_id).and_return(7)
|
665
|
+
i2.should_receive(:odba_container=).with(obj).times(1)
|
666
|
+
@storage.should_receive(:restore_collection).with(1)\
|
667
|
+
.times(1).and_return([['keydump1','dump1'],['keydump2','dump2']])
|
668
|
+
@storage.should_receive(:restore_collection).with(7).times(1).and_return([])
|
669
|
+
@storage.should_receive(:bulk_restore).with([7]).and_return([[7,'inst']])
|
670
|
+
@marshal.should_receive(:load).with('keydump1').and_return(0)
|
671
|
+
@marshal.should_receive(:load).with('keydump2').and_return(1)
|
672
|
+
@marshal.should_receive(:load).with('dump1').and_return(i1)
|
673
|
+
@marshal.should_receive(:load).with('dump2').and_return(i2)
|
674
|
+
@marshal.should_receive(:load).with('inst').and_return(restored)
|
675
|
+
assert_equal([[0,i1],[1,i2]], @cache.fetch_collection(obj))
|
676
|
+
end
|
677
|
+
def test_include
|
678
|
+
assert(!@cache.include?(1))
|
679
|
+
@cache.fetched.store(1, 'foo')
|
680
|
+
assert(@cache.include?(1))
|
681
|
+
assert(!@cache.include?(2))
|
682
|
+
@cache.prefetched.store(2, 'bar')
|
683
|
+
assert(@cache.include?(2))
|
684
|
+
end
|
685
|
+
def test_index_keys
|
686
|
+
index = flexmock('Index')
|
687
|
+
@cache.indices.store('index', index)
|
688
|
+
index.should_receive(:keys).with(nil).times(1).and_return(['ABC'])
|
689
|
+
index.should_receive(:keys).with(2).times(1).and_return(['AB'])
|
690
|
+
assert_equal(['ABC'], @cache.index_keys('index'))
|
691
|
+
assert_equal(['AB'], @cache.index_keys('index', 2))
|
692
|
+
end
|
693
|
+
def test_setup
|
694
|
+
@storage.should_receive(:setup).times(1).and_return { assert(true)}
|
695
|
+
@storage.should_receive(:ensure_target_id_index)\
|
696
|
+
.with('index').times(1).and_return { assert(true)}
|
697
|
+
df1 = IndexDefinition.new
|
698
|
+
df1.index_name = 'deferred'
|
699
|
+
df2 = IndexDefinition.new
|
700
|
+
df2.index_name = 'index'
|
701
|
+
indices = flexmock('indices')
|
702
|
+
indices.should_receive(:each_key).and_return { |block|
|
703
|
+
block.call('index')
|
704
|
+
}
|
705
|
+
indices.should_receive(:include?).with('index')\
|
706
|
+
.times(1).and_return(true)
|
707
|
+
indices.should_receive(:include?).with('deferred')\
|
708
|
+
.times(1).and_return(false)
|
709
|
+
indices.should_receive(:store).and_return { |key, val|
|
710
|
+
assert_equal('deferred', key)
|
711
|
+
assert_instance_of(Index, val)
|
712
|
+
}
|
713
|
+
indices.should_receive(:odba_store_unsaved).times(1)
|
714
|
+
@cache.instance_variable_set('@indices', indices)
|
715
|
+
@storage.should_receive(:transaction).and_return { |block|
|
716
|
+
block.call
|
717
|
+
}
|
718
|
+
@storage.should_receive(:create_index).with('deferred')\
|
719
|
+
.times(1).and_return { assert(true) }
|
720
|
+
@cache.instance_variable_set('@deferred_indices', [df1, df2])
|
721
|
+
@cache.setup
|
722
|
+
@cache.instance_variable_set('@indices', {})
|
723
|
+
end
|
724
|
+
end
|
725
|
+
end
|