mysql2 0.3.21 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/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