mysql2 0.3.21 → 0.4.2

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