data_objects 0.10.3 → 0.10.4.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/LICENSE +1 -1
  2. data/README.markdown +1 -1
  3. data/Rakefile +6 -32
  4. data/lib/data_objects/connection.rb +9 -6
  5. data/lib/data_objects/pooling.rb +1 -1
  6. data/lib/data_objects/spec/lib/pending_helpers.rb +11 -0
  7. data/lib/data_objects/spec/{helpers → lib}/ssl.rb +0 -0
  8. data/lib/data_objects/spec/setup.rb +5 -0
  9. data/lib/data_objects/spec/{command_spec.rb → shared/command_spec.rb} +54 -50
  10. data/lib/data_objects/spec/shared/connection_spec.rb +245 -0
  11. data/lib/data_objects/spec/{encoding_spec.rb → shared/encoding_spec.rb} +41 -43
  12. data/lib/data_objects/spec/shared/error/sql_error_spec.rb +30 -0
  13. data/lib/data_objects/spec/{quoting_spec.rb → shared/quoting_spec.rb} +0 -0
  14. data/lib/data_objects/spec/{reader_spec.rb → shared/reader_spec.rb} +31 -26
  15. data/lib/data_objects/spec/shared/result_spec.rb +79 -0
  16. data/lib/data_objects/spec/{typecast → shared/typecast}/array_spec.rb +4 -2
  17. data/lib/data_objects/spec/{typecast → shared/typecast}/bigdecimal_spec.rb +12 -8
  18. data/lib/data_objects/spec/{typecast → shared/typecast}/boolean_spec.rb +14 -10
  19. data/lib/data_objects/spec/{typecast → shared/typecast}/byte_array_spec.rb +6 -4
  20. data/lib/data_objects/spec/{typecast → shared/typecast}/class_spec.rb +5 -3
  21. data/lib/data_objects/spec/{typecast → shared/typecast}/date_spec.rb +13 -9
  22. data/lib/data_objects/spec/{typecast → shared/typecast}/datetime_spec.rb +14 -11
  23. data/lib/data_objects/spec/{typecast → shared/typecast}/float_spec.rb +17 -13
  24. data/lib/data_objects/spec/{typecast → shared/typecast}/integer_spec.rb +7 -5
  25. data/lib/data_objects/spec/{typecast → shared/typecast}/ipaddr_spec.rb +0 -0
  26. data/lib/data_objects/spec/{typecast → shared/typecast}/nil_spec.rb +23 -17
  27. data/lib/data_objects/spec/{typecast → shared/typecast}/other_spec.rb +11 -9
  28. data/lib/data_objects/spec/{typecast → shared/typecast}/range_spec.rb +4 -2
  29. data/lib/data_objects/spec/{typecast → shared/typecast}/string_spec.rb +10 -8
  30. data/lib/data_objects/spec/{typecast → shared/typecast}/time_spec.rb +44 -6
  31. data/lib/data_objects/transaction.rb +9 -0
  32. data/lib/data_objects/uri.rb +62 -4
  33. data/lib/data_objects/version.rb +1 -1
  34. data/spec/command_spec.rb +2 -2
  35. data/spec/connection_spec.rb +45 -25
  36. data/spec/pooling_spec.rb +9 -9
  37. data/spec/reader_spec.rb +11 -12
  38. data/spec/result_spec.rb +13 -11
  39. data/spec/spec_helper.rb +1 -16
  40. data/spec/transaction_spec.rb +9 -11
  41. data/spec/uri_spec.rb +35 -27
  42. data/tasks/spec.rake +8 -17
  43. metadata +40 -56
  44. data/lib/data_objects/spec/bacon.rb +0 -9
  45. data/lib/data_objects/spec/connection_spec.rb +0 -217
  46. data/lib/data_objects/spec/error/sql_error_spec.rb +0 -19
  47. data/lib/data_objects/spec/helpers/immediate_red_green_output.rb +0 -59
  48. data/lib/data_objects/spec/helpers/pending.rb +0 -22
  49. data/lib/data_objects/spec/result_spec.rb +0 -79
  50. data/tasks/metrics.rake +0 -36
@@ -10,20 +10,22 @@ class ::CustomTextType
10
10
 
11
11
  end
12
12
 
13
- shared 'supporting other (unknown) type' do
13
+ shared_examples_for 'supporting other (unknown) type' do
14
14
 
15
- setup_test_environment
16
-
17
- before do
18
- @connection = DataObjects::Connection.new(CONFIG.uri)
19
- end
20
-
21
- after do
22
- @connection.close
15
+ before :all do
16
+ setup_test_environment
23
17
  end
