mysql2 0.3.21 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -0
  3. data/README.md +28 -6
  4. data/examples/eventmachine.rb +1 -1
  5. data/examples/threaded.rb +4 -6
  6. data/ext/mysql2/client.c +93 -84
  7. data/ext/mysql2/client.h +21 -1
  8. data/ext/mysql2/extconf.rb +60 -41
  9. data/ext/mysql2/infile.c +2 -2
  10. data/ext/mysql2/mysql2_ext.c +1 -0
  11. data/ext/mysql2/mysql2_ext.h +5 -6
  12. data/ext/mysql2/mysql_enc_name_to_ruby.h +2 -2
  13. data/ext/mysql2/mysql_enc_to_ruby.h +25 -22
  14. data/ext/mysql2/result.c +464 -97
  15. data/ext/mysql2/result.h +11 -4
  16. data/ext/mysql2/statement.c +491 -0
  17. data/ext/mysql2/statement.h +18 -0
  18. data/lib/mysql2/client.rb +32 -24
  19. data/lib/mysql2/console.rb +1 -1
  20. data/lib/mysql2/em.rb +5 -6
  21. data/lib/mysql2/error.rb +17 -26
  22. data/lib/mysql2/field.rb +3 -0
  23. data/lib/mysql2/statement.rb +17 -0
  24. data/lib/mysql2/version.rb +1 -1
  25. data/lib/mysql2.rb +37 -35
  26. data/spec/em/em_spec.rb +21 -21
  27. data/spec/mysql2/client_spec.rb +322 -290
  28. data/spec/mysql2/error_spec.rb +37 -36
  29. data/spec/mysql2/result_spec.rb +200 -209
  30. data/spec/mysql2/statement_spec.rb +684 -0
  31. data/spec/spec_helper.rb +7 -0
  32. data/spec/ssl/ca-cert.pem +17 -0
  33. data/spec/ssl/ca-key.pem +27 -0
  34. data/spec/ssl/ca.cnf +22 -0
  35. data/spec/ssl/cert.cnf +22 -0
  36. data/spec/ssl/client-cert.pem +17 -0
  37. data/spec/ssl/client-key.pem +27 -0
  38. data/spec/ssl/client-req.pem +15 -0
  39. data/spec/ssl/gen_certs.sh +48 -0
  40. data/spec/ssl/pkcs8-client-key.pem +28 -0
  41. data/spec/ssl/pkcs8-server-key.pem +28 -0
  42. data/spec/ssl/server-cert.pem +17 -0
  43. data/spec/ssl/server-key.pem +27 -0
  44. data/spec/ssl/server-req.pem +15 -0
  45. data/support/mysql_enc_to_ruby.rb +7 -8
  46. data/support/ruby_enc_to_mysql.rb +1 -1
  47. metadata +41 -47
@@ -1,66 +1,64 @@
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
49
47
  klient = Class.new(Mysql2::Client) do
50
48
  attr_reader :connect_args
51
- def connect *args
49
+ def connect(*args)
52
50
  @connect_args ||= []
53
51
  @connect_args << args
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
61
59
  klient = Class.new(Mysql2::Client) do
62
60
  attr_reader :connect_args
63
- def connect *args
61
+ def connect(*args)
64
62
  @connect_args ||= []
65
63
  @connect_args << args
66
64
  end
@@ -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,53 +104,75 @@ 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
124
119
  ssl = @client.query "SHOW VARIABLES LIKE 'have_ssl'"
125
- ssl_uncompiled = ssl.any? {|x| x['Value'] == 'OFF'}
120
+ ssl_uncompiled = ssl.any? { |x| x['Value'] == 'OFF' }
126
121
  pending("DON'T WORRY, THIS TEST PASSES - but SSL is not compiled into your MySQL daemon.") if ssl_uncompiled
127
- ssl_disabled = ssl.any? {|x| x['Value'] == 'DISABLED'}
122
+ ssl_disabled = ssl.any? { |x| x['Value'] == 'DISABLED' }
128
123
  pending("DON'T WORRY, THIS TEST PASSES - but SSL is not enabled in your MySQL daemon.") if ssl_disabled
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 {
128
+ # rubocop:disable Style/TrailingComma
133
129
  ssl_client = Mysql2::Client.new(
134
- :sslkey => '/etc/mysql/client-key.pem',
135
- :sslcert => '/etc/mysql/client-cert.pem',
136
- :sslca => '/etc/mysql/ca-cert.pem',
137
- :sslcapath => '/etc/mysql/',
138
- :sslcipher => 'DHE-RSA-AES256-SHA'
130
+ DatabaseCredentials['root'].merge(
131
+ 'host' => 'mysql2gem.example.com', # must match the certificates
132
+ :sslkey => '/etc/mysql/client-key.pem',
133
+ :sslcert => '/etc/mysql/client-cert.pem',
134
+ :sslca => '/etc/mysql/ca-cert.pem',
135
+ :sslcipher => 'DHE-RSA-AES256-SHA',
136
+ :sslverify => true
137
+ )
139
138
  )
140
- }.should_not raise_error(Mysql2::Error)
139
+ # rubocop:enable Style/TrailingComma
140
+ }.not_to raise_error
141
141
 
142
142
  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
