mysql2 0.3.21 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ #ifndef MYSQL2_STATEMENT_H
2
+ #define MYSQL2_STATEMENT_H
3
+
4
+ extern VALUE cMysql2Statement;
5
+
6
+ typedef struct {
7
+ VALUE client;
8
+ MYSQL_STMT *stmt;
9
+ int refcount;
10
+ } mysql_stmt_wrapper;
11
+
12
+ void init_mysql2_statement();
13
+ void decr_mysql2_stmt(mysql_stmt_wrapper *stmt_wrapper);
14
+
15
+ VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql);
16
+ VALUE rb_raise_mysql2_stmt_error2(MYSQL_STMT *stmt
17
+ #ifdef HAVE_RUBY_ENCODING_H
18
+ , rb_encoding* conn_enc
19
+ #endif
20
+ );
21
+
22
+ #endif
@@ -31,6 +31,8 @@ require 'mysql2/error'
31
31
  require 'mysql2/mysql2'
32
32
  require 'mysql2/result'
33
33
  require 'mysql2/client'
34
+ require 'mysql2/field'
35
+ require 'mysql2/statement'
34
36
 
35
37
  # = Mysql2
36
38
  #
@@ -61,22 +63,4 @@ module Mysql2::Util
61
63
  Hash[hash.map { |k,v| [k.to_sym, v] }]
62
64
  end
63
65
 
64
- #
65
- # In Mysql2::Client#query and Mysql2::Statement#execute,
66
- # Thread#handle_interrupt is used to prevent Timeout#timeout
67
- # from interrupting query execution.
68
- #
69
- # Timeout::ExitException was removed in Ruby 2.3.0, 2.2.3, and 2.1.8,
70
- # but is present in earlier 2.1.x and 2.2.x, so we provide a shim.
71
- #
72
- if Thread.respond_to?(:handle_interrupt)
73
- require 'timeout'
74
- # rubocop:disable Style/ConstantName
75
- TimeoutError = if defined?(::Timeout::ExitException)
76
- ::Timeout::ExitException
77
- else
78
- ::Timeout::Error
79
- end
80
- end
81
-
82
66
  end
@@ -44,6 +44,12 @@ module Mysql2
44
44
  ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
45
45
  ssl_set(*ssl_options) if ssl_options.any?
46
46
 
47
+ # SSL verify is a connection flag rather than a mysql_ssl_set option
48
+ flags = 0
49
+ flags |= @query_options[:connect_flags]
50
+ flags |= opts[:flags] if opts[:flags]
51
+ flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify] and ssl_options.any?
52
+
47
53
  if [:user,:pass,:hostname,:dbname,:db,:sock].any?{|k| @query_options.has_key?(k) }
48
54
  warn "============= WARNING FROM mysql2 ============="
49
55
  warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be deprecated at some point in the future."
@@ -57,7 +63,6 @@ module Mysql2
57
63
  port = opts[:port]
58
64
  database = opts[:database] || opts[:dbname] || opts[:db]
59
65
  socket = opts[:socket] || opts[:sock]
60
- flags = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]
61
66
 
62
67
  # Correct the data types before passing these values down to the C level
63
68
  user = user.to_s unless user.nil?
@@ -75,8 +80,10 @@ module Mysql2
75
80
  end
76
81
 
77
82
  if Thread.respond_to?(:handle_interrupt)
83
+ require 'timeout'
84
+
78
85
  def query(sql, options = {})
79
- Thread.handle_interrupt(::Mysql2::Util::TimeoutError => :never) do
86
+ Thread.handle_interrupt(::Timeout::ExitException => :never) do
80
87
  _query(sql, @query_options.merge(options))
81
88
  end
82
89
  end
@@ -2,8 +2,11 @@
2
2
 
3
3
  module Mysql2
4
4
  class Error < StandardError
5
- REPLACEMENT_CHAR = '?'
6
- ENCODE_OPTS = {:undef => :replace, :invalid => :replace, :replace => REPLACEMENT_CHAR}
5
+ ENCODE_OPTS = {
6
+ :undef => :replace,
7
+ :invalid => :replace,
8
+ :replace => '?'.freeze,
9
+ }.freeze
7
10
 
8
11
  attr_accessor :error_number
9
12
  attr_reader :sql_state
@@ -20,7 +23,7 @@ module Mysql2
20
23
  end
21
24
 
22
25
  def sql_state=(state)
23
- @sql_state = ''.respond_to?(:encode) ? state.encode(ENCODE_OPTS) : state
26
+ @sql_state = state.respond_to?(:encode) ? state.encode(ENCODE_OPTS) : state
24
27
  end
25
28
 
26
29
  private
@@ -53,27 +56,12 @@ module Mysql2
53
56
  #
54
57
  # Returns a valid UTF-8 string in Ruby 1.9+, the original string on Ruby 1.8
55
58
  def clean_message(message)
56
- return message if !message.respond_to?(:encoding)
59
+ return message unless message.respond_to?(:encode)
57
60
 
58
61
  if @server_version && @server_version > 50500
59
62
  message.encode(ENCODE_OPTS)
60
63
  else
61
- if message.respond_to? :scrub
62
- message.scrub(REPLACEMENT_CHAR).encode(ENCODE_OPTS)
63
- else
64
- # This is ugly as hell but Ruby 1.9 doesn't provide a way to clean a string
65
- # and retain it's valid UTF-8 characters, that I know of.
66
-
67
- new_message = "".force_encoding(Encoding::UTF_8)
68
- message.chars.each do |char|
69
- if char.valid_encoding?
70
- new_message << char
71
- else
72
- new_message << REPLACEMENT_CHAR
73
- end
74
- end
75
- new_message.encode(ENCODE_OPTS)
76
- end
64
+ message.encode(Encoding::UTF_8, ENCODE_OPTS)
77
65
  end
78
66
  end
79
67
  end
@@ -0,0 +1,4 @@
1
+ module Mysql2
2
+ class Field < Struct.new(:name, :type)
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Mysql2
2
+ class Statement
3
+ include Enumerable
4
+ end
5
+ end
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.3.21"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -4,7 +4,7 @@ begin
4
4
  require 'eventmachine'
5
5
  require 'mysql2/em'
6
6
 
7
- describe Mysql2::EM::Client do
7
+ RSpec.describe Mysql2::EM::Client do
8
8
  it "should support async queries" do
9
9
  results = []
10
10
  EM.run do
@@ -24,8 +24,8 @@ begin
24
24
  end
25
25
  end
26
26
 
27
- results[0].keys.should include("second_query")
28
- results[1].keys.should include("first_query")
27
+ expect(results[0].keys).to include("second_query")
28
+ expect(results[1].keys).to include("first_query")
29
29
  end
30
30
 
31
31
  it "should support queries in callbacks" do
@@ -44,12 +44,12 @@ begin
44
44
  end
45
45
  end
46
46
 
47
- results[0].keys.should include("first_query")
48
- results[1].keys.should include("second_query")
47
+ expect(results[0].keys).to include("first_query")
48
+ expect(results[1].keys).to include("second_query")
49
49
  end
50
50
 
51
51
  it "should not swallow exceptions raised in callbacks" do