24
18
 
25
19
  describe 'writing an object of unknown type' do
26
20
 
21
+ before do
22
+ @connection = DataObjects::Connection.new(CONFIG.uri)
23
+ end
24
+
25
+ after do
26
+ @connection.close
27
+ end
28
+
27
29
  before do
28
30
  @command = @connection.create_command("SELECT ad_description FROM widgets WHERE ad_description = ?")
29
31
  @command.set_types(::CustomTextType)
@@ -1,6 +1,8 @@
1
- shared 'supporting Range' do
1
+ shared_examples_for 'supporting Range' do
2
2
 
3
- setup_test_environment
3
+ before :all do
4
+ setup_test_environment
5
+ end
4
6
 
5
7
  before do
6
8
  @connection = DataObjects::Connection.new(CONFIG.uri)
@@ -1,8 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
- shared 'supporting String' do
3
+ shared_examples_for 'supporting String' do
4
4
 
5
- setup_test_environment
5
+ before :all do
6
+ setup_test_environment
7
+ end
6
8
 
7
9
  before do
8
10
  @connection = DataObjects::Connection.new(CONFIG.uri)
@@ -27,7 +29,7 @@ shared 'supporting String' do
27
29
  end
28
30
 
29
31
  it 'should return the correctly typed result' do
30
- @values.first.should.be.kind_of(String)
32
+ @values.first.should be_kind_of(String)
31
33
  end
32
34
 
33
35
  it 'should return the correct result' do
@@ -51,7 +53,7 @@ shared 'supporting String' do
51
53
  end
52
54
 
53
55
  it 'should return the correctly typed result' do
54
- @values.first.should.be.kind_of(String)
56
+ @values.first.should be_kind_of(String)
55
57
  end
56
58
 
57
59
  it 'should return the correct result' do
@@ -76,7 +78,7 @@ shared 'supporting String' do
76
78
 
77
79
  it 'should return the correct entry' do
78
80
  # Some of the drivers starts autoincrementation from 0 not 1
79
- @values.first.should.satisfy { |val| val == 1 or val == 2 }
81
+ @values.first.should satisfy { |val| val == 1 or val == 2 }
80
82
  end
81
83
 
82
84
  end
@@ -94,7 +96,7 @@ shared 'supporting String' do
94
96
 
95
97
  it 'should write a multibyte String' do
96
98
  @command = @connection.create_command('INSERT INTO users (name) VALUES(?)')
97
- should.not.raise(DataObjects::DataError) { @command.execute_non_query(name) }
99
+ expect { @command.execute_non_query(name) }.not_to raise_error(DataObjects::DataError)
98
100
  end
99
101
 
100
102
  it 'should read back the multibyte String' do
@@ -107,7 +109,7 @@ shared 'supporting String' do
107
109
 
108
110
  it 'should write a multibyte String (without query parameters)' do
109
111
  @command = @connection.create_command("INSERT INTO users (name) VALUES(#{@n}\'#{name}\')")
110
- should.not.raise(DataObjects::DataError) { @command.execute_non_query }
112
+ expect { @command.execute_non_query }.not_to raise_error(DataObjects::DataError)
111
113
  end
112
114
 
113
115
  it 'should read back the multibyte String (without query parameters)' do
@@ -137,7 +139,7 @@ shared 'supporting String' do
137
139
 
138
140
  it 'should return the correct entry' do
139
141
  # Some of the drivers starts autoincrementation from 0 not 1
140
- @values.first.should.satisfy { |val| val == 1 or val == 2 }
142
+ @values.first.should satisfy { |val| val == 1 or val == 2 }
141
143
  end
142
144
 
143
145
  end
@@ -1,6 +1,8 @@
1
- shared 'supporting Time' do
1
+ shared_examples_for 'supporting Time' do
2
2
 
3
- setup_test_environment
3
+ before :all do
4
+ setup_test_environment
5
+ end
4
6
 
5
7
  before do
6
8
  @connection = DataObjects::Connection.new(CONFIG.uri)
@@ -27,7 +29,7 @@ shared 'supporting Time' do
27
29
  end
28
30
 
29
31
  it 'should return the correctly typed result' do
30
- @values.first.should.be.kind_of(Time)
32
+ @values.first.should be_kind_of(Time)
31
33
  end
32
34
 
33
35
  it 'should return the correct result' do
@@ -51,11 +53,11 @@ shared 'supporting Time' do
51
53
  end
52
54
 
53
55
  it 'should return a nil class' do