143
+ expect(results[0]['Variable_name']).to eql('Ssl_cipher')
144
+ expect(results[0]['Value']).not_to be_nil
145
+ expect(results[0]['Value']).to be_an_instance_of(String)
146
+ expect(results[0]['Value']).not_to be_empty
147
147
 
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
148
+ expect(results[1]['Variable_name']).to eql('Ssl_version')
149
+ expect(results[1]['Value']).not_to be_nil
150
+ expect(results[1]['Value']).to be_an_instance_of(String)
151
+ expect(results[1]['Value']).not_to be_empty
152
152
 
153
153
  ssl_client.close
154
154
  end
155
155
 
156
+ def run_gc
157
+ if defined?(Rubinius)
158
+ GC.run(true)
159
+ else
160
+ GC.start
161
+ end
162
+ sleep(0.5)
163
+ end
164
+
165
+ it "should terminate connections when calling close" do
166
+ expect {
167
+ Mysql2::Client.new(DatabaseCredentials['root']).close
168
+ }.to_not change {
169
+ @client.query("SHOW STATUS LIKE 'Aborted_clients'").first['Value'].to_i
170
+ }
171
+ end
172
+
156
173
  it "should not leave dangling connections after garbage collection" do
157
- GC.start
158
- sleep 0.300 # Let GC do its work
174
+ run_gc
175
+
159
176
  client = Mysql2::Client.new(DatabaseCredentials['root'])
160
177
  before_count = client.query("SHOW STATUS LIKE 'Threads_connected'").first['Value'].to_i
161
178
 
@@ -163,69 +180,70 @@ describe Mysql2::Client do
163
180
  Mysql2::Client.new(DatabaseCredentials['root']).query('SELECT 1')
164
181
  end
165
182
  after_count = client.query("SHOW STATUS LIKE 'Threads_connected'").first['Value'].to_i
166
- after_count.should == before_count + 10
183
+ expect(after_count).to eq(before_count + 10)
167
184
 
168
- GC.start
169
- sleep 0.300 # Let GC do its work
185
+ run_gc
170
186
  final_count = client.query("SHOW STATUS LIKE 'Threads_connected'").first['Value'].to_i
171
- final_count.should == before_count
187
+ expect(final_count).to eq(before_count)
172
188
  end
173
189
 
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'])
190
+ it "should not close connections when running in a child process" do
191
+ pending("fork is not available on this platform") unless Process.respond_to?(:fork)
179
192
 
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
193
+ run_gc
194
+ client = Mysql2::Client.new(DatabaseCredentials['root'])
186
195
 
187
- Process.wait
196
+ # this empty `fork` call fixes this tests on RBX; without it, the next
197
+ # `fork` call hangs forever. WTF?
198
+ fork {}
188
199
 
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
200
+ fork do
201
+ client.query('SELECT 1')
202
+ client = nil
203
+ run_gc
192
204
  end
205
+
206
+ Process.wait
207
+
208
+ # this will throw an error if the underlying socket was shutdown by the
209
+ # child's GC
210
+ expect { client.query('SELECT 1') }.to_not raise_exception
193
211
  end
194
212
 
195
213
  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
214
+ creds = DatabaseCredentials['numericuser']
215
+ @client.query "CREATE DATABASE IF NOT EXISTS `#{creds['database']}`"
216
+ @client.query "GRANT ALL ON `#{creds['database']}`.* TO #{creds['username']}@`#{creds['host']}`"
217
+
218
+ expect { Mysql2::Client.new(creds) }.not_to raise_error
219
+
220
+ @client.query "DROP DATABASE IF EXISTS `#{creds['database']}`"
203
221
  end
204
222
 
205
223
  it "should respond to #close" do
206
- @client.should respond_to(:close)
224
+ expect(@client).to respond_to(:close)
207
225
  end
208
226
 
209
227
  it "should be able to close properly" do
210
- @client.close.should be_nil
211
- lambda {
228
+ expect(@client.close).to be_nil
229
+ expect {
212
230
  @client.query "SELECT 1"
213
- }.should raise_error(Mysql2::Error)
231
+ }.to raise_error(Mysql2::Error)
214
232
  end
215
233
 
216
234
  it "should respond to #query" do
217
- @client.should respond_to(:query)
235
+ expect(@client).to respond_to(:query)
218
236
  end
219
237
 
220
238
  it "should respond to #warning_count" do
221
- @client.should respond_to(:warning_count)
239
+ expect(@client).to respond_to(:warning_count)
222
240
  end
223
241
 
224
242
  context "#warning_count" do
225
243
  context "when no warnings" do
226
244
  it "should 0" do
227
245
  @client.query('select 1')
228
- @client.warning_count.should == 0
246
+ expect(@client.warning_count).to eq(0)
229
247
  end
230
248
  end
231
249
  context "when has a warnings" do
@@ -233,21 +251,21 @@ describe Mysql2::Client do
233
251
  # "the statement produces extra information that can be viewed by issuing a SHOW WARNINGS"
234
252
  # http://dev.mysql.com/doc/refman/5.0/en/explain-extended.html
235
253
  @client.query("explain extended select 1")
236
- @client.warning_count.should > 0
254
+ expect(@client.warning_count).to be > 0
237
255
  end
238
256
  end
239
257
  end
240
258
 
241
259
  it "should respond to #query_info" do
242
- @client.should respond_to(:query_info)
260
+ expect(@client).to respond_to(:query_info)
243
261
  end
244
262
 
245
263
  context "#query_info" do
246
264
  context "when no info present" do
247
265
  it "should 0" do