52
- lambda {
52
+ expect {
53
53
  EM.run do
54
54
  client = Mysql2::EM::Client.new DatabaseCredentials['root']
55
55
  defer = client.query "SELECT sleep(0.1) as first_query"
@@ -63,13 +63,13 @@ begin
63
63
  EM.stop_event_loop
64
64
  end
65
65
  end
66
- }.should raise_error
66
+ }.to raise_error('some error')
67
67
  end
68
68
 
69
69
  context 'when an exception is raised by the client' do
70
70
  let(:client) { Mysql2::EM::Client.new DatabaseCredentials['root'] }
71
71
  let(:error) { StandardError.new('some error') }
72
- before { client.stub(:async_result).and_raise(error) }
72
+ before { allow(client).to receive(:async_result).and_raise(error) }
73
73
 
74
74
  it "should swallow exceptions raised in by the client" do
75
75
  errors = []
@@ -85,7 +85,7 @@ begin
85
85
  EM.stop_event_loop
86
86
  end
87
87
  end
88
- errors.should == [error]
88
+ expect(errors).to eq([error])
89
89
  end
90
90
 
91
91
  it "should fail the deferrable" do
@@ -105,7 +105,7 @@ begin
105
105
  end
106
106
  end
107
107
  end
108
- callbacks_run.should == [:errback]
108
+ expect(callbacks_run).to eq([:errback])
109
109
  end
110
110
  end
111
111
 
@@ -121,10 +121,10 @@ begin
121
121
  callbacks_run << :errback
122
122
  end
123
123
  EM.add_timer(0.1) do
124
- callbacks_run.should == [:callback]
125
- lambda {
124
+ expect(callbacks_run).to eq([:callback])
125
+ expect {
126
126
  client.close
127
- }.should_not raise_error(/invalid binding to detach/)
127
+ }.not_to raise_error
128
128
  EM.stop_event_loop
129
129
  end
130
130
  end
@@ -1,48 +1,46 @@
1
1
  # encoding: UTF-8
2
2
  require 'spec_helper'
3
3
 
4
- describe Mysql2::Client do
4
+ RSpec.describe Mysql2::Client do
5
5
  context "using defaults file" do
6
6
  let(:cnf_file) { File.expand_path('../../my.cnf', __FILE__) }
7
7
 
8
8
  it "should not raise an exception for valid defaults group" do
9
- lambda {
9
+ expect {
10
10
  opts = DatabaseCredentials['root'].merge(:default_file => cnf_file, :default_group => "test")
11
11
  @client = Mysql2::Client.new(opts)
12
- }.should_not raise_error(Mysql2::Error)
12
+ }.not_to raise_error
13
13
  end
14
14
 
15
15
  it "should not raise an exception without default group" do
16
- lambda {
16
+ expect {
17
17
  @client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:default_file => cnf_file))
18
- }.should_not raise_error(Mysql2::Error)
18
+ }.not_to raise_error
19
19
  end
20
20
  end
21
21
 
22
22
  it "should raise an exception upon connection failure" do
23
- lambda {
23
+ expect {
24
24
  # The odd local host IP address forces the mysql client library to
25
25
  # use a TCP socket rather than a domain socket.
26
26
  Mysql2::Client.new DatabaseCredentials['root'].merge('host' => '127.0.0.2', 'port' => 999999)
27
- }.should raise_error(Mysql2::Error)
27
+ }.to raise_error(Mysql2::Error)
28
28
  end
29
29
 
30
- if defined? Encoding
31
- it "should raise an exception on create for invalid encodings" do
32
- lambda {
33
- Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "fake"))
34
- }.should raise_error(Mysql2::Error)
35
- end
30
+ it "should raise an exception on create for invalid encodings" do
31
+ expect {
32
+ Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "fake"))
33
+ }.to raise_error(Mysql2::Error)
34
+ end
36
35
 
37
- it "should not raise an exception on create for a valid encoding" do
38
- lambda {
39
- Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "utf8"))
40
- }.should_not raise_error(Mysql2::Error)
36
+ it "should not raise an exception on create for a valid encoding" do
37
+ expect {
38
+ Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "utf8"))
39
+ }.not_to raise_error
41
40
 
42
- lambda {
43
- Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "big5"))
44
- }.should_not raise_error(Mysql2::Error)
45
- end
41
+ expect {
42
+ Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "big5"))
43
+ }.not_to raise_error
46
44
  end
47
45
 
48
46
  it "should accept connect flags and pass them to #connect" do
@@ -54,7 +52,7 @@ describe Mysql2::Client do
54
52
  end
55
53
  end
56
54
  client = klient.new :flags => Mysql2::Client::FOUND_ROWS
57
- (client.connect_args.last[6] & Mysql2::Client::FOUND_ROWS).should be_true
55
+ expect(client.connect_args.last[6] & Mysql2::Client::FOUND_ROWS).to be > 0
58
56
  end
59
57
 
60
58
  it "should default flags to (REMEMBER_OPTIONS, LONG_PASSWORD, LONG_FLAG, TRANSACTIONS, PROTOCOL_41, SECURE_CONNECTION)" do
@@ -72,7 +70,7 @@ describe Mysql2::Client do
72
70
  Mysql2::Client::TRANSACTIONS |
73
71
  Mysql2::Client::PROTOCOL_41 |
74
72
  Mysql2::Client::SECURE_CONNECTION
75
- client.connect_args.last[6].should eql(client_flags)
73
+ expect(client.connect_args.last[6]).to eql(client_flags)
76
74
  end
77
75
 
78
76
  it "should execute init command" do
@@ -80,7 +78,7 @@ describe Mysql2::Client do
80
78
  options[:init_command] = "SET @something = 'setting_value';"
81
79
  client = Mysql2::Client.new(options)
82
80
  result = client.query("SELECT @something;")
83
- result.first['@something'].should eq('setting_value')
81
+ expect(result.first['@something']).to eq('setting_value')
84
82
  end
85
83
 
86
84
  it "should send init_command after reconnect" do
@@ -90,17 +88,14 @@ describe Mysql2::Client do
90
88
  client = Mysql2::Client.new(options)
91
89
 
92
90
  result = client.query("SELECT @something;")
93
- result.first['@something'].should eq('setting_value')
91
+ expect(result.first['@something']).to eq('setting_value')
94
92
 
95
93
  # get the current connection id
96
94
  result = client.query("SELECT CONNECTION_ID()")
97
95
  first_conn_id = result.first['CONNECTION_ID()']
98
96
 
99
97
  # break the current connection
100
- begin
101
- client.query("KILL #{first_conn_id}")
102
- rescue Mysql2::Error
103
- end
98
+ expect { client.query("KILL #{first_conn_id}") }.to raise_error(Mysql2::Error)
104
99
 
105
100
  client.ping # reconnect now
106
101
 
@@ -109,15 +104,15 @@ describe Mysql2::Client do
109
104
  second_conn_id = result.first['CONNECTION_ID()']
110
105
 
111
106
  # confirm reconnect by checking the new connection id
112
- first_conn_id.should_not == second_conn_id
107
+ expect(first_conn_id).not_to eq(second_conn_id)
113
108
 
114
109
  # At last, check that the init command executed
115
110
  result = client.query("SELECT @something;")
116
- result.first['@something'].should eq('setting_value')
111
+ expect(result.first['@something']).to eq('setting_value')
117
112
  end
118
113
 
119
114
  it "should have a global default_query_options hash" do
120
- Mysql2::Client.should respond_to(:default_query_options)
115
+ expect(Mysql2::Client).to respond_to(:default_query_options)
121
116
  end
122
117
 
