odba 1.1.9 → 1.2.1

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/devenv.yml +34 -0
  3. data/.github/workflows/ruby.yml +8 -8
  4. data/.gitignore +15 -0
  5. data/History.md +131 -0
  6. data/README.md +77 -1
  7. data/Rakefile +3 -15
  8. data/devenv.lock +171 -0
  9. data/devenv.nix +66 -0
  10. data/devenv.yaml +16 -0
  11. data/lib/odba/cache.rb +395 -344
  12. data/lib/odba/cache_entry.rb +42 -31
  13. data/lib/odba/connection_pool.rb +99 -72
  14. data/lib/odba/drbwrapper.rb +26 -18
  15. data/lib/odba/id_server.rb +20 -20
  16. data/lib/odba/index.rb +249 -215
  17. data/lib/odba/index_definition.rb +17 -17
  18. data/lib/odba/marshal.rb +15 -14
  19. data/lib/odba/odba.rb +40 -32
  20. data/lib/odba/odba_error.rb +4 -2
  21. data/lib/odba/persistable.rb +460 -414
  22. data/lib/odba/storage.rb +328 -277
  23. data/lib/odba/stub.rb +166 -153
  24. data/lib/odba/version.rb +1 -1
  25. data/lib/odba.rb +9 -9
  26. data/odba.gemspec +8 -3
  27. data/test/example.rb +47 -0
  28. data/test/helper.rb +6 -0
  29. data/test/suite.rb +7 -0
  30. data/test/test_array.rb +38 -33
  31. data/test/test_cache.rb +666 -622
  32. data/test/test_cache_entry.rb +51 -71
  33. data/test/test_connection_pool.rb +70 -25
  34. data/test/test_drbwrapper.rb +31 -20
  35. data/test/test_hash.rb +98 -89
  36. data/test/test_id_server.rb +30 -32
  37. data/test/test_index.rb +191 -158
  38. data/test/test_marshal.rb +15 -25
  39. data/test/test_persistable.rb +378 -369
  40. data/test/test_storage.rb +510 -471
  41. data/test/test_stub.rb +147 -135
  42. metadata +63 -20
  43. data/Guide.txt +0 -36
  44. data/History.txt +0 -91
  45. data/Manifest.txt +0 -38
  46. data/install.rb +0 -1098
  47. data/lib/odba/18_19_loading_compatibility.rb +0 -77
@@ -1,113 +1,93 @@
1
1
  #!/usr/bin/env ruby
2
2
  # TestCacheEntry -- odba-- 29.04.2004 -- hwyss@ywesee.com mwalder@ywesee.com
3
-
4
- $: << File.dirname(__FILE__)
5
- $: << File.expand_path("../lib", File.dirname(__FILE__))
6
-
7
- require 'minitest/autorun'
8
- require 'flexmock/test_unit'
9
- require 'flexmock'
10
- require 'odba/cache_entry'
11
- require 'odba/odba'
12
- require 'odba/persistable'
3
+ require_relative "helper"
4
+ require "odba/cache_entry"
5
+ require "odba/odba"
6
+ require "odba/persistable"
13
7
 
14
8
  module ODBA
15
- class CacheEntry
16
- attr_accessor :accessed_by
17
- end
18
- class TestCacheEntry < Minitest::Test
9
+ class CacheEntry
10
+ attr_accessor :accessed_by
11
+ end
12
+
13
+ class TestCacheEntry < Test::Unit::TestCase
19
14
  include FlexMock::TestCase
20
- def setup
21
- @mock = flexmock
15
+ def setup
16
+ @mock = flexmock
22
17
  @mock.should_receive(:odba_add_observer)
23
- @mock.should_receive(:odba_observers).and_return { [] }
24
- @mock.should_receive(:odba_id).and_return { 123 }
25
- @cache_entry = ODBA::CacheEntry.new(@mock)
26
- ODBA.cache = flexmock("cache")
18
+ @mock.should_receive(:odba_observers).and_return { [] }
19
+ @mock.should_receive(:odba_id).and_return { 123 }
20
+ @cache_entry = ODBA::CacheEntry.new(@mock)
21
+ ODBA.cache = flexmock("cache")
27
22
  ODBA.cache.should_receive(:retire_age).and_return(0.9)
28
23
  ODBA.cache.should_receive(:destroy_age).and_return(0.9)
29
- end
24
+ end
25
+
30
26
  def teardown
31
27
  super
32
28
  end