248
266
  @client.query('select 1')
249
- @client.query_info.should be_empty
250
- @client.query_info_string.should be_nil
267
+ expect(@client.query_info).to be_empty
268
+ expect(@client.query_info_string).to be_nil
251
269
  end
252
270
  end
253
271
  context "when has some info" do
@@ -259,8 +277,8 @@ describe Mysql2::Client do
259
277
  # # 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
278
  @client.query("INSERT INTO infoTest (blah) VALUES (1234),(4535)")
261
279
 
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')
280
+ expect(@client.query_info).to eql(:records => 2, :duplicates => 0, :warnings => 0)
281
+ expect(@client.query_info_string).to eq('Records: 2 Duplicates: 0 Warnings: 0')
264
282
 
265
283
  @client.query "DROP TABLE infoTest"
266
284
  end
@@ -271,7 +289,7 @@ describe Mysql2::Client do
271
289
  before(:all) do
272
290
  @client_i = Mysql2::Client.new DatabaseCredentials['root'].merge(:local_infile => true)
273
291
  local = @client_i.query "SHOW VARIABLES LIKE 'local_infile'"
274
- local_enabled = local.any? {|x| x['Value'] == 'ON'}
292
+ local_enabled = local.any? { |x| x['Value'] == 'ON' }
275
293
  pending("DON'T WORRY, THIS TEST PASSES - but LOCAL INFILE is not enabled in your MySQL daemon.") unless local_enabled
276
294
 
277
295
  @client_i.query %[
@@ -289,43 +307,43 @@ describe Mysql2::Client do
289
307
 
290
308
  it "should raise an error when local_infile is disabled" do
291
309
  client = Mysql2::Client.new DatabaseCredentials['root'].merge(:local_infile => false)
292
- lambda {
310
+ expect {
293
311
  client.query "LOAD DATA LOCAL INFILE 'spec/test_data' INTO TABLE infileTest"
294
- }.should raise_error(Mysql2::Error, %r{command is not allowed})
312
+ }.to raise_error(Mysql2::Error, /command is not allowed/)
295
313
  end
296
314
 
297
315
  it "should raise an error when a non-existent file is loaded" do
298
- lambda {
316
+ expect {
299
317
  @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})
318
+ }.to raise_error(Mysql2::Error, 'No such file or directory: this/file/is/not/here')
301
319
  end
302
320
 
303
321
  it "should LOAD DATA LOCAL INFILE" do
304
322
  @client_i.query "LOAD DATA LOCAL INFILE 'spec/test_data' INTO TABLE infileTest"
305
323
  info = @client_i.query_info
306
- info.should eql({:records => 1, :deleted => 0, :skipped => 0, :warnings => 0})
324
+ expect(info).to eql(:records => 1, :deleted => 0, :skipped => 0, :warnings => 0)
307
325
 
308
326
  result = @client_i.query "SELECT * FROM infileTest"
309
- result.first.should eql({'id' => 1, 'foo' => 'Hello', 'bar' => 'World'})
327
+ expect(result.first).to eql('id' => 1, 'foo' => 'Hello', 'bar' => 'World')
310
328
  end
311
329
  end
312
330
 
313
331
  it "should expect connect_timeout to be a positive integer" do
314
- lambda {
332
+ expect {
315
333
  Mysql2::Client.new(:connect_timeout => -1)
316
- }.should raise_error(Mysql2::Error)
334
+ }.to raise_error(Mysql2::Error)
317
335
  end
318
336
 
319
337
  it "should expect read_timeout to be a positive integer" do
320
- lambda {
338
+ expect {
321
339
  Mysql2::Client.new(:read_timeout => -1)
322
- }.should raise_error(Mysql2::Error)
340
+ }.to raise_error(Mysql2::Error)
323
341
  end
324
342
 
325
343
  it "should expect write_timeout to be a positive integer" do
326
- lambda {
344
+ expect {
327
345
  Mysql2::Client.new(:write_timeout => -1)
328
- }.should raise_error(Mysql2::Error)
346
+ }.to raise_error(Mysql2::Error)
329
347
  end
330
348
 
331
349
  context "#query" do
@@ -334,7 +352,7 @@ describe Mysql2::Client do
334
352
 
335
353
  expect {
336
354
  @client.query("SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false)
337
- }.to_not raise_exception(Mysql2::Error)
355
+ }.to_not raise_error
338
356
  end
339
357
 
340
358
  it "should not let you query again if iterating is not finished when streaming" do
@@ -346,126 +364,135 @@ describe Mysql2::Client do
346
364
  end
347
365
 
348
366
  it "should only accept strings as the query parameter" do
349
- lambda {
367
+ expect {
350
368
  @client.query ["SELECT 'not right'"]
351
- }.should raise_error(TypeError)
369
+ }.to raise_error(TypeError)
352
370
  end
353
371
 
354
372
  it "should not retain query options set on a query for subsequent queries, but should retain it in the result" do
355
373
  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))
374
+ expect(@client.query_options[:something]).to be_nil
375
+ expect(result.instance_variable_get('@query_options')).to eql(@client.query_options.merge(:something => :else))
376
+ expect(@client.instance_variable_get('@current_query_options')).to eql(@client.query_options.merge(:something => :else))
359
377
 
360
378
  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)
379
+ expect(result.instance_variable_get('@query_options')).to eql(@client.query_options)
380
+ expect(@client.instance_variable_get('@current_query_options')).to eql(@client.query_options)
363
381
  end