123
118
  it "should be able to connect via SSL options" do
@@ -129,7 +124,7 @@ describe Mysql2::Client do
129
124
 
130
125
  # You may need to adjust the lines below to match your SSL certificate paths
131
126
  ssl_client = nil
132
- lambda {
127
+ expect {
133
128
  ssl_client = Mysql2::Client.new(
134
129
  :sslkey => '/etc/mysql/client-key.pem',
135
130
  :sslcert => '/etc/mysql/client-cert.pem',
@@ -137,25 +132,34 @@ describe Mysql2::Client do
137
132
  :sslcapath => '/etc/mysql/',
138
133
  :sslcipher => 'DHE-RSA-AES256-SHA'
139
134
  )
140
- }.should_not raise_error(Mysql2::Error)
135
+ }.not_to raise_error
141
136
 
142
137
  results = ssl_client.query("SHOW STATUS WHERE Variable_name = \"Ssl_version\" OR Variable_name = \"Ssl_cipher\"").to_a
143
- results[0]['Variable_name'].should eql('Ssl_cipher')
144
- results[0]['Value'].should_not be_nil
145
- results[0]['Value'].should be_kind_of(String)
146
- results[0]['Value'].should_not be_empty
138
+ expect(results[0]['Variable_name']).to eql('Ssl_cipher')
139
+ expect(results[0]['Value']).not_to be_nil
140
+ expect(results[0]['Value']).to be_kind_of(String)
141
+ expect(results[0]['Value']).not_to be_empty
147
142
 
148
- results[1]['Variable_name'].should eql('Ssl_version')
149
- results[1]['Value'].should_not be_nil
150
- results[1]['Value'].should be_kind_of(String)
151
- results[1]['Value'].should_not be_empty
143
+ expect(results[1]['Variable_name']).to eql('Ssl_version')
144
+ expect(results[1]['Value']).not_to be_nil
145
+ expect(results[1]['Value']).to be_kind_of(String)
146
+ expect(results[1]['Value']).not_to be_empty
152
147
 
153
148
  ssl_client.close
154
149
  end
155
150
 
151
+ def run_gc
152
+ if defined?(Rubinius)
153
+ GC.run(true)
154
+ else
155
+ GC.start
156
+ end
157
+ sleep(0.5)
158
+ end
159
+
156
160
  it "should not leave dangling connections after garbage collection" do
157
- GC.start
158
- sleep 0.300 # Let GC do its work
161
+ run_gc
162
+
159
163
  client = Mysql2::Client.new(DatabaseCredentials['root'])
160
164
  before_count = client.query("SHOW STATUS LIKE 'Threads_connected'").first['Value'].to_i
161
165
 
@@ -163,69 +167,70 @@ describe Mysql2::Client do
163
167
  Mysql2::Client.new(DatabaseCredentials['root']).query('SELECT 1')
164
168
  end
165
169
  after_count = client.query("SHOW STATUS LIKE 'Threads_connected'").first['Value'].to_i
166
- after_count.should == before_count + 10
170
+ expect(after_count).to eq(before_count + 10)
167
171
 
168
- GC.start
169
- sleep 0.300 # Let GC do its work
172
+ run_gc
170
173
  final_count = client.query("SHOW STATUS LIKE 'Threads_connected'").first['Value'].to_i
171
- final_count.should == before_count
174
+ expect(final_count).to eq(before_count)
172
175
  end
173
176
 
174
- if Process.respond_to?(:fork)
175
- it "should not close connections when running in a child process" do
176
- GC.start
177
- sleep 1 if defined? Rubinius # Let the rbx GC thread do its work
178
- client = Mysql2::Client.new(DatabaseCredentials['root'])
179
-
180
- fork do
181
- client.query('SELECT 1')
182
- client = nil
183
- GC.start
184
- sleep 1 if defined? Rubinius # Let the rbx GC thread do its work
185
- end
177
+ it "should not close connections when running in a child process" do
178
+ pending("fork is not available on this platform") unless Process.respond_to?(:fork)
186
179
 
187
- Process.wait
180
+ run_gc
181
+ client = Mysql2::Client.new(DatabaseCredentials['root'])
182
+
183
+ # this empty `fork` call fixes this tests on RBX; without it, the next
184
+ # `fork` call hangs forever. WTF?
185
+ fork { }
188
186
 
189
- # this will throw an error if the underlying socket was shutdown by the
190
- # child's GC
191
- expect { client.query('SELECT 1') }.to_not raise_exception
187
+ fork do
188
+ client.query('SELECT 1')
189
+ client = nil
190
+ run_gc
192
191
  end
192
+
193
+ Process.wait
194
+
195
+ # this will throw an error if the underlying socket was shutdown by the
196
+ # child's GC
197
+ expect { client.query('SELECT 1') }.to_not raise_exception
193
198
  end
194
199
 
195
200
  it "should be able to connect to database with numeric-only name" do
196
- lambda {
197
- creds = DatabaseCredentials['numericuser']
198
- @client.query "CREATE DATABASE IF NOT EXISTS `#{creds['database']}`"
199
- @client.query "GRANT ALL ON `#{creds['database']}`.* TO #{creds['username']}@`#{creds['host']}`"
200
- client = Mysql2::Client.new creds
201
- @client.query "DROP DATABASE IF EXISTS `#{creds['database']}`"
202
- }.should_not raise_error
201
+ creds = DatabaseCredentials['numericuser']
202
+ @client.query "CREATE DATABASE IF NOT EXISTS `#{creds['database']}`"
203
+ @client.query "GRANT ALL ON `#{creds['database']}`.* TO #{creds['username']}@`#{creds['host']}`"
204
+
205
+ expect { Mysql2::Client.new(creds) }.not_to raise_error
206
+
207
+ @client.query "DROP DATABASE IF EXISTS `#{creds['database']}`"
203
208
  end
204
209
 
205
210
  it "should respond to #close" do
206
- @client.should respond_to(:close)
211
+ expect(@client).to respond_to(:close)
207
212
  end
208
213
 
209
214
  it "should be able to close properly" do
210
- @client.close.should be_nil
211
- lambda {
215
+ expect(@client.close).to be_nil
216
+ expect {
212
217
  @client.query "SELECT 1"
213
- }.should raise_error(Mysql2::Error)
218
+ }.to raise_error(Mysql2::Error)
214
219
  end
215
220
 
216
221
  it "should respond to #query" do
217
- @client.should respond_to(:query)
222
+ expect(@client).to respond_to(:query)
218
223
  end
219
224
 
220
225
  it "should respond to #warning_count" do
221
- @client.should respond_to(:warning_count)
226
+ expect(@client).to respond_to(:warning_count)
222
227
  end
223
228
 
224
229
  context "#warning_count" do
225
230
  context "when no warnings" do
226
231
  it "should 0" do
227
232
  @client.query('select 1')
228
- @client.warning_count.should == 0
233
+ expect(@client.warning_count).to eq(0)
229
234
  end
230
235
  end
231
236
  context "when has a warnings" do
@@ -233,21 +238,21 @@ describe Mysql2::Client do
233
238
  # "the statement produces extra information that can be viewed by issuing a SHOW WARNINGS"
234
239
  # http://dev.mysql.com/doc/refman/5.0/en/explain-extended.html
235
240
  @client.query("explain extended select 1")
236
- @client.warning_count.should > 0
241
+ expect(@client.warning_count).to be > 0
237
242
  end