33
- def test_retire_check
34
- @mock.should_receive(:odba_unsaved?).and_return { false }
35
- @mock.should_receive(:odba_unsaved?).and_return { false }
36
- assert_equal(false, @cache_entry.odba_old?(Time.now - 1))
37
- assert_equal(true, @cache_entry.odba_old?(Time.now + 1))
38
- end
39
- def test_retire
40
- obj_1 = Object.new
41
- obj_1.extend(Persistable)
42
- obj_1.instance_variable_set('@odba_id', 36)
43
- obj_2 = Object.new
44
- obj_2.extend(Persistable)
45
- obj_2.instance_variable_set('@odba_id', 34)
46
- ODBA.cache.should_receive(:include?).with(34).and_return(false)
47
- ODBA.cache.should_receive(:include?).with(35).and_return(false)
48
- ODBA.cache.should_receive(:include?).with(36).and_return(true)
49
- ODBA.cache.should_receive(:fetch).with(36).and_return(obj_1)
50
- hash = {}
51
- hash.instance_variable_set('@odba_id', 35)
52
- hash.instance_variable_set('@odba_persistent', true)
53
- @cache_entry.accessed_by = {
54
- obj_1.object_id => 36,
55
- obj_2.object_id => 34,
56
- hash.object_id => 35,
57
- }
58
- @cache_entry.odba_retire
59
- assert_equal({hash.object_id => 35}, @cache_entry.accessed_by)
60
- end
61
- def test_odba_add_reference
62
- mock = flexmock
63
- @cache_entry.odba_add_reference(mock)
29
+
30
+ def test_retire_check
31
+ @mock.should_receive(:odba_unsaved?).and_return { false }
32
+ @mock.should_receive(:odba_unsaved?).and_return { false }
33
+ assert_equal(false, @cache_entry.odba_old?(Time.now - 1))
34
+ assert_equal(true, @cache_entry.odba_old?(Time.now + 1))
35
+ end
36
+
37
+ def test_odba_add_reference
38
+ mock = flexmock
39
+ @cache_entry.odba_add_reference(mock)
64
40
  id = mock.object_id
65
41
  assert_equal({id => nil}, @cache_entry.accessed_by)
66
42
  mock2 = flexmock
67
43
  mock2.should_receive(:odba_id).and_return(123)
68
- @cache_entry.odba_add_reference(mock2)
44
+ @cache_entry.odba_add_reference(mock2)
69
45
  assert_equal({mock2.object_id => 123, id => nil}, @cache_entry.accessed_by)
70
- end
71
- def test_odba_id
72
- assert_equal(123, @cache_entry.odba_id)
73
- end
46
+ end
47
+
48
+ def test_odba_id
49
+ assert_equal(123, @cache_entry.odba_id)
50
+ end
51
+
74
52
  def test_odba_cut_connections
75
53
  ## transaction-rollback for unsaved items
76
- item1 = flexmock('Item1', :odba_id => 145)
77
- item2 = flexmock('Item2', :odba_id => 148)
54
+ item1 = flexmock("Item1", odba_id: 145)
55
+ item2 = flexmock("Item2", odba_id: 148)
78
56
  ODBA.cache.should_receive(:include?).with(145).and_return(false)
79
57
  ODBA.cache.should_receive(:include?).with(148).and_return(true)
80
58
  ODBA.cache.should_receive(:fetch).with(148).and_return(item2)
81
59
  @cache_entry.accessed_by.store(item1.object_id, 145)
82
60
  @cache_entry.accessed_by.store(item2.object_id, 148)
83
- item1.should_receive(:respond_to?).with(:odba_cut_connection)\
61
+ item1.should_receive(:respond_to?).with(:odba_cut_connection)
84
62
  .and_return(false)
85
- item2.should_receive(:respond_to?).with(:odba_cut_connection)\
63
+ item2.should_receive(:respond_to?).with(:odba_cut_connection)
86
64
  .and_return(true)
87
- item2.should_receive(:odba_cut_connection).with(@mock)\
65
+ item2.should_receive(:odba_cut_connection).with(@mock)
88
66
  .times(1).and_return { assert(true) }
89
67
  @cache_entry.odba_cut_connections!
90
68
  end
69
+
91
70
  def test_odba_replace
92
71
  ## transaction-rollback for saved items
93
72
  modified = Object.new
94
73
  modified.extend(ODBA::Persistable)