364
382
 
365
383
  it "should allow changing query options for subsequent queries" do
366
384
  @client.query_options.merge!(:something => :else)
367
385
  result = @client.query "SELECT 1"
368
- @client.query_options[:something].should eql(:else)
369
- result.instance_variable_get('@query_options')[:something].should eql(:else)
386
+ expect(@client.query_options[:something]).to eql(:else)
387
+ expect(result.instance_variable_get('@query_options')[:something]).to eql(:else)
370
388
 
371
389
  # Clean up after this test
372
390
  @client.query_options.delete(:something)
373
- @client.query_options[:something].should be_nil
391
+ expect(@client.query_options[:something]).to be_nil
374
392
  end
375
393
 
376
394
  it "should return results as a hash by default" do
377
- @client.query("SELECT 1").first.class.should eql(Hash)
395
+ expect(@client.query("SELECT 1").first).to be_an_instance_of(Hash)
378
396
  end
379
397
 
380
398
  it "should be able to return results as an array" do
381
- @client.query("SELECT 1", :as => :array).first.class.should eql(Array)
399
+ expect(@client.query("SELECT 1", :as => :array).first).to be_an_instance_of(Array)
382
400
  @client.query("SELECT 1").each(:as => :array)
383
401
  end
384
402
 
385
403
  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)
404
+ expect(@client.query("SELECT 1", :symbolize_keys => true).first.keys[0]).to be_an_instance_of(Symbol)
387
405
  end
388
406
 
389
407
  it "should require an open connection" do
390
408
  @client.close
391
- lambda {
409
+ expect {
392
410
  @client.query "SELECT 1"
393
- }.should raise_error(Mysql2::Error)
411
+ }.to raise_error(Mysql2::Error)
394
412
  end
395
413
 
396
414
  if RUBY_PLATFORM !~ /mingw|mswin/
397
415
  it "should not allow another query to be sent without fetching a result first" do
398
416
  @client.query("SELECT 1", :async => true)
399
- lambda {
417
+ expect {
400
418
  @client.query("SELECT 1")
401
- }.should raise_error(Mysql2::Error)
419
+ }.to raise_error(Mysql2::Error)
402
420
  end
403
421
 
404
422
  it "should describe the thread holding the active query" do
405
423
  thr = Thread.new { @client.query("SELECT 1", :async => true) }
406
424
 
407
425
  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))
426
+ expect { @client.query('SELECT 1') }.to raise_error(Mysql2::Error, Regexp.new(Regexp.escape(thr.inspect)))
415
427
  end
416
428
 
417
429
  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)
422
- end
423
-
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')
430
+ client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:read_timeout => 0))
431
+ expect {
432
+ client.query('SELECT SLEEP(0.1)')
433
+ }.to raise_error(Mysql2::Error)
434
+ end
435
+
436
+ # XXX this test is not deterministic (because Unix signal handling is not)
437
+ # and may fail on a loaded system
438
+ it "should run signal handlers while waiting for a response" do
439
+ kill_time = 0.1
440
+ query_time = 2 * kill_time
441
+
442
+ mark = {}
443
+
444
+ begin
445
+ trap(:USR1) { mark.store(:USR1, Time.now) }
446
+ pid = fork do
447
+ sleep kill_time # wait for client query to start
448
+ Process.kill(:USR1, Process.ppid)
449
+ sleep # wait for explicit kill to prevent GC disconnect
449
450
  end
451
+ mark.store(:QUERY_START, Time.now)
452
+ @client.query("SELECT SLEEP(#{query_time})")
453
+ mark.store(:QUERY_END, Time.now)
454
+ ensure
455
+ Process.kill(:TERM, pid)
456
+ Process.waitpid2(pid)
457
+ trap(:USR1, 'DEFAULT')
450
458
  end
459
+
460
+ # the query ran uninterrupted
461
+ expect(mark.fetch(:QUERY_END) - mark.fetch(:QUERY_START)).to be_within(0.02).of(query_time)
462
+ # signals fired while the query was running
463
+ expect(mark.fetch(:USR1)).to be_between(mark.fetch(:QUERY_START), mark.fetch(:QUERY_END))
451
464
  end
452
465
 
453
466
  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)
467
+ expect(@client.socket).to be_an_instance_of(Fixnum)
468
+ expect(@client.socket).not_to eql(0)
456
469
  end
457
470
 
458
471
  it "#socket should require an open connection" do
459
472
  @client.close
460
- lambda {
473
+ expect {
461
474
  @client.socket
462
- }.should raise_error(Mysql2::Error)
475
+ }.to raise_error(Mysql2::Error)
463
476
  end
464
477
 
465
478
  it 'should be impervious to connection-corrupting timeouts in #query' do
466
479
  pending('`Thread.handle_interrupt` is not defined') unless Thread.respond_to?(:handle_interrupt)
467
480
  # attempt to break the connection