54
- @values.first.should.be.kind_of(NilClass)
56
+ @values.first.should be_kind_of(NilClass)
55
57
  end
56
58
 
57
59
  it 'should return nil' do
58
- @values.first.should.be.nil
60
+ @values.first.should be_nil
59
61
  end
60
62
 
61
63
  end
@@ -76,9 +78,45 @@ shared 'supporting Time' do
76
78
 
77
79
  it 'should return the correct entry' do
78
80
  #Some of the drivers starts autoincrementation from 0 not 1
79
- @values.first.should.satisfy { |val| val == 1 or val == 0 }
81
+ @values.first.should satisfy { |val| val == 1 or val == 0 }
80
82
  end
81
83
 
82
84
  end
83
85
 
84
86
  end
87
+
88
+ shared_examples_for 'supporting sub second Time' do
89
+
90
+ before :all do
91
+ setup_test_environment
92
+ end
93
+
94
+ before do
95
+ @connection = DataObjects::Connection.new(CONFIG.uri)
96
+ @connection.create_command(<<-EOF).execute_non_query(Time.parse('2010-12-15 14:32:08.49377-08'))
97
+ update widgets set release_timestamp = ? where id = 1
98
+ EOF
99
+ @connection.create_command(<<-EOF).execute_non_query(Time.parse('2010-12-15 14:32:28.942694-08'))
100
+ update widgets set release_timestamp = ? where id = 2
101
+ EOF
102
+
103
+ @command = @connection.create_command("SELECT release_timestamp FROM widgets WHERE id < ? order by id")
104
+ @command.set_types(Time)
105
+ @reader = @command.execute_reader(3)
106
+ @reader.next!
107
+ @values = @reader.values
108
+ end
109
+
110
+ after do
111
+ @connection.close
112
+ end
113
+
114
+ it 'should handle variable subsecond lengths properly' do
115
+ @values.first.should == Time.at(1292452328, 493770)
116
+
117
+ @reader.next!
118
+ @values = @reader.values
119
+ @values.first.should == Time.at(1292452348, 942694)
120
+ end
121
+
122
+ end
@@ -72,6 +72,15 @@ module DataObjects
72
72
  DataObjects::SavePoint.new(uri, connection)
73
73
  end
74
74
 
75
+ # SavePoints can only occur in the context of a Transaction, thus they
76
+ # re-use TXN's connection (which was acquired from the connection pool
77
+ # legitimately via DO::Connection.new). We no-op #close in SP because
78
+ # calling DO::Connection#close will release the connection back into the
79
+ # pool (before the top-level Transaction might be done with it).
80
+ def close
81
+ # no-op
82
+ end
83
+
75
84
  def begin
76
85
  run %{SAVEPOINT "#{@id}"}
77
86
  end
@@ -13,18 +13,75 @@ module DataObjects
13
13
  # path:: The name or path to the database
14
14
  # query:: Parameters for the connection, for example encoding=utf8
15
15
  # fragment:: Not currently known to be in use, but available to the adapters
16
- class URI < Struct.new(:scheme, :user, :password, :host, :port, :path, :query, :fragment)
16
+ class URI
17
+ attr_reader :scheme, :subscheme, :user, :password, :host, :port, :path, :query, :fragment
18
+
17
19
  # Make a DataObjects::URI object by parsing a string. Simply delegates to Addressable::URI::parse.
18
20
  def self.parse(uri)
19
21
  return uri if uri.kind_of?(self)
20
- uri = Addressable::URI::parse(uri) unless uri.kind_of?(Addressable::URI)
21
- self.new(uri.scheme, uri.user, uri.password, uri.host, uri.port, uri.path, uri.query_values, uri.fragment)
22
+
23
+ if uri.kind_of?(Addressable::URI)
24
+ scheme = uri.scheme
25
+ else
26
+ if uri[0,4] == 'jdbc'
27
+ scheme = uri[0,4]
28
+ uri = Addressable::URI::parse(uri[5, uri.length])
29
+ subscheme = uri.scheme
30
+ else
31
+ uri = Addressable::URI::parse(uri)
32
+ scheme = uri.scheme
33
+ subscheme = nil
34
+ end
35
+ end
36
+
37
+ self.new(
38
+ :scheme => scheme,
39
+ :subscheme => subscheme,
40
+ :user => uri.user,
41
+ :password => uri.password,
42
+ :host => uri.host,
43
+ :port => uri.port,
44
+ :path => uri.path,
45
+ :query => uri.query_values,
46
+ :fragment => uri.fragment,
47
+ :relative => !!uri.to_s.index('//') # basic (naive) check for relativity / opaqueness
48
+ )
49
+ end
50
+
51
+ def initialize(*args)
52
+ if (component = args.first).kind_of?(Hash)
53
+ @scheme = component[:scheme]
54
+ @subscheme = component[:subscheme]
55
+ @user = component[:user]
56
+ @password = component[:password]
57
+ @host = component[:host]
58
+ @port = component[:port]
59
+ @path = component[:path]
60
+ @query = component[:query]
61
+ @fragment = component[:fragment]
62
+ @relative = component[:relative]
63
+ elsif args.size > 1
64
+ warn "DataObjects::URI.new with arguments is deprecated, use a Hash of URI components (#{caller.first})"
65
+ @scheme, @user, @password, @host, @port, @path, @query, @fragment = *args
66
+ else
67
+ raise ArgumentError, "argument should be a Hash of URI components, was: #{args.inspect}"
68
+ end
69
+ end
70
+
71
+ def opaque?
72
+ !@relative
73
+ end
74
+
75
+ def relative?
76
+ @relative
22
77
  end