95
- modified.instance_variable_set('@data', 'foo')
96
- modified.instance_variable_set('@odba_id', 124)
74
+ modified.instance_variable_set(:@data, "foo")
75
+ modified.instance_variable_set(:@odba_id, 124)
97
76
  cache_entry = CacheEntry.new(modified)
98
77
 
99
78
  reloaded = modified.dup
100
79
 
101
- modified.instance_variable_set('@data', 'bar')
102
- assert_equal('bar', modified.instance_variable_get('@data'))
103
-
80
+ modified.instance_variable_set(:@data, "bar")
81
+ assert_equal("bar", modified.instance_variable_get(:@data))
82
+
104
83
  cache_entry.odba_replace!(reloaded)
105
- assert_equal('foo', modified.instance_variable_get('@data'))
84
+ assert_equal("foo", modified.instance_variable_get(:@data))
106
85
  end
86
+
107
87
  def test_odba_notify_observers
108
- @mock.should_receive(:odba_notify_observers).with(:foo, 2, 'bar')\
88
+ @mock.should_receive(:odba_notify_observers).with(:foo, 2, "bar")
109
89
  .and_return { assert(true) }
110
- @cache_entry.odba_notify_observers(:foo, 2, 'bar')
90
+ @cache_entry.odba_notify_observers(:foo, 2, "bar")
111
91
  end
112
- end
92
+ end
113
93
  end
@@ -1,12 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # TestConnectionPool -- odba -- 03.08.2005 -- hwyss@ywesee.com
3
-
4
- $: << File.expand_path('../lib', File.dirname(__FILE__))
5
-
6
- require 'minitest/autorun'
7
- require 'flexmock/test_unit'
8
- require 'flexmock'
9
- require 'odba/connection_pool'
3
+ require_relative "helper"
4
+ require "odba/connection_pool"
10
5
  ## connection_pool requires 'dbi', which unshifts the site_ruby dir
11
6
  # to the first position in $LOAD_PATH ( == $: ). As a result, files are
12
7
  # loaded from site_ruby if they are installed there, and thus ignored
@@ -14,64 +9,114 @@ require 'odba/connection_pool'
14
9
  # $:.shift
15
10
 
16
11
  module ODBA
17
- class TestConnectionPool < Minitest::Test
12
+ class TestConnectionPool < Test::Unit::TestCase
18
13
  include FlexMock::TestCase
19
14
  def test_survive_error