238
243
  end
239
244
  end
240
245
 
241
246
  it "should respond to #query_info" do
242
- @client.should respond_to(:query_info)
247
+ expect(@client).to respond_to(:query_info)
243
248
  end
244
249
 
245
250
  context "#query_info" do
246
251
  context "when no info present" do
247
252
  it "should 0" do
248
253
  @client.query('select 1')
249
- @client.query_info.should be_empty
250
- @client.query_info_string.should be_nil
254
+ expect(@client.query_info).to be_empty
255
+ expect(@client.query_info_string).to be_nil
251
256
  end
252
257
  end
253
258
  context "when has some info" do
@@ -259,8 +264,8 @@ describe Mysql2::Client do
259
264
  # # Note that mysql_info() returns a non-NULL value for INSERT ... VALUES only for the multiple-row form of the statement (that is, only if multiple value lists are specified).
260
265
  @client.query("INSERT INTO infoTest (blah) VALUES (1234),(4535)")
261
266
 
262
- @client.query_info.should eql({:records => 2, :duplicates => 0, :warnings => 0})
263
- @client.query_info_string.should eq('Records: 2 Duplicates: 0 Warnings: 0')
267
+ expect(@client.query_info).to eql({:records => 2, :duplicates => 0, :warnings => 0})
268
+ expect(@client.query_info_string).to eq('Records: 2 Duplicates: 0 Warnings: 0')
264
269
 
265
270
  @client.query "DROP TABLE infoTest"
266
271
  end
@@ -289,43 +294,43 @@ describe Mysql2::Client do
289
294
 
290
295
  it "should raise an error when local_infile is disabled" do
291
296
  client = Mysql2::Client.new DatabaseCredentials['root'].merge(:local_infile => false)
292
- lambda {
297
+ expect {
293
298
  client.query "LOAD DATA LOCAL INFILE 'spec/test_data' INTO TABLE infileTest"
294
- }.should raise_error(Mysql2::Error, %r{command is not allowed})
299
+ }.to raise_error(Mysql2::Error, /command is not allowed/)
295
300
  end
296
301
 
297
302
  it "should raise an error when a non-existent file is loaded" do
298
- lambda {
303
+ expect {
299
304
  @client_i.query "LOAD DATA LOCAL INFILE 'this/file/is/not/here' INTO TABLE infileTest"
300
- }.should_not raise_error(Mysql2::Error, %r{file not found: this/file/is/not/here})
305
+ }.to raise_error(Mysql2::Error, 'No such file or directory: this/file/is/not/here')
301
306
  end
302
307
 
303
308
  it "should LOAD DATA LOCAL INFILE" do
304
309
  @client_i.query "LOAD DATA LOCAL INFILE 'spec/test_data' INTO TABLE infileTest"
305
310
  info = @client_i.query_info
306
- info.should eql({:records => 1, :deleted => 0, :skipped => 0, :warnings => 0})
311
+ expect(info).to eql({:records => 1, :deleted => 0, :skipped => 0, :warnings => 0})
307
312
 
308
313
  result = @client_i.query "SELECT * FROM infileTest"
309
- result.first.should eql({'id' => 1, 'foo' => 'Hello', 'bar' => 'World'})
314
+ expect(result.first).to eql({'id' => 1, 'foo' => 'Hello', 'bar' => 'World'})
310
315
  end
311
316
  end
312
317
 
313
318
  it "should expect connect_timeout to be a positive integer" do
314
- lambda {
319
+ expect {
315
320
  Mysql2::Client.new(:connect_timeout => -1)
316
- }.should raise_error(Mysql2::Error)
321
+ }.to raise_error(Mysql2::Error)
317
322
  end
318
323
 
319
324
  it "should expect read_timeout to be a positive integer" do
320
- lambda {
325
+ expect {
321
326
  Mysql2::Client.new(:read_timeout => -1)
322
- }.should raise_error(Mysql2::Error)
327
+ }.to raise_error(Mysql2::Error)
323
328
  end
324
329
 
325
330
  it "should expect write_timeout to be a positive integer" do
326
- lambda {
331
+ expect {
327
332
  Mysql2::Client.new(:write_timeout => -1)
328
- }.should raise_error(Mysql2::Error)
333
+ }.to raise_error(Mysql2::Error)
329
334
  end
330
335
 
331
336
  context "#query" do
@@ -334,7 +339,7 @@ describe Mysql2::Client do
334
339
 
335
340
  expect {
336
341
  @client.query("SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false)
337
- }.to_not raise_exception(Mysql2::Error)
342
+ }.to_not raise_error
338
343
  end
339
344
 
340
345
  it "should not let you query again if iterating is not finished when streaming" do
@@ -346,126 +351,121 @@ describe Mysql2::Client do
346
351
  end
347
352
 
348
353
  it "should only accept strings as the query parameter" do
349
- lambda {
354
+ expect {
350
355
  @client.query ["SELECT 'not right'"]
351
- }.should raise_error(TypeError)
356
+ }.to raise_error(TypeError)
352
357
  end
353
358
 
354
359
  it "should not retain query options set on a query for subsequent queries, but should retain it in the result" do
355
360
  result = @client.query "SELECT 1", :something => :else
356
- @client.query_options[:something].should be_nil
357
- result.instance_variable_get('@query_options').should eql(@client.query_options.merge(:something => :else))
358
- @client.instance_variable_get('@current_query_options').should eql(@client.query_options.merge(:something => :else))
361
+ expect(@client.query_options[:something]).to be_nil
362
+ expect(result.instance_variable_get('@query_options')).to eql(@client.query_options.merge(:something => :else))
363
+ expect(@client.instance_variable_get('@current_query_options')).to eql(@client.query_options.merge(:something => :else))
359
364
 
360
365
  result = @client.query "SELECT 1"
361
- result.instance_variable_get('@query_options').should eql(@client.query_options)
362
- @client.instance_variable_get('@current_query_options').should eql(@client.query_options)
366
+ expect(result.instance_variable_get('@query_options')).to eql(@client.query_options)
367
+ expect(@client.instance_variable_get('@current_query_options')).to eql(@client.query_options)
363
368
  end
364
369
 
365
370
  it "should allow changing query options for subsequent queries" do
366
371
  @client.query_options.merge!(:something => :else)
367
372
  result = @client.query "SELECT 1"
368
- @client.query_options[:something].should eql(:else)
369
- result.instance_variable_get('@query_options')[:something].should eql(:else)
373
+ expect(@client.query_options[:something]).to eql(:else)
374
+ expect(result.instance_variable_get('@query_options')[:something]).to eql(:else)
370
375
 
371
376
  # Clean up after this test
372
377
  @client.query_options.delete(:something)
373
- @client.query_options[:something].should be_nil
378
+ expect(@client.query_options[:something]).to be_nil
374
379
  end
375
380
 
376
381
  it "should return results as a hash by default" do
377
- @client.query("SELECT 1").first.class.should eql(Hash)
382
+ expect(@client.query("SELECT 1").first.class).to eql(Hash)
378
383
  end
379
384
 
380
385
  it "should be able to return results as an array" do
381
- @client.query("SELECT 1", :as => :array).first.class.should eql(Array)
386
+ expect(@client.query("SELECT 1", :as => :array).first.class).to eql(Array)
382
387
  @client.query("SELECT 1").each(:as => :array)