468
- expect { Timeout.timeout(0.1) { @client.query('SELECT SLEEP(1)') } }.to raise_error(Timeout::Error)
481
+ expect { Timeout.timeout(0.1) { @client.query('SELECT SLEEP(0.2)') } }.to raise_error(Timeout::Error)
482
+
483
+ # expect the connection to not be broken
484
+ expect { @client.query('SELECT 1') }.to_not raise_error
485
+ end
486
+
487
+ it 'should be impervious to connection-corrupting timeouts in #execute' do
488
+ # the statement handle gets corrupted and will segfault the tests if interrupted,
489
+ # so we can't even use pending on this test, really have to skip it on older Rubies.
490
+ skip('`Thread.handle_interrupt` is not defined') unless Thread.respond_to?(:handle_interrupt)
491
+
492
+ # attempt to break the connection
493
+ stmt = @client.prepare('SELECT SLEEP(?)')
494
+ expect { Timeout.timeout(0.1) { stmt.execute(0.2) } }.to raise_error(Timeout::Error)
495
+ stmt.close
469
496
 
470
497
  # expect the connection to not be broken
471
498
  expect { @client.query('SELECT 1') }.to_not raise_error
@@ -478,13 +505,21 @@ describe Mysql2::Client do
478
505
  end
479
506
 
480
507
  it "should handle Timeouts without leaving the connection hanging if reconnect is true" do
508
+ if RUBY_PLATFORM.include?('darwin') && Mysql2::Client.info.fetch(:version).start_with?('5.5')
509
+ pending('libmysqlclient 5.5 on OSX is afflicted by an unknown bug that breaks this test. See #633 and #634.')
510
+ end
511
+
481
512
  client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:reconnect => true))
482
513
 
483
514
  expect { Timeout.timeout(0.1, ArgumentError) { client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
484
515
  expect { client.query('SELECT 1') }.to_not raise_error
485
516
  end
486
517
 
487
- it "should handle Timeouts without leaving the connection hanging if reconnect is set to true after construction true" do
518
+ it "should handle Timeouts without leaving the connection hanging if reconnect is set to true after construction" do
519
+ if RUBY_PLATFORM.include?('darwin') && Mysql2::Client.info.fetch(:version).start_with?('5.5')
520
+ pending('libmysqlclient 5.5 on OSX is afflicted by an unknown bug that breaks this test. See #633 and #634.')
521
+ end
522
+
488
523
  client = Mysql2::Client.new(DatabaseCredentials['root'])
489
524
 
490
525
  expect { Timeout.timeout(0.1, ArgumentError) { client.query('SELECT SLEEP(1)') } }.to raise_error(ArgumentError)
@@ -498,28 +533,27 @@ describe Mysql2::Client do
498
533
  end
499
534
 
500
535
  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
- }
536
+ sleep_time = 0.5
537
+
538
+ # Note that each thread opens its own database connection
539
+ threads = 5.times.map do
540
+ Thread.new do
541
+ client = Mysql2::Client.new(DatabaseCredentials.fetch('root'))
542
+ client.query("SELECT SLEEP(#{sleep_time})")
543
+ Thread.current.object_id
544
+ end
515
545
  end
516
- threads.each{|t| t.join }
517
- results.keys.sort.should eql(threads.map{|t| t.object_id }.sort)
546
+
547
+ # This timeout demonstrates that the threads are sleeping concurrently:
548
+ # In the serial case, the timeout would fire and the test would fail
549
+ values = Timeout.timeout(sleep_time * 1.1) { threads.map(&:value) }
550
+
551
+ expect(values).to match_array(threads.map(&:object_id))
518
552
  end
519
553
 
520
554
  it "evented async queries should be supported" do
521
555
  # should immediately return nil
522
- @client.query("SELECT sleep(0.1)", :async => true).should eql(nil)
556
+ expect(@client.query("SELECT sleep(0.1)", :async => true)).to eql(nil)
523
557
 
524
558
  io_wrapper = IO.for_fd(@client.socket)
525
559
  loops = 0
@@ -532,10 +566,10 @@ describe Mysql2::Client do
532
566
  end
533
567
 
534
568
  # make sure we waited some period of time
535
- (loops >= 1).should be_true
569
+ expect(loops >= 1).to be true
536
570
 
537
571
  result = @client.async_result
538
- result.class.should eql(Mysql2::Result)
572
+ expect(result).to be_an_instance_of(Mysql2::Result)
539
573
  end
540
574
  end
541
575
 
@@ -546,155 +580,153 @@ describe Mysql2::Client do
546
580
 
547
581
  it "should raise an exception when one of multiple statements fails" do
548
582
  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 {
583
+ expect(result.first['set_1']).to be(1)
584
+ expect {
551
585
  @multi_client.next_result
552
- }.should raise_error(Mysql2::Error)
553
- @multi_client.next_result.should be_false
586
+ }.to raise_error(Mysql2::Error)
587
+ expect(@multi_client.next_result).to be false
554
588
  end
555
589
 
556
590
  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 })