20
- flexstub(DBI).should_receive(:connect).times(10).and_return {
15
+ flexstub(DBI).should_receive(:connect).times(10).and_return {
21
16
  conn = FlexMock.new("Connection")
22
17
  conn.should_ignore_missing
23
18
  conn
24
19
  }
25
- pool = ConnectionPool.new()
20
+ pool = ConnectionPool.new
26
21
  pool.connections.each { |conn|
27
- conn.should_receive(:execute).and_return {
28
- raise DBI::InterfaceError.new
22
+ conn.should_receive(:execute).and_return {
23
+ raise DBI::InterfaceError.new
29
24
  ## after the first error is raised, ConnectionPool reconnects.
30
25
  }
31
26
  }
32
- pool.execute('statement')
27
+ pool.execute("statement")
33
28
  end
29
+
34
30
  def test_multiple_errors__give_up
35
- flexstub(DBI).should_receive(:connect).times(20).and_return {
31
+ flexstub(DBI).should_receive(:connect).times(20).and_return {
36
32
  conn = FlexMock.new("Connection")
37
- conn.should_receive(:execute).and_return {
38
- raise DBI::InterfaceError.new
33
+ conn.should_receive(:execute).and_return {
34
+ raise DBI::InterfaceError.new
39
35
  }
40
36
  conn
41
37
  }
42
- pool = ConnectionPool.new()
43
- assert_raises(DBI::InterfaceError) { pool.execute('statement') }
38
+ pool = ConnectionPool.new
39
+ assert_raises(DBI::InterfaceError) { pool.execute("statement") }
44
40
  end
41
+
42
+ # ydbd-pg reports a lost connection as DBI::ProgrammingError, which used
43
+ # to be excluded from the retry - so a database restart broke the pool
44
+ # for good.
45
+ def test_survive_lost_connection_reported_as_programming_error
46
+ flexstub(DBI).should_receive(:connect).times(10).and_return {
47
+ conn = FlexMock.new("Connection")
48
+ conn.should_ignore_missing
49
+ conn
50
+ }
51
+ pool = ConnectionPool.new
52
+ pool.connections.each { |conn|
53
+ conn.should_receive(:execute).and_return {
54
+ raise DBI::ProgrammingError.new("PQsocket() can't get socket descriptor")
55
+ }
56
+ }
57
+ ## after the first error is raised, ConnectionPool reconnects.
58
+ assert_nothing_raised { pool.execute("statement") }
59
+ end
60
+
61
+ def test_genuine_programming_error__give_up_at_once
62
+ flexstub(DBI).should_receive(:connect).times(5).and_return {
63
+ conn = FlexMock.new("Connection")
64
+ conn.should_receive(:execute).and_return {
65
+ raise DBI::ProgrammingError.new('syntax error at or near "selct"')
66
+ }
67
+ conn
68
+ }
69
+ pool = ConnectionPool.new
70
+ ## a broken statement must not be retried on a fresh connection
71
+ assert_raises(DBI::ProgrammingError) { pool.execute("selct 1") }
72
+ end
73
+
74
+ def test_retryable
75
+ flexstub(DBI).should_receive(:connect).times(5).and_return {
76
+ conn = FlexMock.new("Connection")
77
+ conn.should_ignore_missing
78
+ conn
79
+ }
80
+ pool = ConnectionPool.new
81
+ assert(pool.retryable?(DBI::InterfaceError.new("anything")))
82
+ assert(pool.retryable?(NoMethodError.new("undefined method")))
83
+ assert(pool.retryable?(DBI::ProgrammingError.new("PQsocket() can't get socket descriptor")))
84
+ assert(pool.retryable?(DBI::ProgrammingError.new("no connection to the server")))
85
+ assert(!pool.retryable?(DBI::ProgrammingError.new("relation does not exist")))
86
+ end
87
+
45
88
  def test_size
46
- flexstub(DBI).should_receive(:connect).times(5).and_return {
89
+ flexstub(DBI).should_receive(:connect).times(5).and_return {
47
90
  conn = FlexMock.new("Connection")
48
91
  conn.should_ignore_missing
49
92
  conn
50
93
  }
51
- pool = ConnectionPool.new()
94
+ pool = ConnectionPool.new
52
95
  assert_equal(5, pool.size)
53
96
  end
97
+
54
98
  def test_disconnect
55
- flexstub(DBI).should_receive(:connect).times(5).and_return {
99
+ flexstub(DBI).should_receive(:connect).times(5).and_return {
56
100
  conn = FlexMock.new("Connection")
57
101
  conn.should_ignore_missing
58
102
  conn
59
103
  }
60
- pool = ConnectionPool.new()
104
+ pool = ConnectionPool.new
61
105
  pool.connections.each { |conn|
62
106
  conn.should_receive(:disconnect).and_return { assert(true) }
63
107
  }
64
108
  pool.disconnect
65
109
  end
110
+
66
111
  def test_disconnect_error
67
- flexstub(DBI).should_receive(:connect).times(5).and_return {
112
+ flexstub(DBI).should_receive(:connect).times(5).and_return {
68
113
  conn = FlexMock.new("Connection")
69
- conn.should_receive(:disconnect).times(1).and_return {
114
+ conn.should_receive(:disconnect).times(1).and_return {
70
115
  raise DBI::InterfaceError.new
71
116
  }
72
117
  conn
73
118
  }
74
- pool = ConnectionPool.new()
119
+ pool = ConnectionPool.new
75
120
  pool.disconnect
76
121
  end
77
122
  end
@@ -1,15 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
  # TestDRbWrapper -- odba -- 13.06.2006 -- hwyss@ywesee.com
3
-
4
- $: << File.expand_path('../lib', File.dirname(__FILE__))
5
-
6
- require 'minitest/autorun'
7
- require 'flexmock/test_unit'
8
- require 'flexmock'
9
- require 'odba/drbwrapper'
3
+ require_relative "helper"
4
+ require "odba/drbwrapper"
10
5
 
11
6
  module ODBA
12
- class TestDRbWrapper < Minitest::Test
7
+ class TestDRbWrapper < Test::Unit::TestCase
13
8
  include FlexMock::TestCase
14
9
  def test_include
15
10
  obj = FlexMock.new
@@ -22,6 +17,7 @@ module ODBA
22
17
  assert_equal(true, arr.include?(DRbWrapper.new(obj)))
23
18
  assert_equal(false, arr.include?(DRbWrapper.new(obj2)))
24
19
  end
20
+
25
21
  def test_respond_to
26
22
  obj = FlexMock.new
27
23
  wrap = DRbWrapper.new(obj)
@@ -30,12 +26,13 @@ module ODBA
30
26
  assert_equal(true, wrap.respond_to?(:foo))
31
27
  assert_equal(false, wrap.respond_to?(:bar))
32
28
  end
29
+
33
30
  def test_method_missing
34
31
  obj = FlexMock.new
35
32
  wrap = DRbWrapper.new(obj)
36
- obj.should_receive(:foo).with(:arg1, :arg2).times(1).and_return('result_foo')
37
- assert_equal('result_foo', wrap.foo(:arg1, :arg2))
38
- pers = flexmock('Persistable')
33
+ obj.should_receive(:foo).with(:arg1, :arg2).times(1).and_return("result_foo")
34
+ assert_equal("result_foo", wrap.foo(:arg1, :arg2))
35
+ pers = flexmock("Persistable")
39
36
  pers.should_receive(:is_a?).with(Persistable).and_return(true)
40
37
  obj.should_receive(:bar).with(:arg1).times(1).and_return([pers])
41
38
  res = wrap.bar(:arg1)
@@ -53,50 +50,64 @@ module ODBA
53
50
  }
54
51
  end
55
52
  end
56
- class TestDRbIdConv < Minitest::Test
53
+
54
+ class TestDRbIdConv < Test::Unit::TestCase
57
55
  include FlexMock::TestCase
58
56
  def setup
59
- ODBA.cache = flexmock('cache')
57
+ ODBA.cache = flexmock("cache")
60
58
  @idconv = ODBA::DRbIdConv.new
61
59
  end
60
+
62
61
  def test_to_id
63
62
  ODBA.cache.should_receive(:store)
64
63
  o = Object.new
65
64
  assert_equal(o.object_id, @idconv.to_id(o))
66
65
  o.extend(ODBA::Persistable)
67
- o.instance_variable_set('@odba_id', 4)
66
+ o.instance_variable_set(:@odba_id, 4)
68
67
  o.odba_isolated_store
69
- assert_equal('4', @idconv.to_id(o))
68
+ assert_equal("4", @idconv.to_id(o))
70
69
  end
70
+
71
71
  def test_to_id__odba_unsaved
72
72
  o = Object.new
73
73
  o.extend(ODBA::Persistable)
74
74
  assert_equal(o.object_id, @idconv.to_id(o))
75
75
  assert_equal([@idconv], o.odba_observers)
76
76
  end
77
+
77
78
  def test_to_obj
78
79
  ODBA.cache.should_receive(:store)
79
80
  o = Object.new
80
- assert_equal(o, @idconv.to_obj(o.object_id))
81
+ ## drb >= 2.2 resolves only those ids it handed out itself: DRbIdConv
82
+ ## keeps a DRbObjectSpace WeakMap that to_id populates, and to_obj raises
83
+ ## RangeError for anything absent from it. Older drb looked the id up
84
+ ## with ObjectSpace._id2ref, which resolved any live object. Register the
85
+ ## object first, as real DRb traffic does - an id only reaches to_obj
86
+ ## after to_id produced it.
87
+ assert_equal(o, @idconv.to_obj(@idconv.to_id(o)))
81
88
  o.extend(ODBA::Persistable)
82
- o.instance_variable_set('@odba_id', 4)
89
+ o.instance_variable_set(:@odba_id, 4)
83
90
  o.odba_isolated_store
84
91
  ODBA.cache.should_receive(:fetch).with(4).times(1)
85
- @idconv.to_obj('4')
92
+ @idconv.to_obj("4")
86
93
  end
94
+
87
95
  def test_to_obj__error
88
- ODBA.cache.should_receive(:fetch).with(4).times(1).and_return {
96
+ ODBA.cache.should_receive(:fetch).with(4).times(1).and_return {
89
97
  raise "some error"
90
98
  }
91
- assert_raises(RangeError) { @idconv.to_obj('4') }
99
+ assert_raises(RangeError) { @idconv.to_obj("4") }
92
100
  end
101
+
93
102
  def test_odba_update
94
103
  id = Object.new.object_id
95
104
  @idconv.odba_update(:store, 4, id)
96
105
  ODBA.cache.should_receive(:fetch).with(4).times(1)
97
106
  @idconv.to_obj(id)
98
107
  @idconv.odba_update(:clean, 4, id)
108
+ return if RUBY_VERSION.to_f >= 3.3
99
109
  GC.start
110
+ assert_raises { @idconv.to_obj(id) }
100
111
  assert_raises(RangeError) { @idconv.to_obj(id) }
101
112
  end
102
113
  end