23
78
 
24
79
  # Display this URI object as a string
25
80
  def to_s
26
81
  string = ""
27
- string << "#{scheme}://" if scheme
82
+ string << "#{scheme}:" if scheme
83
+ string << "#{subscheme}:" if subscheme
84
+ string << '//' if relative?
28
85
  if user
29
86
  string << "#{user}"
30
87
  string << ":#{password}" if password
@@ -51,5 +108,6 @@ module DataObjects
51
108
  def hash
52
109
  to_s.hash
53
110
  end
111
+
54
112
  end
55
113
  end
@@ -1,3 +1,3 @@
1
1
  module DataObjects
2
- VERSION = '0.10.3'
2
+ VERSION = '0.10.4.rc1'
3
3
  end
data/spec/command_spec.rb CHANGED
@@ -12,13 +12,13 @@ describe DataObjects::Command do
12
12
 
13
13
  %w{connection execute_non_query execute_reader set_types}.each do |meth|
14
14
  it "should respond to ##{meth}" do
15
- @command.should.respond_to(meth.intern)
15
+ @command.should respond_to(meth.intern)
16
16
  end
17
17
  end
18
18
 
19
19
  %w{execute_non_query execute_reader set_types}.each do |meth|
20
20
  it "should raise NotImplementedError on ##{meth}" do
21
- should.raise(NotImplementedError) { @command.send(meth.intern, nil) }
21
+ lambda { @command.send(meth.intern, nil) }.should raise_error(NotImplementedError)
22
22
  end
23
23
  end
24
24
 
@@ -1,41 +1,61 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+ require 'stringio'
2
3
 
3
4
  describe DataObjects::Connection do
4
- before do
5
- @connection = DataObjects::Connection.new('mock://localhost')
6
- end
5
+ subject { connection }
7
6
 
8
- after do
9
- @connection.release
10
- end
7
+ let(:connection) { described_class.new(uri) }
11
8
 
12
- %w{dispose create_command}.each do |meth|
13
- it "should respond to ##{meth}" do
14
- @connection.should.respond_to(meth.intern)
15
- end
16
- end
9
+ after { connection.close }
10
+
11
+ context 'should define a standard API' do
12
+ let(:uri) { 'mock://localhost' }
13
+
14
+ it { should respond_to(:dispose) }
15
+ it { should respond_to(:create_command) }
17
16
 
18
- it "should have #to_s that returns the connection uri string" do
19
- @connection.to_s.should == 'mock://localhost'
17
+ its(:to_s) { should == 'mock://localhost' }
20
18
  end
21
19
 
22
- describe "initialization" do
20
+ describe 'initialization' do
23
21
 
24
- it "should accept a connection uri as a Addressable::URI" do
25
- c = DataObjects::Connection.new(Addressable::URI::parse('mock://localhost/database'))
26
- # relying on the fact that mock connection sets @uri
27
- c.to_s.should == 'mock://localhost/database'
22
+ context 'with a connection uri as a Addressable::URI' do
23
+ let(:uri) { Addressable::URI::parse('mock://localhost/database') }
24
+
25
+ it { should be_kind_of(DataObjects::Mock::Connection) }
26
+ it { should be_kind_of(DataObjects::Pooling) }
27
+
28
+ its(:to_s) { should == 'mock://localhost/database' }
28
29
  end
29
30
 