591
+ expect(@multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'").first).to eql('set_1' => 1)
558
592
 
559
- @multi_client.next_result.should be_true
560
- @multi_client.store_result.first.should eql({ 'set_2' => 2 })
593
+ expect(@multi_client.next_result).to be true
594
+ expect(@multi_client.store_result.first).to eql('set_2' => 2)
561
595
 
562
- @multi_client.next_result.should be_false
596
+ expect(@multi_client.next_result).to be false
563
597
  end
564
598
 
565
599
  it "does not interfere with other statements" do
566
600
  @multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'")
567
- while( @multi_client.next_result )
568
- @multi_client.store_result
569
- end
601
+ @multi_client.store_result while @multi_client.next_result
570
602
 
571
- @multi_client.query("SELECT 3 AS 'next'").first.should == { 'next' => 3 }
603
+ expect(@multi_client.query("SELECT 3 AS 'next'").first).to eq('next' => 3)
572
604
  end
573
605
 
574
606
  it "will raise on query if there are outstanding results to read" do
575
607
  @multi_client.query("SELECT 1; SELECT 2; SELECT 3")
576
- lambda {
608
+ expect {
577
609
  @multi_client.query("SELECT 4")
578
- }.should raise_error(Mysql2::Error)
610
+ }.to raise_error(Mysql2::Error)
579
611
  end
580
612
 
581
613
  it "#abandon_results! should work" do
582
614
  @multi_client.query("SELECT 1; SELECT 2; SELECT 3")
583
615
  @multi_client.abandon_results!
584
- lambda {
616
+ expect {
585
617
  @multi_client.query("SELECT 4")
586
- }.should_not raise_error(Mysql2::Error)
618
+ }.not_to raise_error
587
619
  end
588
620
 
589
621
  it "#more_results? should work" do
590
622
  @multi_client.query("SELECT 1 AS 'set_1'; SELECT 2 AS 'set_2'")
591
- @multi_client.more_results?.should be_true
623
+ expect(@multi_client.more_results?).to be true
592
624
 
593
625
  @multi_client.next_result
594
626
  @multi_client.store_result
595
627
 
596
- @multi_client.more_results?.should be_false
628
+ expect(@multi_client.more_results?).to be false
597
629
  end
598
630
 
599
631
  it "#more_results? should work with stored procedures" do
600
632
  @multi_client.query("DROP PROCEDURE IF EXISTS test_proc")
601
633
  @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
634
+ expect(@multi_client.query("CALL test_proc()").first).to eql('set_1' => 1)
635
+ expect(@multi_client.more_results?).to be true
604
636
 
605
637
  @multi_client.next_result
606
- @multi_client.store_result.first.should eql({ 'set_2' => 2 })
638
+ expect(@multi_client.store_result.first).to eql('set_2' => 2)
607
639
 
608
640
  @multi_client.next_result
609
- @multi_client.store_result.should be_nil # this is the result from CALL itself
641
+ expect(@multi_client.store_result).to be_nil # this is the result from CALL itself
610
642
 
611
- @multi_client.more_results?.should be_false
643
+ expect(@multi_client.more_results?).to be false
612
644
  end
613
645
  end
614
646
  end
615
647
 
616
648
  it "should respond to #socket" do
617
- @client.should respond_to(:socket)
649
+ expect(@client).to respond_to(:socket)
618
650
  end
619
651
 
620
652
  if RUBY_PLATFORM =~ /mingw|mswin/
621
653
  it "#socket should raise as it's not supported" do
622
- lambda {
654
+ expect {
623
655
  @client.socket
624
- }.should raise_error(Mysql2::Error)
656
+ }.to raise_error(Mysql2::Error)
625
657
  end
626
658
  end
627
659
 
628
660
  it "should respond to escape" do
629
- Mysql2::Client.should respond_to(:escape)
661
+ expect(Mysql2::Client).to respond_to(:escape)
630
662
  end
631
663
 
632
664
  context "escape" do
633
665
  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")
666
+ expect(Mysql2::Client.escape("abc'def\"ghi\0jkl%mno")).to eql("abc\\'def\\\"ghi\\0jkl%mno")
635
667
  end
636
668
 
637
669
  it "should return the passed string if nothing was escaped" do
638
670
  str = "plain"
639
- Mysql2::Client.escape(str).object_id.should eql(str.object_id)
671
+ expect(Mysql2::Client.escape(str).object_id).to eql(str.object_id)
640
672
  end
641
673
 
642
674
  it "should not overflow the thread stack" do
643
- lambda {
675
+ expect {
644
676
  Thread.new { Mysql2::Client.escape("'" * 256 * 1024) }.join
645
- }.should_not raise_error(SystemStackError)
677
+ }.not_to raise_error
646
678
  end
647
679
 
648
680
  it "should not overflow the process stack" do
649
- lambda {
681
+ expect {
650
682
  Thread.new { Mysql2::Client.escape("'" * 1024 * 1024 * 4) }.join
651
- }.should_not raise_error(SystemStackError)
683
+ }.not_to raise_error
652
684
  end
653
685
 
654
686
  unless RUBY_VERSION =~ /1.8/
655
687
  it "should carry over the original string's encoding" do
656
688
  str = "abc'def\"ghi\0jkl%mno"
657
689
  escaped = Mysql2::Client.escape(str)
658
- escaped.encoding.should eql(str.encoding)
690
+ expect(escaped.encoding).to eql(str.encoding)
659
691
 
660
692
  str.encode!('us-ascii')
661
693
  escaped = Mysql2::Client.escape(str)
662
- escaped.encoding.should eql(str.encoding)
694
+ expect(escaped.encoding).to eql(str.encoding)
663
695
  end
664
696
  end
665
697
  end
666
698
 
667
699
  it "should respond to #escape" do
668
- @client.should respond_to(:escape)
700
+ expect(@client).to respond_to(:escape)
669
701
  end
670
702
 
671
703
  context "#escape" do
672
704
  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")
705
+ expect(@client.escape("abc'def\"ghi\0jkl%mno")).to eql("abc\\'def\\\"ghi\\0jkl%mno")
674
706
  end
675
707
 
676
708
  it "should return the passed string if nothing was escaped" do
677
709
  str = "plain"
678
- @client.escape(str).object_id.should eql(str.object_id)
710
+ expect(@client.escape(str).object_id).to eql(str.object_id)
679
711
  end
680
712
 
681
713
  it "should not overflow the thread stack" do
682
- lambda {
714
+ expect {
683
715
  Thread.new { @client.escape("'" * 256 * 1024) }.join
684
- }.should_not raise_error(SystemStackError)
716
+ }.not_to raise_error
685
717
  end
686
718
 
687
719
  it "should not overflow the process stack" do
688
- lambda {
720
+ expect {
689
721
  Thread.new { @client.escape("'" * 1024 * 1024 * 4) }.join
690
- }.should_not raise_error(SystemStackError)
722
+ }.not_to raise_error
691
723
  end
692
724
 
693
725
  it "should require an open connection" do
694
726
  @client.close
695
- lambda {
727
+ expect {
696
728
  @client.escape ""
697
- }.should raise_error(Mysql2::Error)
729
+ }.to raise_error(Mysql2::Error)
698
730
  end
699
731
 
700
732
  context 'when mysql encoding is not utf8' do
@@ -704,32 +736,32 @@ describe Mysql2::Client do
704
736
 
705
737
  it 'should return a internal encoding string if Encoding.default_internal is set' do
706
738
  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}")
