mysql2 0.3.21 → 0.4.10
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/README.md +132 -55
- data/examples/eventmachine.rb +1 -1
- data/examples/threaded.rb +4 -6
- data/ext/mysql2/client.c +314 -118
- data/ext/mysql2/client.h +13 -3
- data/ext/mysql2/extconf.rb +111 -44
- data/ext/mysql2/infile.c +2 -2
- data/ext/mysql2/mysql2_ext.c +1 -0
- data/ext/mysql2/mysql2_ext.h +5 -10
- data/ext/mysql2/mysql_enc_name_to_ruby.h +2 -2
- data/ext/mysql2/mysql_enc_to_ruby.h +25 -22
- data/ext/mysql2/result.c +489 -101
- data/ext/mysql2/result.h +12 -4
- data/ext/mysql2/statement.c +595 -0
- data/ext/mysql2/statement.h +19 -0
- data/lib/mysql2/client.rb +70 -27
- data/lib/mysql2/console.rb +1 -1
- data/lib/mysql2/em.rb +5 -6
- data/lib/mysql2/error.rb +17 -26
- data/lib/mysql2/field.rb +3 -0
- data/lib/mysql2/statement.rb +17 -0
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +37 -35
- data/spec/configuration.yml.example +0 -6
- data/spec/em/em_spec.rb +22 -21
- data/spec/mysql2/client_spec.rb +484 -346
- data/spec/mysql2/error_spec.rb +38 -39
- data/spec/mysql2/result_spec.rb +256 -230
- data/spec/mysql2/statement_spec.rb +776 -0
- data/spec/spec_helper.rb +80 -59
- data/spec/ssl/ca-cert.pem +17 -0
- data/spec/ssl/ca-key.pem +27 -0
- data/spec/ssl/ca.cnf +22 -0
- data/spec/ssl/cert.cnf +22 -0
- data/spec/ssl/client-cert.pem +17 -0
- data/spec/ssl/client-key.pem +27 -0
- data/spec/ssl/client-req.pem +15 -0
- data/spec/ssl/gen_certs.sh +48 -0
- data/spec/ssl/pkcs8-client-key.pem +28 -0
- data/spec/ssl/pkcs8-server-key.pem +28 -0
- data/spec/ssl/server-cert.pem +17 -0
- data/spec/ssl/server-key.pem +27 -0
- data/spec/ssl/server-req.pem +15 -0
- data/support/5072E1F5.asc +432 -0
- data/support/mysql_enc_to_ruby.rb +7 -8
- data/support/ruby_enc_to_mysql.rb +1 -1
- metadata +50 -55
@@ -0,0 +1,19 @@
|
|
1
|
+
#ifndef MYSQL2_STATEMENT_H
|
2
|
+
#define MYSQL2_STATEMENT_H
|
3
|
+
|
4
|
+
extern VALUE cMysql2Statement;
|
5
|
+
|
6
|
+
typedef struct {
|
7
|
+
VALUE client;
|
8
|
+
MYSQL_STMT *stmt;
|
9
|
+
int refcount;
|
10
|
+
int closed;
|
11
|
+
} mysql_stmt_wrapper;
|
12
|
+
|
13
|
+
void init_mysql2_statement(void);
|
14
|
+
void decr_mysql2_stmt(mysql_stmt_wrapper *stmt_wrapper);
|
15
|
+
|
16
|
+
VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql);
|
17
|
+
void rb_raise_mysql2_stmt_error(mysql_stmt_wrapper *stmt_wrapper) RB_MYSQL_NORETURN;
|
18
|
+
|
19
|
+
#endif
|
data/lib/mysql2/client.rb
CHANGED
@@ -1,24 +1,28 @@
|
|
1
1
|
module Mysql2
|
2
2
|
class Client
|
3
3
|
attr_reader :query_options, :read_timeout
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
4
|
+
|
5
|
+
def self.default_query_options
|
6
|
+
@default_query_options ||= {
|
7
|
+
:as => :hash, # the type of object you want each row back as; also supports :array (an array of values)
|
8
|
+
:async => false, # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result
|
9
|
+
:cast_booleans => false, # cast tinyint(1) fields as true/false in ruby
|
10
|
+
:symbolize_keys => false, # return field names as symbols instead of strings
|
11
|
+
:database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
|
12
|
+
:application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
|
13
|
+
:cache_rows => true, # tells Mysql2 to use its internal row cache for results
|
14
|
+
:connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION,
|
15
|
+
:cast => true,
|
16
|
+
:default_file => nil,
|
17
|
+
:default_group => nil,
|
18
|
+
}
|
19
|
+
end
|
17
20
|
|
18
21
|
def initialize(opts = {})
|
19
|
-
|
22
|
+
fail Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash
|
23
|
+
opts = Mysql2::Util.key_hash_as_symbols(opts)
|
20
24
|
@read_timeout = nil
|
21
|
-
@query_options =
|
25
|
+
@query_options = self.class.default_query_options.dup
|
22
26
|
@query_options.merge! opts
|
23
27
|
|
24
28
|
initialize_ext
|
@@ -26,13 +30,14 @@ module Mysql2
|
|
26
30
|
# Set default connect_timeout to avoid unlimited retries from signal interruption
|
27
31
|
opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout)
|
28
32
|
|
29
|
-
|
33
|
+
# TODO: stricter validation rather than silent massaging
|
34
|
+
[:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout, :default_file, :default_group, :secure_auth, :init_command, :automatic_close, :enable_cleartext_plugin].each do |key|
|
30
35
|
next unless opts.key?(key)
|
31
36
|
case key
|
32
|
-
when :reconnect, :local_infile, :secure_auth
|
33
|
-
send(:"#{key}=", !!opts[key])
|
37
|
+
when :reconnect, :local_infile, :secure_auth, :automatic_close, :enable_cleartext_plugin
|
38
|
+
send(:"#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation
|
34
39
|
when :connect_timeout, :read_timeout, :write_timeout
|
35
|
-
send(:"#{key}=", opts[key].
|
40
|
+
send(:"#{key}=", Integer(opts[key])) unless opts[key].nil?
|
36
41
|
else
|
37
42
|
send(:"#{key}=", opts[key])
|
38
43
|
end
|
@@ -42,11 +47,26 @@ module Mysql2
|
|
42
47
|
self.charset_name = opts[:encoding] || 'utf8'
|
43
48
|
|
44
49
|
ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
|
45
|
-
ssl_set(*ssl_options) if ssl_options.any?
|
50
|
+
ssl_set(*ssl_options) if ssl_options.any? || opts.key?(:sslverify)
|
51
|
+
self.ssl_mode = parse_ssl_mode(opts[:ssl_mode]) if opts[:ssl_mode]
|
52
|
+
|
53
|
+
case opts[:flags]
|
54
|
+
when Array
|
55
|
+
flags = parse_flags_array(opts[:flags], @query_options[:connect_flags])
|
56
|
+
when String
|
57
|
+
flags = parse_flags_array(opts[:flags].split(' '), @query_options[:connect_flags])
|
58
|
+
when Integer
|
59
|
+
flags = @query_options[:connect_flags] | opts[:flags]
|
60
|
+
else
|
61
|
+
flags = @query_options[:connect_flags]
|
62
|
+
end
|
63
|
+
|
64
|
+
# SSL verify is a connection flag rather than a mysql_ssl_set option
|
65
|
+
flags |= SSL_VERIFY_SERVER_CERT if opts[:sslverify]
|
46
66
|
|
47
|
-
if [:user
|
67
|
+
if [:user, :pass, :hostname, :dbname, :db, :sock].any? { |k| @query_options.key?(k) }
|
48
68
|
warn "============= WARNING FROM mysql2 ============="
|
49
|
-
warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be
|
69
|
+
warn "The options :user, :pass, :hostname, :dbname, :db, and :sock are deprecated and will be removed at some point in the future."
|
50
70
|
warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options."
|
51
71
|
warn "============= END WARNING FROM mysql2 ========="
|
52
72
|
end
|
@@ -57,7 +77,6 @@ module Mysql2
|
|
57
77
|
port = opts[:port]
|
58
78
|
database = opts[:database] || opts[:dbname] || opts[:db]
|
59
79
|
socket = opts[:socket] || opts[:sock]
|
60
|
-
flags = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]
|
61
80
|
|
62
81
|
# Correct the data types before passing these values down to the C level
|
63
82
|
user = user.to_s unless user.nil?
|
@@ -70,8 +89,29 @@ module Mysql2
|
|
70
89
|
connect user, pass, host, port, database, socket, flags
|
71
90
|
end
|
72
91
|
|
73
|
-
def
|
74
|
-
|
92
|
+
def parse_ssl_mode(mode)
|
93
|
+
m = mode.to_s.upcase
|
94
|
+
if m.start_with?('SSL_MODE_')
|
95
|
+
return Mysql2::Client.const_get(m) if Mysql2::Client.const_defined?(m)
|
96
|
+
else
|
97
|
+
x = 'SSL_MODE_' + m
|
98
|
+
return Mysql2::Client.const_get(x) if Mysql2::Client.const_defined?(x)
|
99
|
+
end
|
100
|
+
warn "Unknown MySQL ssl_mode flag: #{mode}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def parse_flags_array(flags, initial = 0)
|
104
|
+
flags.reduce(initial) do |memo, f|
|
105
|
+
fneg = f.start_with?('-') ? f[1..-1] : nil
|
106
|
+
if fneg && fneg =~ /^\w+$/ && Mysql2::Client.const_defined?(fneg)
|
107
|
+
memo & ~ Mysql2::Client.const_get(fneg)
|
108
|
+
elsif f && f =~ /^\w+$/ && Mysql2::Client.const_defined?(f)
|
109
|
+
memo | Mysql2::Client.const_get(f)
|
110
|
+
else
|
111
|
+
warn "Unknown MySQL connection flag: '#{f}'"
|
112
|
+
memo
|
113
|
+
end
|
114
|
+
end
|
75
115
|
end
|
76
116
|
|
77
117
|
if Thread.respond_to?(:handle_interrupt)
|
@@ -98,9 +138,12 @@ module Mysql2
|
|
98
138
|
self.class.info
|
99
139
|
end
|
100
140
|
|
101
|
-
|
102
|
-
|
141
|
+
class << self
|
142
|
+
private
|
143
|
+
|
144
|
+
def local_offset
|
103
145
|
::Time.local(2010).utc_offset.to_r / 86400
|
104
146
|
end
|
147
|
+
end
|
105
148
|
end
|
106
149
|
end
|
data/lib/mysql2/console.rb
CHANGED
data/lib/mysql2/em.rb
CHANGED
@@ -17,7 +17,7 @@ module Mysql2
|
|
17
17
|
detach
|
18
18
|
begin
|
19
19
|
result = @client.async_result
|
20
|
-
rescue
|
20
|
+
rescue => e
|
21
21
|
@deferable.fail(e)
|
22
22
|
else
|
23
23
|
@deferable.succeed(result)
|
@@ -34,17 +34,16 @@ module Mysql2
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def close(*args)
|
37
|
-
if @watch
|
38
|
-
|
39
|
-
end
|
37
|
+
@watch.detach if @watch && @watch.watching?
|
38
|
+
|
40
39
|
super(*args)
|
41
40
|
end
|
42
41
|
|
43
|
-
def query(sql, opts={})
|
42
|
+
def query(sql, opts = {})
|
44
43
|
if ::EM.reactor_running?
|
45
44
|
super(sql, opts.merge(:async => true))
|
46
45
|
deferable = ::EM::DefaultDeferrable.new
|
47
|
-
@watch = ::EM.watch(
|
46
|
+
@watch = ::EM.watch(socket, Watcher, self, deferable)
|
48
47
|
@watch.notify_readable = true
|
49
48
|
deferable
|
50
49
|
else
|
data/lib/mysql2/error.rb
CHANGED
@@ -2,25 +2,31 @@
|
|
2
2
|
|
3
3
|
module Mysql2
|
4
4
|
class Error < StandardError
|
5
|
-
|
6
|
-
|
5
|
+
ENCODE_OPTS = {
|
6
|
+
:undef => :replace,
|
7
|
+
:invalid => :replace,
|
8
|
+
:replace => '?'.freeze,
|
9
|
+
}.freeze
|
7
10
|
|
8
|
-
|
9
|
-
attr_reader :sql_state
|
10
|
-
attr_writer :server_version
|
11
|
+
attr_reader :error_number, :sql_state
|
11
12
|
|
12
13
|
# Mysql gem compatibility
|
13
14
|
alias_method :errno, :error_number
|
14
15
|
alias_method :error, :message
|
15
16
|
|
16
|
-
def initialize(msg
|
17
|
-
|
17
|
+
def initialize(msg)
|
18
|
+
@server_version ||= nil
|
18
19
|
|
19
20
|
super(clean_message(msg))
|
20
21
|
end
|
21
22
|
|
22
|
-
def sql_state
|
23
|
-
|
23
|
+
def self.new_with_args(msg, server_version, error_number, sql_state)
|
24
|
+
err = allocate
|
25
|
+
err.instance_variable_set('@server_version', server_version)
|
26
|
+
err.instance_variable_set('@error_number', error_number)
|
27
|
+
err.instance_variable_set('@sql_state', sql_state.respond_to?(:encode) ? sql_state.encode(ENCODE_OPTS) : sql_state)
|
28
|
+
err.send(:initialize, msg)
|
29
|
+
err
|
24
30
|
end
|
25
31
|
|
26
32
|
private
|
@@ -53,27 +59,12 @@ module Mysql2
|
|
53
59
|
#
|
54
60
|
# Returns a valid UTF-8 string in Ruby 1.9+, the original string on Ruby 1.8
|
55
61
|
def clean_message(message)
|
56
|
-
return message
|
62
|
+
return message unless message.respond_to?(:encode)
|
57
63
|
|
58
64
|
if @server_version && @server_version > 50500
|
59
65
|
message.encode(ENCODE_OPTS)
|
60
66
|
else
|
61
|
-
|
62
|
-
message.scrub(REPLACEMENT_CHAR).encode(ENCODE_OPTS)
|
63
|
-
else
|
64
|
-
# This is ugly as hell but Ruby 1.9 doesn't provide a way to clean a string
|
65
|
-
# and retain it's valid UTF-8 characters, that I know of.
|
66
|
-
|
67
|
-
new_message = "".force_encoding(Encoding::UTF_8)
|
68
|
-
message.chars.each do |char|
|
69
|
-
if char.valid_encoding?
|
70
|
-
new_message << char
|
71
|
-
else
|
72
|
-
new_message << REPLACEMENT_CHAR
|
73
|
-
end
|
74
|
-
end
|
75
|
-
new_message.encode(ENCODE_OPTS)
|
76
|
-
end
|
67
|
+
message.encode(Encoding::UTF_8, ENCODE_OPTS)
|
77
68
|
end
|
78
69
|
end
|
79
70
|
end
|
data/lib/mysql2/field.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Mysql2
|
2
|
+
class Statement
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
if Thread.respond_to?(:handle_interrupt)
|
6
|
+
def execute(*args)
|
7
|
+
Thread.handle_interrupt(::Mysql2::Util::TimeoutError => :never) do
|
8
|
+
_execute(*args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
else
|
12
|
+
def execute(*args)
|
13
|
+
_execute(*args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/mysql2/version.rb
CHANGED
data/lib/mysql2.rb
CHANGED
@@ -8,16 +8,16 @@ require 'rational' unless RUBY_VERSION >= '1.9.2'
|
|
8
8
|
# Or to bomb out with a clear error message instead of a linker crash
|
9
9
|
if RUBY_PLATFORM =~ /mswin|mingw/
|
10
10
|
dll_path = if ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
# If this environment variable is set, it overrides any other paths
|
12
|
+
# The user is advised to use backslashes not forward slashes
|
13
|
+
ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
|
14
|
+
elsif File.exist?(File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)))
|
15
|
+
# Use vendor/libmysql.dll if it exists, convert slashes for Win32 LoadLibrary
|
16
|
+
File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)).tr('/', '\\')
|
17
|
+
else
|
18
|
+
# This will use default / system library paths
|
19
|
+
'libmysql.dll'
|
20
|
+
end
|
21
21
|
|
22
22
|
require 'Win32API'
|
23
23
|
LoadLibrary = Win32API.new('Kernel32', 'LoadLibrary', ['P'], 'I')
|
@@ -31,6 +31,8 @@ require 'mysql2/error'
|
|
31
31
|
require 'mysql2/mysql2'
|
32
32
|
require 'mysql2/result'
|
33
33
|
require 'mysql2/client'
|
34
|
+
require 'mysql2/field'
|
35
|
+
require 'mysql2/statement'
|
34
36
|
|
35
37
|
# = Mysql2
|
36
38
|
#
|
@@ -51,32 +53,32 @@ if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING < "3
|
|
51
53
|
end
|
52
54
|
|
53
55
|
# For holding utility methods
|
54
|
-
module Mysql2
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
module Mysql2
|
57
|
+
module Util
|
58
|
+
#
|
59
|
+
# Rekey a string-keyed hash with equivalent symbols.
|
60
|
+
#
|
61
|
+
def self.key_hash_as_symbols(hash)
|
62
|
+
return nil unless hash
|
63
|
+
Hash[hash.map { |k, v| [k.to_sym, v] }]
|
64
|
+
end
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
66
|
+
#
|
67
|
+
# In Mysql2::Client#query and Mysql2::Statement#execute,
|
68
|
+
# Thread#handle_interrupt is used to prevent Timeout#timeout
|
69
|
+
# from interrupting query execution.
|
70
|
+
#
|
71
|
+
# Timeout::ExitException was removed in Ruby 2.3.0, 2.2.3, and 2.1.8,
|
72
|
+
# but is present in earlier 2.1.x and 2.2.x, so we provide a shim.
|
73
|
+
#
|
74
|
+
if Thread.respond_to?(:handle_interrupt)
|
75
|
+
require 'timeout'
|
76
|
+
# rubocop:disable Style/ConstantName
|
77
|
+
TimeoutError = if defined?(::Timeout::ExitException)
|
78
|
+
::Timeout::ExitException
|
79
|
+
else
|
80
|
+
::Timeout::Error
|
81
|
+
end
|
79
82
|
end
|
80
83
|
end
|
81
|
-
|
82
84
|
end
|
data/spec/em/em_spec.rb
CHANGED
@@ -4,7 +4,7 @@ begin
|
|
4
4
|
require 'eventmachine'
|
5
5
|
require 'mysql2/em'
|
6
6
|
|
7
|
-
describe Mysql2::EM::Client do
|
7
|
+
RSpec.describe Mysql2::EM::Client do
|
8
8
|
it "should support async queries" do
|
9
9
|
results = []
|
10
10
|
EM.run do
|
@@ -24,8 +24,8 @@ begin
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
results[0].keys.
|
28
|
-
results[1].keys.
|
27
|
+
expect(results[0].keys).to include("second_query")
|
28
|
+
expect(results[1].keys).to include("first_query")
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should support queries in callbacks" do
|
@@ -44,38 +44,39 @@ begin
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
results[0].keys.
|
48
|
-
results[1].keys.
|
47
|
+
expect(results[0].keys).to include("first_query")
|
48
|
+
expect(results[1].keys).to include("second_query")
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should not swallow exceptions raised in callbacks" do
|
52
|
-
|
52
|
+
expect {
|
53
53
|
EM.run do
|
54
54
|
client = Mysql2::EM::Client.new DatabaseCredentials['root']
|
55
55
|
defer = client.query "SELECT sleep(0.1) as first_query"
|
56
|
-
defer.callback do
|
56
|
+
defer.callback do
|
57
57
|
client.close
|
58
|
-
|
58
|
+
fail 'some error'
|
59
59
|
end
|
60
|
-
defer.errback do
|
60
|
+
defer.errback do
|
61
61
|
# This _shouldn't_ be run, but it needed to prevent the specs from
|
62
62
|
# freezing if this test fails.
|
63
63
|
EM.stop_event_loop
|
64
64
|
end
|
65
65
|
end
|
66
|
-
}.
|
66
|
+
}.to raise_error('some error')
|
67
67
|
end
|
68
68
|
|
69
69
|
context 'when an exception is raised by the client' do
|
70
70
|
let(:client) { Mysql2::EM::Client.new DatabaseCredentials['root'] }
|
71
71
|
let(:error) { StandardError.new('some error') }
|
72
|
-
before { client.
|
72
|
+
before { allow(client).to receive(:async_result).and_raise(error) }
|
73
|
+
after { client.close }
|
73
74
|
|
74
75
|
it "should swallow exceptions raised in by the client" do
|
75
76
|
errors = []
|
76
77
|
EM.run do
|
77
78
|
defer = client.query "SELECT sleep(0.1) as first_query"
|
78
|
-
defer.callback do
|
79
|
+
defer.callback do
|
79
80
|
# This _shouldn't_ be run, but it is needed to prevent the specs from
|
80
81
|
# freezing if this test fails.
|
81
82
|
EM.stop_event_loop
|
@@ -85,7 +86,7 @@ begin
|
|
85
86
|
EM.stop_event_loop
|
86
87
|
end
|
87
88
|
end
|
88
|
-
errors.
|
89
|
+
expect(errors).to eq([error])
|
89
90
|
end
|
90
91
|
|
91
92
|
it "should fail the deferrable" do
|
@@ -93,19 +94,19 @@ begin
|
|
93
94
|
EM.run do
|
94
95
|
defer = client.query "SELECT sleep(0.025) as first_query"
|
95
96
|
EM.add_timer(0.1) do
|
96
|
-
defer.callback do
|
97
|
+
defer.callback do
|
97
98
|
callbacks_run << :callback
|
98
99
|
# This _shouldn't_ be run, but it is needed to prevent the specs from
|
99
100
|
# freezing if this test fails.
|
100
101
|
EM.stop_event_loop
|
101
102
|
end
|
102
|
-
defer.errback do
|
103
|
+
defer.errback do
|
103
104
|
callbacks_run << :errback
|
104
105
|
EM.stop_event_loop
|
105
106
|
end
|
106
107
|
end
|
107
108
|
end
|
108
|
-
callbacks_run.
|
109
|
+
expect(callbacks_run).to eq([:errback])
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
@@ -114,17 +115,17 @@ begin
|
|
114
115
|
EM.run do
|
115
116
|
client = Mysql2::EM::Client.new DatabaseCredentials['root']
|
116
117
|
defer = client.query("select sleep(0.025)")
|
117
|
-
defer.callback do
|
118
|
+
defer.callback do
|
118
119
|
callbacks_run << :callback
|
119
120
|
end
|
120
|
-
defer.errback do
|
121
|
+
defer.errback do
|
121
122
|
callbacks_run << :errback
|
122
123
|
end
|
123
124
|
EM.add_timer(0.1) do
|
124
|
-
callbacks_run.
|
125
|
-
|
125
|
+
expect(callbacks_run).to eq([:callback])
|
126
|
+
expect {
|
126
127
|
client.close
|
127
|
-
}.
|
128
|
+
}.not_to raise_error
|
128
129
|
EM.stop_event_loop
|
129
130
|
end
|
130
131
|
end
|