30
- it "should return the Connection specified by the scheme" do
31
- c = DataObjects::Connection.new(Addressable::URI.parse('mock://localhost/database'))
32
- c.should.be.kind_of(DataObjects::Mock::Connection)
33
- c.should.be.kind_of(DataObjects::Pooling)
31
+ [
32
+ 'java:comp/env/jdbc/DataSource?driver=mock2',
33
+ Addressable::URI.parse('java:comp/env/jdbc/DataSource?driver=mock2')
34
+ ].each do |jndi_url|
35
+ context 'should return the Connection specified by the scheme without pooling' do
36
+ let(:uri) { jndi_url }
37
+
38
+ it { should be_kind_of(DataObjects::Mock2::Connection) }
39
+ it { should_not be_kind_of(DataObjects::Pooling) }
34
40
  end
41
+ end
35
42
 
36
- it "should return the Connection specified by the scheme without pooling" do
37
- c = DataObjects::Connection.new(Addressable::URI.parse('java://jdbc/database?scheme=mock2'))
38
- c.should.not.be.kind_of(DataObjects::Pooling)
43
+ %w(
44
+ jdbc:mock:memory::
45
+ jdbc:mock://host/database
46
+ jdbc:mock://host:6969/database
47
+ jdbc:mock:thin:host:database
48
+ jdbc:mock:thin:@host.domain.com:6969:database
49
+ jdbc:mock://server:6969/database;property=value;
50
+ jdbc:mock://[1111:2222:3333:4444:5555:6666:7777:8888]/database
51
+ ).each do |jdbc_url|
52
+ context "with JDBC URL '#{jdbc_url}'" do
53
+ let(:uri) { jdbc_url }
54
+
55
+ it { should be_kind_of(DataObjects::Mock::Connection) }
56
+ end
39
57
  end
58
+
40
59
  end
60
+
41
61
  end
data/spec/pooling_spec.rb CHANGED
@@ -64,7 +64,7 @@ describe "DataObjects::Pooling" do
64
64
  end
65
65
  end
66
66
 
67
- after do
67
+ after :each do
68
68
  DataObjects::Pooling.lock.synchronize do
69
69
  DataObjects::Pooling.pools.each do |pool|
70
70
  pool.lock.synchronize do
@@ -95,24 +95,24 @@ describe "DataObjects::Pooling" do
95
95
  it "should track the initialized pools" do
96
96
  bob = Person.new('Bob') # Ensure the pool is "primed"
97
97
  bob.name.should == 'Bob'
98
- bob.instance_variable_get(:@__pool).should.not.be.nil
98
+ bob.instance_variable_get(:@__pool).should_not be_nil
99
99
  Person.__pools.size.should == 1
100
100
  bob.release
101
101
  Person.__pools.size.should == 1
102
102
 
103
- DataObjects::Pooling::pools.should.not.be.empty
103
+ DataObjects::Pooling::pools.should_not be_empty
104
104
 
105
105
  sleep(1.2)
106
106
 
107
107
  # NOTE: This assertion is commented out, as our MockConnection objects are
108
108
  # currently in the pool.
109
- DataObjects::Pooling::pools.should.be.empty
110
- bob.name.should == nil
109
+ # DataObjects::Pooling::pools.should be_empty
110
+ bob.name.should be_nil
111
111
  end
112
112
 
113
113
  it "should allow you to overwrite Class#new" do
114
114
  bob = Overwriter.new('Bob')
115
- bob.should.be.overwritten
115
+ bob.should be_overwritten
116
116
  bob.release
117
117
  end
118
118
 
@@ -127,7 +127,7 @@ describe "DataObjects::Pooling" do
127
127
  bob = Person.new('Bob')
128
128
  t1.join
129
129
  bob.release
130
- end.should.not.raise(DataObjects::Pooling::InvalidResourceError)
130
+ end.should_not raise_error(DataObjects::Pooling::InvalidResourceError)
131
131
  end
132
132
 
133
133
  it "should allow you to flush a pool" do
@@ -141,7 +141,7 @@ describe "DataObjects::Pooling" do
141
141
  Overwriter.__pools[['Bob']].flush!
142
142
  Overwriter.__pools[['Bob']].size.should == 0
143
143
 
144
- bob.name.should.be.nil
144
+ bob.name.should be_nil
145
145
  end
146
146
 
147
147
  it "should wake up the scavenger thread when exiting" do
@@ -149,7 +149,7 @@ describe "DataObjects::Pooling" do
149
149
  bob.release
150
150
  DataObjects.exiting = true
151
151
  sleep(0.1)
152
- DataObjects::Pooling.scavenger?.should.be.false
152
+ DataObjects::Pooling.scavenger?.should be_false
153
153
  end
154
154
 
155
155
  it "should be able to detach an instance from the pool" do