739
+ expect(client.escape("\u{30C6}\u{30B9}\u{30C8}")).to eq "\u{30C6}\u{30B9}\u{30C8}"
740
+ expect(client.escape("\u{30C6}'\u{30B9}\"\u{30C8}")).to eq "\u{30C6}\\'\u{30B9}\\\"\u{30C8}"
709
741
  end
710
742
  end
711
743
  end
712
744
  end
713
745
 
714
746
  it "should respond to #info" do
715
- @client.should respond_to(:info)
747
+ expect(@client).to respond_to(:info)
716
748
  end
717
749
 
718
750
  it "#info should return a hash containing the client version ID and String" do
719
751
  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)
752
+ expect(info).to be_an_instance_of(Hash)
753
+ expect(info).to have_key(:id)
754
+ expect(info[:id]).to be_an_instance_of(Fixnum)
755
+ expect(info).to have_key(:version)
756
+ expect(info[:version]).to be_an_instance_of(String)
725
757
  end
726
758
 
727
759
  context "strings returned by #info" do
728
760
  before { pending('Encoding is undefined') unless defined?(Encoding) }
729
761
 
730
762
  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)
763
+ expect(@client.info[:version].encoding).to eql(Encoding::US_ASCII)
764
+ expect(@client.info[:header_version].encoding).to eql(Encoding::US_ASCII)
733
765
  end
734
766
  end
735
767
 
@@ -737,62 +769,62 @@ describe Mysql2::Client do
737
769
  before { pending('Encoding is undefined') unless defined?(Encoding) }
738
770
 
739
771
  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)
772
+ expect(Mysql2::Client.info[:version].encoding).to eql(Encoding::US_ASCII)
773
+ expect(Mysql2::Client.info[:header_version].encoding).to eql(Encoding::US_ASCII)
742
774
  end
743
775
  end
744
776
 
745
777
  it "should respond to #server_info" do
746
- @client.should respond_to(:server_info)
778
+ expect(@client).to respond_to(:server_info)
747
779
  end
748
780
 
749
781
  it "#server_info should return a hash containing the client version ID and String" do
750
782
  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)
783
+ expect(server_info).to be_an_instance_of(Hash)
784
+ expect(server_info).to have_key(:id)
785
+ expect(server_info[:id]).to be_an_instance_of(Fixnum)
786
+ expect(server_info).to have_key(:version)
787
+ expect(server_info[:version]).to be_an_instance_of(String)
756
788
  end
757
789
 
758
790
  it "#server_info should require an open connection" do
759
791
  @client.close
760
- lambda {
792
+ expect {
761
793
  @client.server_info
762
- }.should raise_error(Mysql2::Error)
794
+ }.to raise_error(Mysql2::Error)
763
795
  end
764
796
 
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'))
797
+ context "strings returned by #server_info" do
798
+ before { pending('Encoding is undefined') unless defined?(Encoding) }
770
799
 
771
- client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
772
- client2.server_info[:version].encoding.should eql(Encoding.find('us-ascii'))
773
- end
800
+ it "should default to the connection's encoding if Encoding.default_internal is nil" do
801
+ with_internal_encoding nil do
802
+ expect(@client.server_info[:version].encoding).to eql(Encoding::UTF_8)
803
+
804
+ client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii'))
805
+ expect(client2.server_info[:version].encoding).to eql(Encoding::ASCII)
774
806
  end
807
+ end
775
808
 
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
809
+ it "should use Encoding.default_internal" do
810
+ with_internal_encoding Encoding::UTF_8 do
811
+ expect(@client.server_info[:version].encoding).to eql(Encoding.default_internal)
812
+ end
780
813
 
781
- with_internal_encoding 'us-ascii' do
782
- @client.server_info[:version].encoding.should eql(Encoding.default_internal)
783
- end
814
+ with_internal_encoding Encoding::ASCII do
815
+ expect(@client.server_info[:version].encoding).to eql(Encoding.default_internal)
784
816
  end
785
817
  end
786
818
  end
787
819
 
788
820
  it "should raise a Mysql2::Error exception upon connection failure" do
