tarantool 0.3.0.7 → 0.4.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -3
- data/README.md +90 -30
- data/Rakefile +6 -1
- data/lib/tarantool.rb +93 -18
- data/lib/tarantool/base_record.rb +97 -10
- data/lib/tarantool/block_db.rb +104 -6
- data/lib/tarantool/callback_db.rb +7 -0
- data/lib/tarantool/core-ext.rb +24 -8
- data/lib/tarantool/em_db.rb +189 -20
- data/lib/tarantool/exceptions.rb +4 -0
- data/lib/tarantool/fiber_db.rb +15 -1
- data/lib/tarantool/light_record.rb +17 -0
- data/lib/tarantool/query.rb +15 -9
- data/lib/tarantool/record/select.rb +21 -3
- data/lib/tarantool/request.rb +130 -43
- data/lib/tarantool/response.rb +70 -7
- data/lib/tarantool/serializers.rb +26 -5
- data/lib/tarantool/serializers/ber_array.rb +14 -0
- data/lib/tarantool/shards_support.rb +204 -0
- data/lib/tarantool/space_array.rb +38 -13
- data/lib/tarantool/space_hash.rb +49 -27
- data/lib/tarantool/util.rb +96 -10
- data/lib/tarantool/version.rb +2 -1
- data/test/helper.rb +154 -4
- data/test/{tarant/init.lua → init.lua} +0 -0
- data/test/run_all.rb +2 -2
- data/test/shared_record.rb +59 -0
- data/test/shared_replicated_shard.rb +1018 -0
- data/test/shared_reshard.rb +380 -0
- data/test/tarantool.cfg +2 -0
- data/test/test_light_record.rb +2 -0
- data/test/test_light_record_callback.rb +92 -0
- data/test/test_query_block.rb +1 -0
- data/test/test_query_fiber.rb +1 -0
- data/test/test_reshard_block.rb +7 -0
- data/test/test_reshard_fiber.rb +11 -0
- data/test/test_shard_replication_block.rb +7 -0
- data/test/test_shard_replication_fiber.rb +11 -0
- data/test/test_space_array_block.rb +1 -0
- data/test/test_space_array_callback.rb +50 -121
- data/test/test_space_array_callback_nodef.rb +39 -96
- data/test/test_space_array_fiber.rb +1 -0
- data/test/test_space_hash_block.rb +1 -0
- data/test/test_space_hash_fiber.rb +1 -0
- metadata +54 -17
- data/lib/tarantool/record.rb +0 -164
- data/test/box.pid +0 -1
- data/test/tarantool.log +0 -6
- data/test/tarantool_repl.cfg +0 -53
- data/test/test_record.rb +0 -88
- data/test/test_record_composite_pk.rb +0 -77
data/lib/tarantool/space_hash.rb
CHANGED
@@ -5,9 +5,10 @@ require 'tarantool/core-ext'
|
|
5
5
|
|
6
6
|
module Tarantool
|
7
7
|
class SpaceHash
|
8
|
+
include CommonSpace
|
8
9
|
include Request
|
9
10
|
|
10
|
-
def initialize(tarantool, space_no, fields_def, indexes)
|
11
|
+
def initialize(tarantool, space_no, fields_def, indexes, shard_fields = nil, shard_proc = nil)
|
11
12
|
@tarantool = tarantool
|
12
13
|
@space_no = space_no
|
13
14
|
|
@@ -46,16 +47,17 @@ module Tarantool
|
|
46
47
|
@index_fields = [*indexes].map{|ind| [*ind].map{|fld| fld.to_sym}.freeze}.freeze
|
47
48
|
@indexes = _map_indexes(@index_fields)
|
48
49
|
@translators = [TranslateToHash.new(@field_names - [:_tail], @tail_size)].freeze
|
49
|
-
end
|
50
50
|
|
51
|
-
|
52
|
-
@
|
51
|
+
@shard_fields = [*(shard_fields || @index_fields[0])]
|
52
|
+
@shard_positions = @shard_fields.map{|name| @field_to_pos[name]}
|
53
|
+
_init_shard_vars(shard_proc)
|
53
54
|
end
|
54
55
|
|
55
56
|
def with_translator(cb = nil, &block)
|
56
|
-
|
57
|
-
|
58
|
-
|
57
|
+
clone.instance_exec do
|
58
|
+
@translators += [cb || block]
|
59
|
+
self
|
60
|
+
end
|
59
61
|
end
|
60
62
|
|
61
63
|
def _map_indexes(indexes)
|
@@ -66,10 +68,6 @@ module Tarantool
|
|
66
68
|
end.freeze
|
67
69
|
end
|
68
70
|
|
69
|
-
def _send_request(type, body, cb)
|
70
|
-
@tarantool._send_request(type, body, cb)
|
71
|
-
end
|
72
|
-
|
73
71
|
def select_cb(keys, offset, limit, cb)
|
74
72
|
index_names = Hash === keys ? keys.keys : keys.first.keys
|
75
73
|
index_no = @index_fields.index{|fields|
|
@@ -102,7 +100,9 @@ module Tarantool
|
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
105
|
-
|
103
|
+
shard_nums = _get_shard_nums { _detect_shards_for_keys(keys, index_no) }
|
104
|
+
|
105
|
+
_select(@space_no, index_no, offset, limit, keys, cb, @field_types, index_types, shard_nums, @translators)
|
106
106
|
end
|
107
107
|
|
108
108
|
def all_cb(keys, cb, opts = {})
|
@@ -114,15 +114,17 @@ module Tarantool
|
|
114
114
|
end
|
115
115
|
|
116
116
|
def all_by_pks_cb(keys, cb, opts={})
|
117
|
-
keys = [*keys].map{|key| _prepare_pk(key)}
|
117
|
+
keys = (Hash === keys ? [keys] : [*keys]).map{|key| _prepare_pk(key)}
|
118
|
+
shard_nums = _get_shard_nums{ _detect_shards_for_keys(keys, 0) }
|
118
119
|
_select(@space_no, 0,
|
119
120
|
opts[:offset] || 0, opts[:limit] || -1,
|
120
|
-
keys, cb, @field_types, @indexes[0], @translators)
|
121
|
+
keys, cb, @field_types, @indexes[0], shard_nums, @translators)
|
121
122
|
end
|
122
123
|
|
123
|
-
def by_pk_cb(
|
124
|
-
|
125
|
-
|
124
|
+
def by_pk_cb(pk, cb)
|
125
|
+
pk = _prepare_pk(pk)
|
126
|
+
shard_nums = _get_shard_nums{ _detect_shards_for_key(pk, 0) }
|
127
|
+
_select(@space_no, 0, 0, :first, [pk], cb, @field_types, @indexes[0], shard_nums, @translators)
|
126
128
|
end
|
127
129
|
|
128
130
|
def _prepare_tuple(tuple)
|
@@ -142,13 +144,30 @@ module Tarantool
|
|
142
144
|
end
|
143
145
|
|
144
146
|
def insert_cb(tuple, cb, opts = {})
|
145
|
-
|
146
|
-
|
147
|
+
tuple = _prepare_tuple(tuple)
|
148
|
+
shard_nums = detect_shard_for_insert(tuple.values_at(*@shard_positions))
|
149
|
+
_insert(@space_no, BOX_ADD, tuple, @field_types, cb, opts[:return_tuple],
|
150
|
+
shard_nums, nil, @translators)
|
147
151
|
end
|
148
152
|
|
149
153
|
def replace_cb(tuple, cb, opts = {})
|
150
|
-
|
151
|
-
|
154
|
+
tuple = _prepare_tuple(tuple)
|
155
|
+
shard_nums = detect_shard(tuple.values_at(*@shard_positions))
|
156
|
+
_insert(@space_no, BOX_REPLACE, tuple, @field_types, cb, opts[:return_tuple],
|
157
|
+
shard_nums, opts.fetch(:in_any_shard, true), @translators)
|
158
|
+
end
|
159
|
+
|
160
|
+
def store_cb(tuple, cb, opts = {})
|
161
|
+
tuple = _prepare_tuple(tuple)
|
162
|
+
shard_nums = _get_shard_nums{
|
163
|
+
if opts.fetch(:to_insert_shard, true)
|
164
|
+
_detect_shard_for_insert(tuple.values_at(*@shard_positions))
|
165
|
+
else
|
166
|
+
_detect_shard(tuple.values_at(*@shard_positions))
|
167
|
+
end
|
168
|
+
}
|
169
|
+
_insert(@space_no, 0, tuple, @field_types, cb, opts[:return_tuple],
|
170
|
+
shard_nums, nil, @translators)
|
152
171
|
end
|
153
172
|
|
154
173
|
def _prepare_pk(pk)
|
@@ -209,13 +228,16 @@ module Tarantool
|
|
209
228
|
)
|
210
229
|
end
|
211
230
|
}
|
212
|
-
|
213
|
-
|
231
|
+
shard_nums = _get_shard_nums{ _detect_shards_for_key(pk, 0) }
|
232
|
+
_update(@space_no, pk, opers, @field_types, @indexes[0], cb, opts[:return_tuple],
|
233
|
+
shard_nums, @translators)
|
214
234
|
end
|
215
235
|
|
216
236
|
def delete_cb(pk, cb, opts = {})
|
217
|
-
|
218
|
-
|
237
|
+
pk = _prepare_pk(pk)
|
238
|
+
shard_nums = _get_shard_nums{ _detect_shards_for_key(pk, 0) }
|
239
|
+
_delete(@space_no, pk, @field_types, @indexes[0], cb, opts[:return_tuple],
|
240
|
+
shard_nums, @translators)
|
219
241
|
end
|
220
242
|
|
221
243
|
def invoke_cb(func_name, values, cb, opts = {})
|
@@ -252,10 +274,10 @@ module Tarantool
|
|
252
274
|
end
|
253
275
|
|
254
276
|
def first_blk(key, &block)
|
255
|
-
|
277
|
+
first_cb(key, block)
|
256
278
|
end
|
257
279
|
|
258
|
-
def select_blk(keys, offset=0, limit
|
280
|
+
def select_blk(keys, offset=0, limit=-1, &block)
|
259
281
|
select_cb(keys, offset, limit, block)
|
260
282
|
end
|
261
283
|
end
|
data/lib/tarantool/util.rb
CHANGED
@@ -1,8 +1,36 @@
|
|
1
1
|
module Tarantool
|
2
2
|
module Util
|
3
3
|
module Packer
|
4
|
+
INT8 = 'C'.freeze
|
5
|
+
INT16 = 'v'.freeze
|
6
|
+
INT32 = 'V'.freeze
|
7
|
+
INT64 = 'Q<'.freeze
|
8
|
+
SINT8 = 'c'.freeze
|
9
|
+
SINT16 = 's<'.freeze
|
10
|
+
SINT32 = 'l<'.freeze
|
11
|
+
SINT64 = 'q<'.freeze
|
12
|
+
MIN_INT = 0
|
13
|
+
MAX_INT64 = 2**64 - 1
|
14
|
+
MAX_INT32 = 2**32 - 1
|
15
|
+
MAX_INT16 = 2**16 - 1
|
16
|
+
MAX_INT8 = 2**8 - 1
|
17
|
+
MAX_SINT64 = 2**63 - 1
|
18
|
+
MAX_SINT32 = 2**31 - 1
|
19
|
+
MAX_SINT16 = 2**15 - 1
|
20
|
+
MAX_SINT8 = 2**7 - 1
|
21
|
+
MIN_SINT64 = -(2**63)
|
22
|
+
MIN_SINT32 = -(2**31)
|
23
|
+
MIN_SINT16 = -(2**15)
|
24
|
+
MIN_SINT8 = -(2**7)
|
4
25
|
private
|
5
26
|
EMPTY = ''.freeze
|
27
|
+
ONE = "\x01".freeze
|
28
|
+
def unpack_int8!(data)
|
29
|
+
int = data.getbyte(0)
|
30
|
+
data[0, 1] = EMPTY
|
31
|
+
int
|
32
|
+
end
|
33
|
+
|
6
34
|
def unpack_int16(data)
|
7
35
|
data.getbyte(0) + data.getbyte(1) * 256
|
8
36
|
end
|
@@ -10,7 +38,7 @@ module Tarantool
|
|
10
38
|
def unpack_int16!(data)
|
11
39
|
int = data.getbyte(0) + data.getbyte(1) * 256
|
12
40
|
data[0, 2] = EMPTY
|
13
|
-
|
41
|
+
int
|
14
42
|
end
|
15
43
|
|
16
44
|
def unpack_int32(int)
|
@@ -26,20 +54,33 @@ module Tarantool
|
|
26
54
|
end
|
27
55
|
|
28
56
|
def unpack_int64!(data)
|
29
|
-
int =
|
30
|
-
data.getbyte(2) * 65536 + data.getbyte(3) * 16777216 +
|
31
|
-
data.getbyte(4) << 32 + data.getbyte(5) << 40 +
|
32
|
-
data.getbyte(6) << 48 + data.getbyte(7) << 56
|
33
|
-
)
|
57
|
+
int = data.unpack(INT64)[0]
|
34
58
|
data[0, 8] = EMPTY
|
35
59
|
int
|
36
60
|
end
|
37
61
|
|
38
62
|
def unpack_int64(data)
|
39
|
-
data.
|
40
|
-
|
41
|
-
|
42
|
-
|
63
|
+
data.unpack(INT64)[0]
|
64
|
+
end
|
65
|
+
|
66
|
+
def unpack_sint8!(data)
|
67
|
+
i = unpack_int8!(data)
|
68
|
+
i - ((i & 128) << 1)
|
69
|
+
end
|
70
|
+
|
71
|
+
def unpack_sint16!(data)
|
72
|
+
i = unpack_int16!(data)
|
73
|
+
i - ((i & 32768) << 1)
|
74
|
+
end
|
75
|
+
|
76
|
+
def unpack_sint32!(data)
|
77
|
+
i = unpack_int32!(data)
|
78
|
+
i - ((i >> 31) << 32)
|
79
|
+
end
|
80
|
+
|
81
|
+
def unpack_sint64!(data)
|
82
|
+
i = unpack_int64!(data)
|
83
|
+
i - ((i >> 63) << 64)
|
43
84
|
end
|
44
85
|
|
45
86
|
def ber_size(int)
|
@@ -64,6 +105,51 @@ module Tarantool
|
|
64
105
|
data[0, pos+1] = EMPTY
|
65
106
|
res
|
66
107
|
end
|
108
|
+
|
109
|
+
def append_int8!(str, int)
|
110
|
+
str << (int & 255)
|
111
|
+
end
|
112
|
+
|
113
|
+
def append_int16!(str, int)
|
114
|
+
str << (int & 255) << ((int>>8) & 255)
|
115
|
+
end
|
116
|
+
|
117
|
+
def append_int32!(str, int)
|
118
|
+
str << (int & 255) << ((int>>8) & 255) <<
|
119
|
+
((int>>16) & 255) << ((int>>24) & 255)
|
120
|
+
end
|
121
|
+
|
122
|
+
def append_int64!(str, int)
|
123
|
+
str << [int].pack(INT64)
|
124
|
+
end
|
125
|
+
|
126
|
+
alias append_sint8! append_int8!
|
127
|
+
alias append_sint16! append_int16!
|
128
|
+
alias append_sint32! append_int32!
|
129
|
+
alias append_sint64! append_int64!
|
130
|
+
|
131
|
+
def append_ber_int8!(str, int)
|
132
|
+
str << 1 << (int & 255)
|
133
|
+
end
|
134
|
+
|
135
|
+
def append_ber_int16!(str, int)
|
136
|
+
str << 2 << (int & 255) << ((int>>8) & 255)
|
137
|
+
end
|
138
|
+
|
139
|
+
def append_ber_int32!(str, int)
|
140
|
+
str << 4 <<
|
141
|
+
(int & 255) << ((int>>8) & 255) <<
|
142
|
+
((int>>16) & 255) << ((int>>24) & 255)
|
143
|
+
end
|
144
|
+
|
145
|
+
def append_ber_int64!(str, int)
|
146
|
+
str << 8 << [int].pack(INT64)
|
147
|
+
end
|
148
|
+
|
149
|
+
alias append_ber_sint8! append_ber_int8!
|
150
|
+
alias append_ber_sint16! append_ber_int16!
|
151
|
+
alias append_ber_sint32! append_ber_int32!
|
152
|
+
alias append_ber_sint64! append_ber_int64!
|
67
153
|
end
|
68
154
|
|
69
155
|
module TailGetter
|
data/lib/tarantool/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'minitest/spec'
|
2
|
-
require 'minitest/autorun'
|
3
2
|
require 'rr'
|
3
|
+
require 'fileutils'
|
4
4
|
|
5
5
|
require 'tarantool'
|
6
6
|
|
@@ -14,6 +14,138 @@ class ArrayPackSerializer
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
module TConf
|
18
|
+
extend FileUtils
|
19
|
+
CONF = {
|
20
|
+
master1: {port: 33013, replica: :imaster},
|
21
|
+
slave1: {port: 34013, replica: :master1},
|
22
|
+
master2: {port: 35013, replica: :imaster},
|
23
|
+
slave2: {port: 36013, replica: :master2},
|
24
|
+
}
|
25
|
+
DIR = File.expand_path('..', __FILE__)
|
26
|
+
def self.fjoin(*args)
|
27
|
+
File.join(*args.map(&:to_s))
|
28
|
+
end
|
29
|
+
def self.dir(name)
|
30
|
+
fjoin(DIR, "tarantool_#{name}")
|
31
|
+
end
|
32
|
+
|
33
|
+
def self._to_master(cfg, conf)
|
34
|
+
cfg.sub!(/^replication_source.*$/, '#\0')
|
35
|
+
end
|
36
|
+
|
37
|
+
def self._to_slave(cfg, master)
|
38
|
+
replica_source = "127.0.0.1:#{CONF.fetch(master)[:port]+3}"
|
39
|
+
cfg.sub!(/^#?replication_source.*$/, "replication_source = \"#{replica_source}\"")
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.prepare(name)
|
43
|
+
conf = CONF.fetch(name)
|
44
|
+
return if conf[:dir]
|
45
|
+
clear(name)
|
46
|
+
dir = dir(name)
|
47
|
+
FileUtils.rm_rf dir
|
48
|
+
mkdir_p(dir)
|
49
|
+
cp fjoin(DIR, 'init.lua'), dir
|
50
|
+
cfg = File.read(fjoin(DIR, 'tarantool.cfg'))
|
51
|
+
cfg.sub!(/(pid_file\s*=\s*)"[^"]*"/, "\\1\"#{fjoin(dir, 'box.pid')}\"")
|
52
|
+
cfg.sub!(/(work_dir\s*=\s*)"[^"]*"/, "\\1\"#{dir}\"")
|
53
|
+
cfg.sub!(/(primary_port\s*=\s*)\d+/, "\\1#{conf[:port]}")
|
54
|
+
cfg.sub!(/(secondary_port\s*=\s*)\d+/, "\\1#{conf[:port]+1}")
|
55
|
+
cfg.sub!(/(admin_port\s*=\s*)\d+/, "\\1#{conf[:port]+2}")
|
56
|
+
cfg.sub!(/(replication_port\s*=\s*)\d+/, "\\1#{conf[:port]+3}")
|
57
|
+
if conf[:replica] == :imaster
|
58
|
+
_to_master(cfg, conf)
|
59
|
+
else
|
60
|
+
_to_slave(cfg, conf[:replica])
|
61
|
+
end
|
62
|
+
File.open(fjoin(dir, 'tarantool.cfg'), 'w'){|f| f.write(cfg)}
|
63
|
+
Dir.chdir(dir) do
|
64
|
+
`tarantool_box --init-storage 2>&1`
|
65
|
+
end
|
66
|
+
conf[:dir] = dir
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.run(name)
|
70
|
+
conf = CONF.fetch(name)
|
71
|
+
return if conf[:pid]
|
72
|
+
prepare(name)
|
73
|
+
Dir.chdir(conf[:dir]) do
|
74
|
+
conf[:pid] = spawn('tarantool_box')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.stop(name)
|
79
|
+
conf = CONF.fetch(name)
|
80
|
+
return unless conf[:pid]
|
81
|
+
Process.kill('INT', conf[:pid])
|
82
|
+
Process.wait2(conf[:pid])
|
83
|
+
conf.delete :pid
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.clear(name)
|
87
|
+
conf = CONF.fetch(name)
|
88
|
+
return unless conf[:dir]
|
89
|
+
stop(name)
|
90
|
+
rm_rf(conf[:dir])
|
91
|
+
conf.delete :dir
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.clear_all
|
95
|
+
CONF.keys.each{|name| clear(name) }
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.reset_and_up_all
|
99
|
+
clear_all
|
100
|
+
CONF.keys.each{|name| run(name) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.reset_and_up_masters
|
104
|
+
clear_masters
|
105
|
+
run(:master1)
|
106
|
+
run(:master2)
|
107
|
+
sleep(0.01)
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.clear_masters
|
111
|
+
clear(:master1)
|
112
|
+
clear(:master2)
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.conf(name)
|
116
|
+
{host: '127.0.0.1', port: CONF.fetch(name)[:port]}
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.promote_to_master(name)
|
120
|
+
conf = CONF.fetch(name)
|
121
|
+
raise "#{name} not running" unless conf[:pid]
|
122
|
+
fcfg = fjoin(dir(name), 'tarantool.cfg')
|
123
|
+
cfg = File.read(fcfg)
|
124
|
+
_to_master(cfg, conf)
|
125
|
+
File.open(fcfg, 'w'){|f| f.write(cfg)}
|
126
|
+
sock = TCPSocket.new('127.0.0.1', conf[:port]+2)
|
127
|
+
sock.write("reload configuration\n")
|
128
|
+
3.times{ sock.gets }
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.promote_to_slave(slave, master)
|
132
|
+
clear(slave)
|
133
|
+
prepare(slave)
|
134
|
+
fcfg = fjoin(dir(slave), 'tarantool.cfg')
|
135
|
+
cfg = File.read(fcfg)
|
136
|
+
_to_slave(cfg, master)
|
137
|
+
File.open(fcfg, 'w'){|f| f.write(cfg)}
|
138
|
+
run(slave)
|
139
|
+
end
|
140
|
+
|
141
|
+
at_exit do
|
142
|
+
CONF.keys.each{|name| clear(name)}
|
143
|
+
end
|
144
|
+
end
|
145
|
+
require 'minitest/autorun'
|
146
|
+
TConf.run(:master1)
|
147
|
+
|
148
|
+
|
17
149
|
TCONFIG = { host: '127.0.0.1', port: 33013, admin: 33015 }
|
18
150
|
|
19
151
|
SPACE0 = {
|
@@ -53,7 +185,7 @@ HSPACE3 = {
|
|
53
185
|
module Helper
|
54
186
|
def tarantool_pipe
|
55
187
|
$tarantool_pipe ||= begin
|
56
|
-
cnf = TCONFIG
|
188
|
+
cnf = {port: 33013, admin: 33015} #TCONFIG
|
57
189
|
tarant = %W{tarantool -p #{cnf[:port]} -m #{cnf[:admin]}}
|
58
190
|
tarant = [{}, *tarant, :err => [:child, :out]]
|
59
191
|
IO.popen(tarant, 'w+').tap{|p| p.sync = true}
|
@@ -115,17 +247,35 @@ module Helper
|
|
115
247
|
end
|
116
248
|
end
|
117
249
|
|
250
|
+
def setp(i)
|
251
|
+
@results ||= []
|
252
|
+
proc{|v| @results[i]=v; emstop}
|
253
|
+
end
|
254
|
+
|
255
|
+
def results
|
256
|
+
@results
|
257
|
+
end
|
258
|
+
|
259
|
+
class TimeOut < Exception
|
260
|
+
end
|
118
261
|
def fibrun
|
119
262
|
res = nil
|
120
263
|
EM.run {
|
264
|
+
t = nil
|
121
265
|
f = Fiber.new{
|
122
266
|
begin
|
123
267
|
res = yield
|
124
268
|
ensure
|
125
|
-
EM.next_tick{
|
269
|
+
EM.next_tick{
|
270
|
+
EM.cancel_timer t
|
271
|
+
EM.stop
|
272
|
+
}
|
126
273
|
end
|
127
274
|
}
|
128
275
|
EM.next_tick{ f.resume }
|
276
|
+
t = EM.add_timer(1) {
|
277
|
+
f.resume TimeOut.new
|
278
|
+
}
|
129
279
|
}
|
130
280
|
res
|
131
281
|
end
|
@@ -156,7 +306,7 @@ module MiniTest::Spec::SharedExamples
|
|
156
306
|
end
|
157
307
|
|
158
308
|
def it_behaves_like(desc)
|
159
|
-
class_eval
|
309
|
+
class_eval(&MiniTest::Spec.shared_examples.fetch(desc))
|
160
310
|
end
|
161
311
|
end
|
162
312
|
|