cql-rb 1.1.0.pre3 → 1.1.0.pre6
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.
- data/README.md +2 -2
- data/lib/cql/client.rb +9 -5
- data/lib/cql/client/asynchronous_client.rb +105 -192
- data/lib/cql/client/asynchronous_prepared_statement.rb +51 -9
- data/lib/cql/client/connection_helper.rb +155 -0
- data/lib/cql/client/connection_manager.rb +56 -0
- data/lib/cql/client/keyspace_changer.rb +27 -0
- data/lib/cql/client/null_logger.rb +21 -0
- data/lib/cql/client/request_runner.rb +5 -3
- data/lib/cql/client/synchronous_client.rb +5 -5
- data/lib/cql/client/synchronous_prepared_statement.rb +4 -8
- data/lib/cql/future.rb +320 -210
- data/lib/cql/io/connection.rb +5 -5
- data/lib/cql/io/io_reactor.rb +21 -23
- data/lib/cql/protocol/cql_protocol_handler.rb +69 -38
- data/lib/cql/protocol/encoding.rb +5 -1
- data/lib/cql/protocol/requests/register_request.rb +2 -0
- data/lib/cql/protocol/type_converter.rb +1 -0
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/asynchronous_client_spec.rb +368 -175
- data/spec/cql/client/asynchronous_prepared_statement_spec.rb +132 -22
- data/spec/cql/client/connection_helper_spec.rb +335 -0
- data/spec/cql/client/connection_manager_spec.rb +118 -0
- data/spec/cql/client/keyspace_changer_spec.rb +50 -0
- data/spec/cql/client/request_runner_spec.rb +12 -12
- data/spec/cql/client/synchronous_client_spec.rb +15 -15
- data/spec/cql/client/synchronous_prepared_statement_spec.rb +15 -11
- data/spec/cql/future_spec.rb +529 -301
- data/spec/cql/io/connection_spec.rb +12 -12
- data/spec/cql/io/io_reactor_spec.rb +61 -61
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +26 -12
- data/spec/cql/protocol/encoding_spec.rb +5 -0
- data/spec/cql/protocol/type_converter_spec.rb +1 -1
- data/spec/cql/time_uuid_spec.rb +7 -7
- data/spec/integration/client_spec.rb +2 -2
- data/spec/integration/io_spec.rb +20 -20
- data/spec/integration/protocol_spec.rb +17 -17
- data/spec/integration/regression_spec.rb +6 -0
- data/spec/integration/uuid_spec.rb +4 -0
- data/spec/support/fake_io_reactor.rb +38 -8
- data/spec/support/fake_server.rb +3 -3
- metadata +12 -2
@@ -11,19 +11,19 @@ module Cql
|
|
11
11
|
end
|
12
12
|
|
13
13
|
let :unblocker do
|
14
|
-
|
14
|
+
double(:unblocker, unblock!: nil)
|
15
15
|
end
|
16
16
|
|
17
17
|
let :socket_impl do
|
18
|
-
|
18
|
+
double(:socket_impl)
|
19
19
|
end
|
20
20
|
|
21
21
|
let :clock do
|
22
|
-
|
22
|
+
double(:clock, now: 0)
|
23
23
|
end
|
24
24
|
|
25
25
|
let :socket do
|
26
|
-
|
26
|
+
double(:socket)
|
27
27
|
end
|
28
28
|
|
29
29
|
before do
|
@@ -76,10 +76,10 @@ module Cql
|
|
76
76
|
end
|
77
77
|
|
78
78
|
shared_examples 'on successfull connection' do
|
79
|
-
it '
|
79
|
+
it 'fulfilles the returned future and returns itself' do
|
80
80
|
f = handler.connect
|
81
|
-
f.should
|
82
|
-
f.
|
81
|
+
f.should be_resolved
|
82
|
+
f.value.should equal(handler)
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'is connected' do
|
@@ -108,7 +108,7 @@ module Cql
|
|
108
108
|
it 'it does nothing' do
|
109
109
|
socket.stub(:connect_nonblock).and_raise(Errno::EALREADY)
|
110
110
|
f = handler.connect
|
111
|
-
f.should_not
|
111
|
+
f.should_not be_resolved
|
112
112
|
f.should_not be_failed
|
113
113
|
end
|
114
114
|
end
|
@@ -133,7 +133,7 @@ module Cql
|
|
133
133
|
it 'fails if there are no more addresses to try' do
|
134
134
|
socket.stub(:connect_nonblock).and_raise(Errno::EINVAL)
|
135
135
|
f = handler.connect
|
136
|
-
expect { f.
|
136
|
+
expect { f.value }.to raise_error(ConnectionError)
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
@@ -145,7 +145,7 @@ module Cql
|
|
145
145
|
|
146
146
|
it 'fails the future with a ConnectionError' do
|
147
147
|
f = handler.connect
|
148
|
-
expect { f.
|
148
|
+
expect { f.value }.to raise_error(ConnectionError)
|
149
149
|
end
|
150
150
|
|
151
151
|
it 'closes the socket' do
|
@@ -180,7 +180,7 @@ module Cql
|
|
180
180
|
|
181
181
|
it 'fails the returned future with a ConnectionError' do
|
182
182
|
f = handler.connect
|
183
|
-
expect { f.
|
183
|
+
expect { f.value }.to raise_error(ConnectionError)
|
184
184
|
end
|
185
185
|
|
186
186
|
it 'calls the close listener' do
|
@@ -217,7 +217,7 @@ module Cql
|
|
217
217
|
clock.stub(:now).and_return(7)
|
218
218
|
handler.connect
|
219
219
|
f.should be_failed
|
220
|
-
expect { f.
|
220
|
+
expect { f.value }.to raise_error(ConnectionTimeoutError)
|
221
221
|
end
|
222
222
|
|
223
223
|
it 'closes the connection' do
|
@@ -11,7 +11,7 @@ module Cql
|
|
11
11
|
end
|
12
12
|
|
13
13
|
let :protocol_handler_factory do
|
14
|
-
|
14
|
+
double(:protocol_handler_factory)
|
15
15
|
end
|
16
16
|
|
17
17
|
let! :selector do
|
@@ -19,61 +19,61 @@ module Cql
|
|
19
19
|
end
|
20
20
|
|
21
21
|
let :clock do
|
22
|
-
|
22
|
+
double(:clock, now: 0)
|
23
23
|
end
|
24
24
|
|
25
25
|
describe '#start' do
|
26
26
|
after do
|
27
|
-
reactor.stop.
|
27
|
+
reactor.stop.value if reactor.running?
|
28
28
|
end
|
29
29
|
|
30
|
-
it 'returns a future that
|
31
|
-
reactor.start.
|
30
|
+
it 'returns a future that is resolved when the reactor has started' do
|
31
|
+
reactor.start.value
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'returns a future that resolves to the reactor' do
|
35
|
-
reactor.start.
|
35
|
+
reactor.start.value.should equal(reactor)
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'is running after being started' do
|
39
|
-
reactor.start.
|
39
|
+
reactor.start.value
|
40
40
|
reactor.should be_running
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'cannot be started again once stopped' do
|
44
|
-
reactor.start.
|
45
|
-
reactor.stop.
|
44
|
+
reactor.start.value
|
45
|
+
reactor.stop.value
|
46
46
|
expect { reactor.start }.to raise_error(ReactorError)
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'calls the selector' do
|
50
50
|
called = false
|
51
51
|
selector.handler { called = true; [[], [], []] }
|
52
|
-
reactor.start.
|
52
|
+
reactor.start.value
|
53
53
|
await { called }
|
54
|
-
reactor.stop.
|
54
|
+
reactor.stop.value
|
55
55
|
called.should be_true, 'expected the selector to have been called'
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
describe '#stop' do
|
60
60
|
after do
|
61
|
-
reactor.stop.
|
61
|
+
reactor.stop.value if reactor.running?
|
62
62
|
end
|
63
63
|
|
64
|
-
it 'returns a future
|
65
|
-
reactor.start.
|
66
|
-
reactor.stop.
|
64
|
+
it 'returns a future that is resolved when the reactor has stopped' do
|
65
|
+
reactor.start.value
|
66
|
+
reactor.stop.value
|
67
67
|
end
|
68
68
|
|
69
69
|
it 'returns a future which resolves to the reactor' do
|
70
|
-
reactor.start.
|
71
|
-
reactor.stop.
|
70
|
+
reactor.start.value
|
71
|
+
reactor.stop.value.should equal(reactor)
|
72
72
|
end
|
73
73
|
|
74
74
|
it 'is not running after being stopped' do
|
75
|
-
reactor.start.
|
76
|
-
reactor.stop.
|
75
|
+
reactor.start.value
|
76
|
+
reactor.stop.value
|
77
77
|
reactor.should_not be_running
|
78
78
|
end
|
79
79
|
|
@@ -81,24 +81,24 @@ module Cql
|
|
81
81
|
connection = nil
|
82
82
|
protocol_handler_factory.stub(:new) do |sh|
|
83
83
|
connection = sh
|
84
|
-
|
84
|
+
double(:protocol_handler)
|
85
85
|
end
|
86
|
-
reactor.start.
|
86
|
+
reactor.start.value
|
87
87
|
reactor.connect('example.com', 9999, 5)
|
88
|
-
reactor.stop.
|
88
|
+
reactor.stop.value
|
89
89
|
connection.should be_closed
|
90
90
|
end
|
91
91
|
|
92
92
|
it 'cancels all active timers' do
|
93
|
-
reactor.start.
|
93
|
+
reactor.start.value
|
94
94
|
clock.stub(:now).and_return(1)
|
95
95
|
expired_timer = reactor.schedule_timer(1)
|
96
96
|
active_timer1 = reactor.schedule_timer(999)
|
97
97
|
active_timer2 = reactor.schedule_timer(111)
|
98
|
-
expired_timer.should_not_receive(:fail
|
98
|
+
expired_timer.should_not_receive(:fail)
|
99
99
|
clock.stub(:now).and_return(2)
|
100
|
-
await { expired_timer.
|
101
|
-
reactor.stop.
|
100
|
+
await { expired_timer.completed? }
|
101
|
+
reactor.stop.value
|
102
102
|
active_timer1.should be_failed
|
103
103
|
active_timer2.should be_failed
|
104
104
|
end
|
@@ -119,7 +119,7 @@ module Cql
|
|
119
119
|
|
120
120
|
it 'calls the listener immediately when the reactor has already crashed' do
|
121
121
|
error = nil
|
122
|
-
reactor.start.
|
122
|
+
reactor.start.value
|
123
123
|
await { !reactor.running? }
|
124
124
|
reactor.on_error { |e| error = e }
|
125
125
|
await { error }
|
@@ -137,7 +137,7 @@ module Cql
|
|
137
137
|
|
138
138
|
describe '#connect' do
|
139
139
|
let :protocol_handler do
|
140
|
-
|
140
|
+
double(:protocol_handler)
|
141
141
|
end
|
142
142
|
|
143
143
|
before do
|
@@ -166,14 +166,14 @@ module Cql
|
|
166
166
|
end
|
167
167
|
|
168
168
|
it 'returns a future that resolves to a new protocol handler' do
|
169
|
-
reactor.start.
|
169
|
+
reactor.start.value
|
170
170
|
f = reactor.connect('example.com', 9999, 5)
|
171
|
-
f.
|
171
|
+
f.value.should equal(protocol_handler)
|
172
172
|
end
|
173
173
|
|
174
174
|
it 'returns a new protocol handler which wraps a socket handler' do
|
175
|
-
reactor.start.
|
176
|
-
protocol_handler = reactor.connect('example.com', 9999, 5).
|
175
|
+
reactor.start.value
|
176
|
+
protocol_handler = reactor.connect('example.com', 9999, 5).value
|
177
177
|
protocol_handler.connection.should_not be_nil
|
178
178
|
protocol_handler.connection.host.should == 'example.com'
|
179
179
|
protocol_handler.connection.port.should == 9999
|
@@ -183,18 +183,18 @@ module Cql
|
|
183
183
|
|
184
184
|
describe '#schedule_timer' do
|
185
185
|
before do
|
186
|
-
reactor.start.
|
186
|
+
reactor.start.value
|
187
187
|
end
|
188
188
|
|
189
189
|
after do
|
190
|
-
reactor.stop.
|
190
|
+
reactor.stop.value
|
191
191
|
end
|
192
192
|
|
193
|
-
it 'returns a future that
|
193
|
+
it 'returns a future that is resolved after the specified duration' do
|
194
194
|
clock.stub(:now).and_return(1)
|
195
195
|
f = reactor.schedule_timer(0.1)
|
196
196
|
clock.stub(:now).and_return(1.1)
|
197
|
-
await { f.
|
197
|
+
await { f.resolved? }
|
198
198
|
end
|
199
199
|
end
|
200
200
|
|
@@ -218,15 +218,15 @@ module Cql
|
|
218
218
|
end
|
219
219
|
|
220
220
|
let :selector do
|
221
|
-
|
221
|
+
double(:selector)
|
222
222
|
end
|
223
223
|
|
224
224
|
let :clock do
|
225
|
-
|
225
|
+
double(:clock, now: 0)
|
226
226
|
end
|
227
227
|
|
228
228
|
let :socket do
|
229
|
-
|
229
|
+
double(:socket, connected?: false, connecting?: false, writable?: false, closed?: false)
|
230
230
|
end
|
231
231
|
|
232
232
|
describe '#tick' do
|
@@ -295,32 +295,32 @@ module Cql
|
|
295
295
|
it 'completes timers that have expired' do
|
296
296
|
selector.stub(:select).and_return([nil, nil, nil])
|
297
297
|
clock.stub(:now).and_return(1)
|
298
|
-
|
299
|
-
loop_body.schedule_timer(1,
|
298
|
+
promise = Promise.new
|
299
|
+
loop_body.schedule_timer(1, promise)
|
300
300
|
loop_body.tick
|
301
|
-
future.should_not
|
301
|
+
promise.future.should_not be_completed
|
302
302
|
clock.stub(:now).and_return(2)
|
303
303
|
loop_body.tick
|
304
|
-
future.should
|
304
|
+
promise.future.should be_completed
|
305
305
|
end
|
306
306
|
|
307
307
|
it 'clears out timers that have expired' do
|
308
308
|
selector.stub(:select).and_return([nil, nil, nil])
|
309
309
|
clock.stub(:now).and_return(1)
|
310
|
-
|
311
|
-
loop_body.schedule_timer(1,
|
310
|
+
promise = Promise.new
|
311
|
+
loop_body.schedule_timer(1, promise)
|
312
312
|
clock.stub(:now).and_return(2)
|
313
313
|
loop_body.tick
|
314
|
-
future.should
|
315
|
-
|
314
|
+
promise.future.should be_completed
|
315
|
+
promise.should_not_receive(:fulfill)
|
316
316
|
loop_body.tick
|
317
317
|
end
|
318
318
|
end
|
319
319
|
|
320
320
|
describe '#close_sockets' do
|
321
321
|
it 'closes all sockets' do
|
322
|
-
socket1 =
|
323
|
-
socket2 =
|
322
|
+
socket1 = double(:socket1, closed?: false)
|
323
|
+
socket2 = double(:socket2, closed?: false)
|
324
324
|
socket1.should_receive(:close)
|
325
325
|
socket2.should_receive(:close)
|
326
326
|
loop_body.add_socket(socket1)
|
@@ -329,8 +329,8 @@ module Cql
|
|
329
329
|
end
|
330
330
|
|
331
331
|
it 'closes all sockets, even when one of them raises an error' do
|
332
|
-
socket1 =
|
333
|
-
socket2 =
|
332
|
+
socket1 = double(:socket1, closed?: false)
|
333
|
+
socket2 = double(:socket2, closed?: false)
|
334
334
|
socket1.stub(:close).and_raise('Blurgh')
|
335
335
|
socket2.should_receive(:close)
|
336
336
|
loop_body.add_socket(socket1)
|
@@ -352,20 +352,20 @@ module Cql
|
|
352
352
|
end
|
353
353
|
|
354
354
|
it 'fails all active timers with a CancelledError' do
|
355
|
-
|
356
|
-
|
357
|
-
|
355
|
+
p1 = Promise.new
|
356
|
+
p2 = Promise.new
|
357
|
+
p3 = Promise.new
|
358
358
|
clock.stub(:now).and_return(1)
|
359
|
-
loop_body.schedule_timer(1,
|
360
|
-
loop_body.schedule_timer(3,
|
361
|
-
loop_body.schedule_timer(3,
|
359
|
+
loop_body.schedule_timer(1, p1)
|
360
|
+
loop_body.schedule_timer(3, p2)
|
361
|
+
loop_body.schedule_timer(3, p3)
|
362
362
|
clock.stub(:now).and_return(2)
|
363
363
|
loop_body.tick
|
364
364
|
loop_body.cancel_timers
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
expect {
|
365
|
+
p1.future.should be_completed
|
366
|
+
p2.future.should be_failed
|
367
|
+
p3.future.should be_failed
|
368
|
+
expect { p3.future.value }.to raise_error(CancelledError)
|
369
369
|
end
|
370
370
|
end
|
371
371
|
end
|
@@ -11,7 +11,7 @@ module Cql
|
|
11
11
|
end
|
12
12
|
|
13
13
|
let :connection do
|
14
|
-
|
14
|
+
double(:connection)
|
15
15
|
end
|
16
16
|
|
17
17
|
let :request do
|
@@ -48,6 +48,20 @@ module Cql
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
describe '#host' do
|
52
|
+
it 'delegates to the connection' do
|
53
|
+
connection.stub(:host).and_return('example.com')
|
54
|
+
protocol_handler.host.should == 'example.com'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#port' do
|
59
|
+
it 'delegates to the connection' do
|
60
|
+
connection.stub(:port).and_return(9042)
|
61
|
+
protocol_handler.port.should == 9042
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
51
65
|
describe '#send_request' do
|
52
66
|
before do
|
53
67
|
connection.stub(:write).and_yield(buffer)
|
@@ -71,27 +85,27 @@ module Cql
|
|
71
85
|
protocol_handler.send_request(request).should be_a(Future)
|
72
86
|
end
|
73
87
|
|
74
|
-
it '
|
88
|
+
it 'succeeds the future when it receives a response frame with the corresponding stream ID' do
|
75
89
|
3.times { protocol_handler.send_request(request) }
|
76
90
|
future = protocol_handler.send_request(request)
|
77
91
|
connection.data_listener.call([0x81, 0, 3, 2, 0].pack('C4N'))
|
78
|
-
await(0.1) { future.
|
92
|
+
await(0.1) { future.resolved? }
|
79
93
|
end
|
80
94
|
|
81
95
|
it 'handles multiple response frames in the same data packet' do
|
82
96
|
futures = Array.new(4) { protocol_handler.send_request(request) }
|
83
97
|
connection.data_listener.call([0x81, 0, 2, 2, 0].pack('C4N') + [0x81, 0, 3, 2, 0].pack('C4N'))
|
84
|
-
await(0.1) { futures[2].
|
98
|
+
await(0.1) { futures[2].resolved? && futures[3].resolved? }
|
85
99
|
end
|
86
100
|
|
87
101
|
it 'queues the request when there are too many in flight, sending it as soon as a stream is available' do
|
88
102
|
connection.stub(:write)
|
89
103
|
futures = Array.new(130) { protocol_handler.send_request(request) }
|
90
104
|
128.times { |i| connection.data_listener.call([0x81, 0, i, 2, 0].pack('C4N')) }
|
91
|
-
futures[127].should
|
92
|
-
futures[128].should_not
|
105
|
+
futures[127].should be_resolved
|
106
|
+
futures[128].should_not be_resolved
|
93
107
|
2.times { |i| connection.data_listener.call([0x81, 0, i, 2, 0].pack('C4N')) }
|
94
|
-
futures[128].should
|
108
|
+
futures[128].should be_resolved
|
95
109
|
end
|
96
110
|
|
97
111
|
context 'when the protocol handler closes' do
|
@@ -113,7 +127,7 @@ module Cql
|
|
113
127
|
connection.data_listener.call([0x81, 0, 0, 2, 0].pack('C4N'))
|
114
128
|
connection.closed_listener.call(nil)
|
115
129
|
begin
|
116
|
-
future.
|
130
|
+
future.value
|
117
131
|
rescue => e
|
118
132
|
e.should be_a(Cql::Io::ConnectionClosedError)
|
119
133
|
else
|
@@ -134,7 +148,7 @@ module Cql
|
|
134
148
|
it 'fails all requests with NotConnectedError' do
|
135
149
|
connection.stub(:closed?).and_return(true)
|
136
150
|
f = protocol_handler.send_request(request)
|
137
|
-
expect { f.
|
151
|
+
expect { f.value }.to raise_error(NotConnectedError)
|
138
152
|
end
|
139
153
|
end
|
140
154
|
end
|
@@ -145,11 +159,11 @@ module Cql
|
|
145
159
|
protocol_handler.close
|
146
160
|
end
|
147
161
|
|
148
|
-
it 'returns a future which
|
162
|
+
it 'returns a future which succeeds when the socket has closed' do
|
149
163
|
connection.stub(:close) do
|
150
164
|
connection.closed_listener.call(nil)
|
151
165
|
end
|
152
|
-
protocol_handler.close.
|
166
|
+
protocol_handler.close.value
|
153
167
|
end
|
154
168
|
end
|
155
169
|
|
@@ -167,7 +181,7 @@ module Cql
|
|
167
181
|
it 'registers the keyspace it has changed to' do
|
168
182
|
f = protocol_handler.send_request(Protocol::QueryRequest.new('USE hello', :one))
|
169
183
|
connection.data_listener.call([0x81, 0, 0, 8, 4 + 2 + 5, 3, 5].pack('C4N2n') + 'hello')
|
170
|
-
f.
|
184
|
+
f.value
|
171
185
|
protocol_handler.keyspace.should == 'hello'
|
172
186
|
end
|
173
187
|
end
|