383
388
  end
384
389
 
385
390
  it "should be able to return results with symbolized keys" do
386
- @client.query("SELECT 1", :symbolize_keys => true).first.keys[0].class.should eql(Symbol)
391
+ expect(@client.query("SELECT 1", :symbolize_keys => true).first.keys[0].class).to eql(Symbol)
387
392
  end
388
393
 
389
394
  it "should require an open connection" do
390
395
  @client.close
391
- lambda {
396
+ expect {
392
397
  @client.query "SELECT 1"
393
- }.should raise_error(Mysql2::Error)
398
+ }.to raise_error(Mysql2::Error)
394
399
  end
395
400
 
396
401
  if RUBY_PLATFORM !~ /mingw|mswin/
397
402
  it "should not allow another query to be sent without fetching a result first" do
398
403
  @client.query("SELECT 1", :async => true)
399
- lambda {
404
+ expect {
400
405
  @client.query("SELECT 1")
401
- }.should raise_error(Mysql2::Error)
406
+ }.to raise_error(Mysql2::Error)
402
407
  end
403
408
 
404
409
  it "should describe the thread holding the active query" do
405
410
  thr = Thread.new { @client.query("SELECT 1", :async => true) }
406
411
 
407
412
  thr.join
408
- begin
409
- @client.query("SELECT 1")
410
- rescue Mysql2::Error => e
411
- message = e.message
412
- end
413
- re = Regexp.escape(thr.inspect)
414
- message.should match(Regexp.new(re))
413
+ expect { @client.query('SELECT 1') }.to raise_error(Mysql2::Error, Regexp.new(Regexp.escape(thr.inspect)))
415
414
  end
416
415
 
417
416
  it "should timeout if we wait longer than :read_timeout" do
418
- client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:read_timeout => 1))
419
- lambda {
420
- client.query("SELECT sleep(2)")
421
- }.should raise_error(Mysql2::Error)
417
+ client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:read_timeout => 0))
418
+ expect {
419
+ client.query('SELECT SLEEP(0.1)')
420
+ }.to raise_error(Mysql2::Error)
422
421
  end
423
422
 
424
- if !defined? Rubinius
425
- # XXX this test is not deterministic (because Unix signal handling is not)
426
- # and may fail on a loaded system
427
- it "should run signal handlers while waiting for a response" do
428
- mark = {}
429
- trap(:USR1) { mark[:USR1] = Time.now }
430
- begin
431
- mark[:START] = Time.now
432
- pid = fork do
433
- sleep 1 # wait for client "SELECT sleep(2)" query to start
434
- Process.kill(:USR1, Process.ppid)
435
- sleep # wait for explicit kill to prevent GC disconnect
436
- end
437
- @client.query("SELECT sleep(2)")
438
- mark[:END] = Time.now
439
- mark.include?(:USR1).should be_true
440
- (mark[:USR1] - mark[:START]).should >= 1
441
- (mark[:USR1] - mark[:START]).should < 1.3
442
- (mark[:END] - mark[:USR1]).should > 0.9
443
- (mark[:END] - mark[:START]).should >= 2
444
- (mark[:END] - mark[:START]).should < 2.3
445
- Process.kill(:TERM, pid)
446
- Process.waitpid2(pid)
447
- ensure
448
- trap(:USR1, 'DEFAULT')
423
+ # XXX this test is not deterministic (because Unix signal handling is not)
424
+ # and may fail on a loaded system
425
+ it "should run signal handlers while waiting for a response" do
426
+ kill_time = 0.1
427
+ query_time = 2 * kill_time
428
+
429
+ mark = {}
430
+
431
+ begin
432
+ trap(:USR1) { mark.store(:USR1, Time.now) }
433
+ pid = fork do
434
+ sleep kill_time # wait for client query to start
435
+ Process.kill(:USR1, Process.ppid)
436
+ sleep # wait for explicit kill to prevent GC disconnect
449
437
  end
438
+ mark.store(:QUERY_START, Time.now)
439
+ @client.query("SELECT SLEEP(#{query_time})")
440
+ mark.store(:QUERY_END, Time.now)
441
+ ensure
442
+ Process.kill(:TERM, pid)
443
+ Process.waitpid2(pid)
444
+ trap(:USR1, 'DEFAULT')
450
445
  end
446
+
447
+ # the query ran uninterrupted
448
+ expect(mark.fetch(:QUERY_END) - mark.fetch(:QUERY_START)).to be_within(0.02).of(query_time)
449
+ # signals fired while the query was running
450
+ expect(mark.fetch(:USR1)).to be_between(mark.fetch(:QUERY_START), mark.fetch(:QUERY_END))
451
451
  end
452
452
 
453
453
  it "#socket should return a Fixnum (file descriptor from C)" do
454
- @client.socket.class.should eql(Fixnum)
455
- @client.socket.should_not eql(0)
454
+ expect(@client.socket.class).to eql(Fixnum)
455
+ expect(@client.socket).not_to eql(0)
456
456
  end
457
457
 
458
458
  it "#socket should require an open connection" do
459
459
  @client.close
460
- lambda {
460
+ expect {
461
461
  @client.socket
462
- }.should raise_error(Mysql2::Error)
462
+ }.to raise_error(Mysql2::Error)
463
463
  end
464
464
 
465
- it 'should be impervious to connection-corrupting timeouts in #query' do
465
+ it 'should be impervious to connection-corrupting timeouts ' do
466
466
  pending('`Thread.handle_interrupt` is not defined') unless Thread.respond_to?(:handle_interrupt)
467
467
  # attempt to break the connection
468
- expect { Timeout.timeout(0.1) { @client.query('SELECT SLEEP(1)') } }.to raise_error(Timeout::Error)
468
+ expect { Timeout.timeout(0.1) { @client.query('SELECT SLEEP(0.2)') } }.to raise_error(Timeout::Error)
469
469
 
470
470
  # expect the connection to not be broken
471
471
  expect { @client.query('SELECT 1') }.to_not raise_error
@@ -478,13 +478,21 @@ describe Mysql2::Client do
478
478
  end
479
479
 
480
480
  it "should handle Timeouts without leaving the connection hanging if reconnect is true" do
481
+ if RUBY_PLATFORM.include?('darwin') && Mysql2::Client.info.fetch(:version).start_with?('5.5')
482
+ pending('libmysqlclient 5.5 on OSX is afflicted by an unknown bug that breaks this test. See #633 and #634.')
483
+ end
484
+
481
485
  client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:reconnect => true))
482
486
 