789
- lambda {
821
+ expect {
790
822
  Mysql2::Client.new :host => "localhost", :username => 'asdfasdf8d2h', :password => 'asdfasdfw42'
791
- }.should raise_error(Mysql2::Error)
823
+ }.to raise_error(Mysql2::Error)
792
824
 
793
- lambda {
825
+ expect {
794
826
  Mysql2::Client.new DatabaseCredentials['root']
795
- }.should_not raise_error(Mysql2::Error)
827
+ }.not_to raise_error
796
828
  end
797
829
 
798
830
  context 'write operations api' do
@@ -806,46 +838,46 @@ describe Mysql2::Client do
806
838
  end
807
839
 
808
840
  it "should respond to #last_id" do
809
- @client.should respond_to(:last_id)
841
+ expect(@client).to respond_to(:last_id)
810
842
  end
811
843
 
812
844
  it "#last_id should return a Fixnum, the from the last INSERT/UPDATE" do
813
- @client.last_id.should eql(0)
845
+ expect(@client.last_id).to eql(0)
814
846
  @client.query "INSERT INTO lastIdTest (blah) VALUES (1234)"
815
- @client.last_id.should eql(1)
847
+ expect(@client.last_id).to eql(1)
816
848
  end
817
849
 
818
850
  it "should respond to #last_id" do
819
- @client.should respond_to(:last_id)
851
+ expect(@client).to respond_to(:last_id)
820
852
  end
821
853
 
822
854
  it "#last_id should return a Fixnum, the from the last INSERT/UPDATE" do
823
855
  @client.query "INSERT INTO lastIdTest (blah) VALUES (1234)"
824
- @client.affected_rows.should eql(1)
856
+ expect(@client.affected_rows).to eql(1)
825
857
  @client.query "UPDATE lastIdTest SET blah=4321 WHERE id=1"
826
- @client.affected_rows.should eql(1)
858
+ expect(@client.affected_rows).to eql(1)
827
859
  end
828
860
 
829
861
  it "#last_id should handle BIGINT auto-increment ids above 32 bits" do
830
862
  # The id column type must be BIGINT. Surprise: INT(x) is limited to 32-bits for all values of x.
831
863
  # Insert a row with a given ID, this should raise the auto-increment state
832
864
  @client.query "INSERT INTO lastIdTest (id, blah) VALUES (5000000000, 5000)"
833
- @client.last_id.should eql(5000000000)
865
+ expect(@client.last_id).to eql(5000000000)
834
866
  @client.query "INSERT INTO lastIdTest (blah) VALUES (5001)"
835
- @client.last_id.should eql(5000000001)
867
+ expect(@client.last_id).to eql(5000000001)
836
868
  end
837
869
  end
838
870
 
839
871
  it "should respond to #thread_id" do
840
- @client.should respond_to(:thread_id)
872
+ expect(@client).to respond_to(:thread_id)
841
873
  end
842
874
 
843
875
  it "#thread_id should be a Fixnum" do
844
- @client.thread_id.class.should eql(Fixnum)
876
+ expect(@client.thread_id).to be_an_instance_of(Fixnum)
845
877
  end
846
878
 
847
879
  it "should respond to #ping" do
848
- @client.should respond_to(:ping)
880
+ expect(@client).to respond_to(:ping)
849
881
  end
850
882
 
851
883
  context "select_db" do
@@ -864,38 +896,38 @@ describe Mysql2::Client do
864
896
  end
865
897
 
866
898
  it "should respond to #select_db" do
867
- @client.should respond_to(:select_db)
899
+ expect(@client).to respond_to(:select_db)
868
900
  end
869
901
 
870
902
  it "should switch databases" do
871
903
  @client.select_db("test_selectdb_0")
872
- @client.query("SHOW TABLES").first.values.first.should eql("test0")
904
+ expect(@client.query("SHOW TABLES").first.values.first).to eql("test0")
873
905
  @client.select_db("test_selectdb_1")
874
- @client.query("SHOW TABLES").first.values.first.should eql("test1")
906
+ expect(@client.query("SHOW TABLES").first.values.first).to eql("test1")
875
907
  @client.select_db("test_selectdb_0")
876
- @client.query("SHOW TABLES").first.values.first.should eql("test0")
908
+ expect(@client.query("SHOW TABLES").first.values.first).to eql("test0")
877
909
  end
878
910
 
879
911
  it "should raise a Mysql2::Error when the database doesn't exist" do
880
- lambda {
912
+ expect {
881
913
  @client.select_db("nopenothere")
882
- }.should raise_error(Mysql2::Error)
914
+ }.to raise_error(Mysql2::Error)
883
915
  end
884
916
 
885
917
  it "should return the database switched to" do
886
- @client.select_db("test_selectdb_1").should eq("test_selectdb_1")
918
+ expect(@client.select_db("test_selectdb_1")).to eq("test_selectdb_1")
887
919
  end
888
920
  end
889
921
 
890
922
  it "#thread_id should return a boolean" do
891
- @client.ping.should eql(true)
923
+ expect(@client.ping).to eql(true)
892
924
  @client.close
893
- @client.ping.should eql(false)
925
+ expect(@client.ping).to eql(false)
894
926
  end
895
927
 
896
928
  unless RUBY_VERSION =~ /1.8/
897
929
  it "should respond to #encoding" do
898
- @client.should respond_to(:encoding)
930
+ expect(@client).to respond_to(:encoding)
899
931
  end
900
932
  end
901
933
  end