483
487
  expect { Timeout.timeout(0.1, ArgumentError) { client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
484
488
  expect { client.query('SELECT 1') }.to_not raise_error
485
489
  end
486
490
 
487
- it "should handle Timeouts without leaving the connection hanging if reconnect is set to true after construction true" do
491
+ it "should handle Timeouts without leaving the connection hanging if reconnect is set to true after construction" do
492
+ if RUBY_PLATFORM.include?('darwin') && Mysql2::Client.info.fetch(:version).start_with?('5.5')
493
+ pending('libmysqlclient 5.5 on OSX is afflicted by an unknown bug that breaks this test. See #633 and #634.')
494
+ end
495
+
488
496
  client = Mysql2::Client.new(DatabaseCredentials['root'])
489
497
 
490
498
  expect { Timeout.timeout(0.1, ArgumentError) { client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
@@ -498,28 +506,27 @@ describe Mysql2::Client do
498
506
  end
499
507
 
500
508
  it "threaded queries should be supported" do
501
- threads, results = [], {}
502
- lock = Mutex.new
503
- connect = lambda{
504
- Mysql2::Client.new(DatabaseCredentials['root'])
505
- }
506
- Timeout.timeout(0.7) do
507
- 5.times {
508
- threads << Thread.new do
509
- result = connect.call.query("SELECT sleep(0.5) as result")
510
- lock.synchronize do
511
- results[Thread.current.object_id] = result
512
- end
513
- end
514
- }
509
+ sleep_time = 0.5
510
+
511
+ # Note that each thread opens its own database connection
512
+ threads = 5.times.map do
513
+ Thread.new do
514
+ client = Mysql2::Client.new(DatabaseCredentials.fetch('root'))
515
+ client.query("SELECT SLEEP(#{sleep_time})")
516
+ Thread.current.object_id
517
+ end
515
518
  end
516
- threads.each{|t| t.join }
517
- results.keys.sort.should eql(threads.map{|t| t.object_id }.sort)
519
+
520
+ # This timeout demonstrates that the threads are sleeping concurrently:
521
+ # In the serial case, the timeout would fire and the test would fail
522
+ values = Timeout.timeout(sleep_time * 1.1) { threads.map(&:value) }
523
+
524
+ expect(values).to match_array(threads.map(&:object_id))
518
525
  end
519
526
 
520
527
  it "evented async queries should be supported" do
521
528
  # should immediately return nil
522
- @client.query("SELECT sleep(0.1)", :async => true).should eql(nil)
529
+ expect(@client.query("SELECT sleep(0.1)", :async => true)).to eql(nil)
523
530
 
524
531
  io_wrapper = IO.for_fd(@client.socket)
525
532
  loops = 0
@@ -532,10 +539,10 @@ describe Mysql2::Client do
532
539
  end
533
540
 
534
541
  # make sure we waited some period of time
535
- (loops >= 1).should be_true
542
+ expect(loops >= 1).to be true
536
543
 
537
544
  result = @client.async_result
538
- result.class.should eql(Mysql2::Result)
545
+ expect(result.class).to eql(Mysql2::Result)
539
546
  end
540
547
  end
541
548
 
@@ -546,20 +553,20 @@ describe Mysql2::Client do
546
553
 
547
554
  it "should raise an exception when one of multiple statements fails" do
548
555
  result = @multi_client.query("SELECT 1 AS 'set_1'; SELECT * FROM invalid_table_name; SELECT 2 AS 'set_2';")
549
- result.first['set_1'].should be(1)
550
- lambda {
556
+ expect(result.first['set_1']).to be(1)
557
+ expect {
551
558
  @multi_client.next_result
552
- }.should raise_error(Mysql2::Error)
553
- @multi_client.next_result.should be_false
559
+ }.to raise_error(Mysql2::Error)
560
+ expect(@multi_client.next_result).to be false
554
561
  end
555
562
 
556
563
  it "returns multiple result sets" do
557
- @multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'").first.should eql({ 'set_1' => 1 })
564
+ expect(@multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'").first).to eql({ 'set_1' => 1 })
558
565
 
559
- @multi_client.next_result.should be_true
560
- @multi_client.store_result.first.should eql({ 'set_2' => 2 })
566
+ expect(@multi_client.next_result).to be true
567
+ expect(@multi_client.store_result.first).to eql({ 'set_2' => 2 })
561
568
 
562
- @multi_client.next_result.should be_false
569
+ expect(@multi_client.next_result).to be false
563
570
  end
564
571
 
565
572
  it "does not interfere with other statements" do
@@ -568,133 +575,133 @@ describe Mysql2::Client do
568
575
  @multi_client.store_result
569
576
  end
570
577
 
571
- @multi_client.query("SELECT 3 AS 'next'").first.should == { 'next' => 3 }
578
+ expect(@multi_client.query("SELECT 3 AS 'next'").first).to eq({ 'next' => 3 })
572
579
  end
573
580
 
574
581
  it "will raise on query if there are outstanding results to read" do
575
582
  @multi_client.query("SELECT 1; SELECT 2; SELECT 3")
576
- lambda {
583
+ expect {
577
584
  @multi_client.query("SELECT 4")
578
- }.should raise_error(Mysql2::Error)
585
+ }.to raise_error(Mysql2::Error)
579
586
  end
580
587
 
581
588
  it "#abandon_results! should work" do
582
589
  @multi_client.query("SELECT 1; SELECT 2; SELECT 3")
583
590
  @multi_client.abandon_results!
584
- lambda {
591
+ expect {
585
592
  @multi_client.query("SELECT 4")
586
- }.should_not raise_error(Mysql2::Error)
593
+ }.not_to raise_error
587
594
  end
588
595
 
589
596
  it "#more_results? should work" do
590
597
  @multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'")
591
- @multi_client.more_results?.should be_true
598
+ expect(@multi_client.more_results?).to be true
592
599
 
593
600
  @multi_client.next_result
594
601
  @multi_client.store_result
595
602
 
596
- @multi_client.more_results?.should be_false
603
+ expect(@multi_client.more_results?).to be false
597
604
  end
598
605
 
599
606
  it "#more_results? should work with stored procedures" do
600
607
  @multi_client.query("DROP PROCEDURE IF EXISTS test_proc")
601
608
  @multi_client.query("CREATE PROCEDURE test_proc() BEGIN SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'; END")
602
- @multi_client.query("CALL test_proc()").first.should eql({ 'set_1' => 1 })
603
- @multi_client.more_results?.should be_true
609
+ expect(@multi_client.query("CALL test_proc()").first).to eql({ 'set_1' => 1 })
610
+ expect(@multi_client.more_results?).to be true
604
611
 
605
612
  @multi_client.next_result
606
- @multi_client.store_result.first.should eql({ 'set_2' => 2 })
613
+ expect(@multi_client.store_result.first).to eql({ 'set_2' => 2 })
607
614
 
608
615
  @multi_client.next_result
609
- @multi_client.store_result.should be_nil # this is the result from CALL itself
616
+ expect(@multi_client.store_result).to be_nil # this is the result from CALL itself
610
617
 
611
- @multi_client.more_results?.should be_false
618
+ expect(@multi_client.more_results?).to be false
612
619
  end
613
620
  end
614
621
  end
615
622
 
616
623
  it "should respond to #socket" do
617
- @client.should respond_to(:socket)
624
+ expect(@client).to respond_to(:socket)
618
625
  end
619
626
 
620
627
  if RUBY_PLATFORM =~ /mingw|mswin/
621
628
  it "#socket should raise as it's not supported" do
622
- lambda {
629
+ expect {
623
630
  @client.socket
624
- }.should raise_error(Mysql2::Error)
631
+ }.to raise_error(Mysql2::Error)
625
632
  end
626
633
  end
627
634
 
628
635
  it "should respond to escape" do
629
- Mysql2::Client.should respond_to(:escape)
636
+ expect(Mysql2::Client).to respond_to(:escape)
630
637
  end
631
638
 
632
639
  context "escape" do
633
640
  it "should return a new SQL-escape version of the passed string" do
634
- Mysql2::Client.escape("abc'def\"ghi\0jkl%mno").should eql("abc\\'def\\\"ghi\\0jkl%mno")
641
+ expect(Mysql2::Client.escape("abc'def\"ghi\0jkl%mno")).to eql("abc\\'def\\\"ghi\\0jkl%mno")
635
642
  end
636
643
 
637
644
  it "should return the passed string if nothing was escaped" do
638
645
  str = "plain"
639
- Mysql2::Client.escape(str).object_id.should eql(str.object_id)
646
+ expect(Mysql2::Client.escape(str).object_id).to eql(str.object_id)
640
647
  end
641
648
 
642
649
  it "should not overflow the thread stack" do
643
- lambda {
650
+ expect {
644
651
  Thread.new { Mysql2::Client.escape("'" * 256 * 1024) }.join
645
- }.should_not raise_error(SystemStackError)
652
+ }.not_to raise_error
646
653
  end
647
654
 
648
655
  it "should not overflow the process stack" do
649
- lambda {
656
+ expect {
650
657
  Thread.new { Mysql2::Client.escape("'" * 1024 * 1024 * 4) }.join
651
- }.should_not raise_error(SystemStackError)
658
+ }.not_to raise_error
652
659
  end
653
660
 
654
661
  unless RUBY_VERSION =~ /1.8/
655
662
  it "should carry over the original string's encoding" do
656
663
  str = "abc'def\"ghi\0jkl%mno"
657
664
  escaped = Mysql2::Client.escape(str)
658
- escaped.encoding.should eql(str.encoding)
665
+ expect(escaped.encoding).to eql(str.encoding)
659
666
 
660
667
  str.encode!('us-ascii')
661
668
  escaped = Mysql2::Client.escape(str)
662
- escaped.encoding.should eql(str.encoding)
669
+ expect(escaped.encoding).to eql(str.encoding)
663
670
  end
664
671
  end
665
672
  end
666
673
 
667
674
  it "should respond to #escape" do
668
- @client.should respond_to(:escape)
675
+ expect(@client).to respond_to(:escape)
669
676
  end
670
677
 
671
678
  context "#escape" do
672
679
  it "should return a new SQL-escape version of the passed string" do
673
- @client.escape("abc'def\"ghi\0jkl%mno").should eql("abc\\'def\\\"ghi\\0jkl%mno")
680
+ expect(@client.escape("abc'def\"ghi\0jkl%mno")).to eql("abc\\'def\\\"ghi\\0jkl%mno")
674
681
  end
675
682
 
676
683
  it "should return the passed string if nothing was escaped" do
677
684
  str = "plain"
678
- @client.escape(str).object_id.should eql(str.object_id)
685
+ expect(@client.escape(str).object_id).to eql(str.object_id)
679
686
  end
680
687
 
681
688
  it "should not overflow the thread stack" do
682
- lambda {
689
+ expect {
683
690
  Thread.new { @client.escape("'" * 256 * 1024) }.join
684
- }.should_not raise_error(SystemStackError)
691
+ }.not_to raise_error
685
692
  end
686
693
 
687
694
  it "should not overflow the process stack" do
688
- lambda {
695
+ expect {
689
696
  Thread.new { @client.escape("'" * 1024 * 1024 * 4) }.join
690
- }.should_not raise_error(SystemStackError)
697
+ }.not_to raise_error
691
698
  end
692
699
 
693
700
  it "should require an open connection" do
694
701
  @client.close
695
- lambda {
702
+ expect {
696
703
  @client.escape ""
697
- }.should raise_error(Mysql2::Error)
704
+ }.to raise_error(Mysql2::Error)
698
705
  end
699
706
 
700
707
  context 'when mysql encoding is not utf8' do
@@ -704,32 +711,32 @@ describe Mysql2::Client do
704
711
 
705
712
  it 'should return a internal encoding string if Encoding.default_internal is set' do
706
713
  with_internal_encoding Encoding::UTF_8 do
707
- client.escape("\u{30C6}\u{30B9}\u{30C8}").should eql("\u{30C6}\u{30B9}\u{30C8}")
708
- client.escape("\u{30C6}'\u{30B9}\"\u{30C8}").should eql("\u{30C6}\\'\u{30B9}\\\"\u{30C8}")
714
+ expect(client.escape("\u{30C6}\u{30B9}\u{30C8}")).to eq "\u{30C6}\u{30B9}\u{30C8}"
715
+ expect(client.escape("\u{30C6}'\u{30B9}\"\u{30C8}")).to eq "\u{30C6}\\'\u{30B9}\\\"\u{30C8}"
709
716
  end
710
717
  end
711
718
  end
712
719
  end
713
720
 
714
721
  it "should respond to #info" do
715
- @client.should respond_to(:info)
722
+ expect(@client).to respond_to(:info)
716
723
  end
717
724
 
718
725
  it "#info should return a hash containing the client version ID and String" do
719
726
  info = @client.info
720
- info.class.should eql(Hash)
721
- info.should have_key(:id)
722
- info[:id].class.should eql(Fixnum)
723
- info.should have_key(:version)
724
- info[:version].class.should eql(String)
727
+ expect(info.class).to eql(Hash)
728
+ expect(info).to have_key(:id)
729
+ expect(info[:id].class).to eql(Fixnum)
730
+ expect(info).to have_key(:version)
731
+ expect(info[:version].class).to eql(String)
725
732
  end
726
733
 
727
734
  context "strings returned by #info" do
728
735
  before { pending('Encoding is undefined') unless defined?(Encoding) }
729
736
 
730
737
  it "should be tagged as ascii" do
731
- @client.info[:version].encoding.should eql(Encoding::US_ASCII)
732
- @client.info[:header_version].encoding.should eql(Encoding::US_ASCII)
738
+ expect(@client.info[:version].encoding).to eql(Encoding::US_ASCII)
739
+ expect(@client.info[:header_version].encoding).to eql(Encoding::US_ASCII)
733
740
  end
734
741
  end
735
742
 
@@ -737,62 +744,62 @@ describe Mysql2::Client do
737
744
  before { pending('Encoding is undefined') unless defined?(Encoding) }
738
745
 
739
746
  it "should be tagged as ascii" do
740
- Mysql2::Client.info[:version].encoding.should eql(Encoding::US_ASCII)
741
- Mysql2::Client.info[:header_version].encoding.should eql(Encoding::US_ASCII)
747
+ expect(Mysql2::Client.info[:version].encoding).to eql(Encoding::US_ASCII)
748
+ expect(Mysql2::Client.info[:header_version].encoding).to eql(Encoding::US_ASCII)
742
749
  end
743
750
  end
744
751
 
745
752
  it "should respond to #server_info" do
746
- @client.should respond_to(:server_info)
753
+ expect(@client).to respond_to(:server_info)
747
754
  end
748
755
 
749
756
  it "#server_info should return a hash containing the client version ID and String" do
750
757
  server_info = @client.server_info
751
- server_info.class.should eql(Hash)
752
- server_info.should have_key(:id)
753
- server_info[:id].class.should eql(Fixnum)
754
- server_info.should have_key(:version)
755
- server_info[:version].class.should eql(String)
758
+ expect(server_info.class).to eql(Hash)
759
+ expect(server_info).to have_key(:id)
760
+ expect(server_info[:id].class).to eql(Fixnum)
761
+ expect(server_info).to have_key(:version)
762
+ expect(server_info[:version].class).to eql(String)
756
763
  end
757
764
 
758
765
  it "#server_info should require an open connection" do
759
766
  @client.close
760
- lambda {
767
+ expect {
761
768
  @client.server_info
762
- }.should raise_error(Mysql2::Error)
769
+ }.to raise_error(Mysql2::Error)
763
770
  end
764
771
 
765
- if defined? Encoding
766
- context "strings returned by #server_info" do
767
- it "should default to the connection's encoding if Encoding.default_internal is nil" do
768
- with_internal_encoding nil do
769
- @client.server_info[:version].encoding.should eql(Encoding.find('utf-8'))
772
+ context "strings returned by #server_info" do
773
+ before { pending('Encoding is undefined') unless defined?(Encoding) }
770
774
 
771
- client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
772
- client2.server_info[:version].encoding.should eql(Encoding.find('us-ascii'))
773
- end
775
+ it "should default to the connection's encoding if Encoding.default_internal is nil" do
776
+ with_internal_encoding nil do
777
+ expect(@client.server_info[:version].encoding).to eql(Encoding::UTF_8)
778
+
779
+ client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
780
+ expect(client2.server_info[:version].encoding).to eql(Encoding::ASCII)
774
781
  end
782
+ end
775
783
 
776
- it "should use Encoding.default_internal" do
777
- with_internal_encoding 'utf-8' do
778
- @client.server_info[:version].encoding.should eql(Encoding.default_internal)
779
- end
784
+ it "should use Encoding.default_internal" do
785
+ with_internal_encoding Encoding::UTF_8 do
786
+ expect(@client.server_info[:version].encoding).to eql(Encoding.default_internal)
787
+ end
780
788
 
781
- with_internal_encoding 'us-ascii' do
782
- @client.server_info[:version].encoding.should eql(Encoding.default_internal)
783
- end
789
+ with_internal_encoding Encoding::ASCII do
790
+ expect(@client.server_info[:version].encoding).to eql(Encoding.default_internal)
784
791
  end
785
792
  end
786
793
  end
787
794
 
788
795
  it "should raise a Mysql2::Error exception upon connection failure" do
789
- lambda {
796
+ expect {
790
797
  Mysql2::Client.new :host => "localhost", :username => 'asdfasdf8d2h', :password => 'asdfasdfw42'
791
- }.should raise_error(Mysql2::Error)
798
+ }.to raise_error(Mysql2::Error)
792
799
 
793
- lambda {
800
+ expect {
794
801
  Mysql2::Client.new DatabaseCredentials['root']
795
- }.should_not raise_error(Mysql2::Error)
802
+ }.not_to raise_error
796
803
  end
797
804
 
798
805
  context 'write operations api' do
@@ -806,46 +813,46 @@ describe Mysql2::Client do
806
813
  end
807
814
 
808
815
  it "should respond to #last_id" do
809
- @client.should respond_to(:last_id)
816
+ expect(@client).to respond_to(:last_id)
810
817
  end
811
818
 
812
819
  it "#last_id should return a Fixnum, the from the last INSERT/UPDATE" do
813
- @client.last_id.should eql(0)
820
+ expect(@client.last_id).to eql(0)
814
821
  @client.query "INSERT INTO lastIdTest (blah) VALUES (1234)"
815
- @client.last_id.should eql(1)
822
+ expect(@client.last_id).to eql(1)
816
823
  end
817
824
 
818
825
  it "should respond to #last_id" do
819
- @client.should respond_to(:last_id)
826
+ expect(@client).to respond_to(:last_id)
820
827
  end
821
828
 
822
829
  it "#last_id should return a Fixnum, the from the last INSERT/UPDATE" do
823
830
  @client.query "INSERT INTO lastIdTest (blah) VALUES (1234)"
824
- @client.affected_rows.should eql(1)
831
+ expect(@client.affected_rows).to eql(1)
825
832
  @client.query "UPDATE lastIdTest SET blah=4321 WHERE id=1"
826
- @client.affected_rows.should eql(1)
833
+ expect(@client.affected_rows).to eql(1)
827
834
  end
828
835
 
829
836
  it "#last_id should handle BIGINT auto-increment ids above 32 bits" do
830
837
  # The id column type must be BIGINT. Surprise: INT(x) is limited to 32-bits for all values of x.
831
838
  # Insert a row with a given ID, this should raise the auto-increment state
832
839
  @client.query "INSERT INTO lastIdTest (id, blah) VALUES (5000000000, 5000)"
833
- @client.last_id.should eql(5000000000)
840
+ expect(@client.last_id).to eql(5000000000)
834
841
  @client.query "INSERT INTO lastIdTest (blah) VALUES (5001)"
835
- @client.last_id.should eql(5000000001)
842
+ expect(@client.last_id).to eql(5000000001)
836
843
  end
837
844
  end
838
845
 
839
846
  it "should respond to #thread_id" do
840
- @client.should respond_to(:thread_id)
847
+ expect(@client).to respond_to(:thread_id)
841
848
  end
842
849
 
843
850
  it "#thread_id should be a Fixnum" do
844
- @client.thread_id.class.should eql(Fixnum)
851
+ expect(@client.thread_id.class).to eql(Fixnum)
845
852
  end
846
853
 
847
854
  it "should respond to #ping" do
848
- @client.should respond_to(:ping)
855
+ expect(@client).to respond_to(:ping)
849
856
  end
850
857
 
851
858
  context "select_db" do
@@ -864,38 +871,38 @@ describe Mysql2::Client do
864
871
  end
865
872
 
866
873
  it "should respond to #select_db" do
867
- @client.should respond_to(:select_db)
874
+ expect(@client).to respond_to(:select_db)
868
875
  end
869
876
 
870
877
  it "should switch databases" do
871
878
  @client.select_db("test_selectdb_0")
872
- @client.query("SHOW TABLES").first.values.first.should eql("test0")
879
+ expect(@client.query("SHOW TABLES").first.values.first).to eql("test0")
873
880
  @client.select_db("test_selectdb_1")
874
- @client.query("SHOW TABLES").first.values.first.should eql("test1")
881
+ expect(@client.query("SHOW TABLES").first.values.first).to eql("test1")
875
882
  @client.select_db("test_selectdb_0")
876
- @client.query("SHOW TABLES").first.values.first.should eql("test0")
883
+ expect(@client.query("SHOW TABLES").first.values.first).to eql("test0")
877
884
  end
878
885
 
879
886
  it "should raise a Mysql2::Error when the database doesn't exist" do
880
- lambda {
887
+ expect {
881
888
  @client.select_db("nopenothere")
882
- }.should raise_error(Mysql2::Error)
889
+ }.to raise_error(Mysql2::Error)
883
890
  end
884
891
 
885
892
  it "should return the database switched to" do
886
- @client.select_db("test_selectdb_1").should eq("test_selectdb_1")
893
+ expect(@client.select_db("test_selectdb_1")).to eq("test_selectdb_1")
887
894
  end
888
895
  end
889
896
 
890
897
  it "#thread_id should return a boolean" do
891
- @client.ping.should eql(true)
898
+ expect(@client.ping).to eql(true)
892
899
  @client.close
893
- @client.ping.should eql(false)
900
+ expect(@client.ping).to eql(false)
894
901
  end
895
902
 
896
903
  unless RUBY_VERSION =~ /1.8/
897
904
  it "should respond to #encoding" do
898
- @client.should respond_to(:encoding)
905
+ expect(@client).to respond_to(:encoding)
899
906
  end
900
907
  end
901
908
  end