cql-rb 1.1.0.pre0 → 1.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cql/byte_buffer.rb +1 -0
- data/lib/cql/client.rb +20 -8
- data/lib/cql/client/asynchronous_client.rb +128 -43
- data/lib/cql/client/synchronous_client.rb +25 -5
- data/lib/cql/client/synchronous_prepared_statement.rb +4 -2
- data/lib/cql/future.rb +97 -0
- data/lib/cql/io/connection.rb +1 -0
- data/lib/cql/io/io_reactor.rb +2 -0
- data/lib/cql/protocol/cql_protocol_handler.rb +16 -1
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/asynchronous_client_spec.rb +286 -52
- data/spec/cql/client/synchronous_client_spec.rb +24 -1
- data/spec/cql/client/synchronous_prepared_statement_spec.rb +24 -0
- data/spec/cql/future_spec.rb +134 -0
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +7 -0
- data/spec/support/fake_io_reactor.rb +53 -13
- metadata +2 -4
- data/spec/cql/client/client_shared.rb +0 -27
data/lib/cql/io/connection.rb
CHANGED
data/lib/cql/io/io_reactor.rb
CHANGED
@@ -10,7 +10,7 @@ module Cql
|
|
10
10
|
#
|
11
11
|
# Instances of this class are thread safe.
|
12
12
|
#
|
13
|
-
# @
|
13
|
+
# @example Sending an OPTIONS request
|
14
14
|
# future = protocol_handler.send_request(Cql::Protocol::OptionsRequest.new)
|
15
15
|
# response = future.get
|
16
16
|
# puts "These options are supported: #{response.options}"
|
@@ -29,11 +29,26 @@ module Cql
|
|
29
29
|
@request_queue_in = []
|
30
30
|
@request_queue_out = []
|
31
31
|
@event_listeners = []
|
32
|
+
@data = {}
|
32
33
|
@lock = Mutex.new
|
33
34
|
@closed_future = Future.new
|
34
35
|
@keyspace = nil
|
35
36
|
end
|
36
37
|
|
38
|
+
# Associate arbitrary data with this protocol handler object. This is
|
39
|
+
# useful in situations where additional metadata can be loaded after the
|
40
|
+
# connection has been set up, or to keep statistics specific to the
|
41
|
+
# connection this protocol handler wraps.
|
42
|
+
def []=(key, value)
|
43
|
+
@lock.synchronize { @data[key] = value }
|
44
|
+
end
|
45
|
+
|
46
|
+
# @see {#[]=}
|
47
|
+
# @return the value associated with the key
|
48
|
+
def [](key)
|
49
|
+
@lock.synchronize { @data[key] }
|
50
|
+
end
|
51
|
+
|
37
52
|
# @return [true, false] true if the underlying connection is connected
|
38
53
|
def connected?
|
39
54
|
@connection.connected?
|
data/lib/cql/version.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
|
-
require 'cql/client/client_shared'
|
5
4
|
|
6
5
|
|
7
6
|
module Cql
|
@@ -11,7 +10,48 @@ module Cql
|
|
11
10
|
described_class.new(connection_options)
|
12
11
|
end
|
13
12
|
|
14
|
-
|
13
|
+
let :connection_options do
|
14
|
+
{:host => 'example.com', :port => 12321, :io_reactor => io_reactor}
|
15
|
+
end
|
16
|
+
|
17
|
+
let :io_reactor do
|
18
|
+
FakeIoReactor.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def connections
|
22
|
+
io_reactor.connections
|
23
|
+
end
|
24
|
+
|
25
|
+
def last_connection
|
26
|
+
connections.last
|
27
|
+
end
|
28
|
+
|
29
|
+
def requests
|
30
|
+
last_connection.requests
|
31
|
+
end
|
32
|
+
|
33
|
+
def last_request
|
34
|
+
requests.last
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle_request(&handler)
|
38
|
+
@request_handler = handler
|
39
|
+
end
|
40
|
+
|
41
|
+
before do
|
42
|
+
io_reactor.on_connection do |connection|
|
43
|
+
connection.handle_request do |request|
|
44
|
+
response = nil
|
45
|
+
if @request_handler
|
46
|
+
response = @request_handler.call(request, connection, proc { connection.default_request_handler(request) })
|
47
|
+
end
|
48
|
+
unless response
|
49
|
+
response = connection.default_request_handler(request)
|
50
|
+
end
|
51
|
+
response
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
15
55
|
|
16
56
|
describe '#connect' do
|
17
57
|
it 'connects' do
|
@@ -25,14 +65,45 @@ module Cql
|
|
25
65
|
connections.should have(1).item
|
26
66
|
end
|
27
67
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
68
|
+
context 'when connecting to multiple hosts' do
|
69
|
+
before do
|
70
|
+
client.close.get
|
71
|
+
io_reactor.stop.get
|
72
|
+
end
|
32
73
|
|
33
|
-
|
34
|
-
|
35
|
-
|
74
|
+
it 'connects to all hosts' do
|
75
|
+
c = described_class.new(connection_options.merge(hosts: %w[h1.example.com h2.example.com h3.example.com]))
|
76
|
+
c.connect.get
|
77
|
+
connections.should have(3).items
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'connects to all hosts, when given as a comma-sepatated string' do
|
81
|
+
c = described_class.new(connection_options.merge(host: 'h1.example.com,h2.example.com,h3.example.com'))
|
82
|
+
c.connect.get
|
83
|
+
connections.should have(3).items
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'only connects to each host once' do
|
87
|
+
c = described_class.new(connection_options.merge(hosts: %w[h1.example.com h2.example.com h2.example.com]))
|
88
|
+
c.connect.get
|
89
|
+
connections.should have(2).items
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'succeeds even if only one of the connections succeeded' do
|
93
|
+
io_reactor.node_down('h1.example.com')
|
94
|
+
io_reactor.node_down('h3.example.com')
|
95
|
+
c = described_class.new(connection_options.merge(hosts: %w[h1.example.com h2.example.com h2.example.com]))
|
96
|
+
c.connect.get
|
97
|
+
connections.should have(1).items
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'fails when all nodes are down' do
|
101
|
+
io_reactor.node_down('h1.example.com')
|
102
|
+
io_reactor.node_down('h2.example.com')
|
103
|
+
io_reactor.node_down('h3.example.com')
|
104
|
+
c = described_class.new(connection_options.merge(hosts: %w[h1.example.com h2.example.com h2.example.com]))
|
105
|
+
expect { c.connect.get }.to raise_error(Io::ConnectionError)
|
106
|
+
end
|
36
107
|
end
|
37
108
|
|
38
109
|
it 'returns itself' do
|
@@ -52,7 +123,7 @@ module Cql
|
|
52
123
|
|
53
124
|
it 'sends a startup request' do
|
54
125
|
client.connect.get
|
55
|
-
|
126
|
+
requests.first.should be_a(Protocol::StartupRequest)
|
56
127
|
end
|
57
128
|
|
58
129
|
it 'sends a startup request to each connection' do
|
@@ -60,10 +131,10 @@ module Cql
|
|
60
131
|
io_reactor.stop.get
|
61
132
|
io_reactor.start.get
|
62
133
|
|
63
|
-
c = described_class.new(connection_options.merge(
|
134
|
+
c = described_class.new(connection_options.merge(hosts: %w[h1.example.com h2.example.com h3.example.com]))
|
64
135
|
c.connect.get
|
65
136
|
connections.each do |cc|
|
66
|
-
cc.requests.
|
137
|
+
cc.requests.first.should be_a(Protocol::StartupRequest)
|
67
138
|
end
|
68
139
|
end
|
69
140
|
|
@@ -75,7 +146,8 @@ module Cql
|
|
75
146
|
it 'changes to the keyspace given as an option' do
|
76
147
|
c = described_class.new(connection_options.merge(:keyspace => 'hello_world'))
|
77
148
|
c.connect.get
|
78
|
-
|
149
|
+
request = requests.find { |rq| rq == Protocol::QueryRequest.new('USE hello_world', :one) }
|
150
|
+
request.should_not be_nil, 'expected a USE request to have been sent'
|
79
151
|
end
|
80
152
|
|
81
153
|
it 'validates the keyspace name before sending the USE command' do
|
@@ -84,6 +156,107 @@ module Cql
|
|
84
156
|
requests.should_not include(Protocol::QueryRequest.new('USE system; DROP KEYSPACE system', :one))
|
85
157
|
end
|
86
158
|
|
159
|
+
context 'with automatic peer discovery' do
|
160
|
+
let :local_info do
|
161
|
+
{
|
162
|
+
'data_center' => 'dc1',
|
163
|
+
'host_id' => nil,
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
let :local_metadata do
|
168
|
+
[
|
169
|
+
['system', 'local', 'data_center', :text],
|
170
|
+
['system', 'local', 'host_id', :uuid],
|
171
|
+
]
|
172
|
+
end
|
173
|
+
|
174
|
+
let :peer_metadata do
|
175
|
+
[
|
176
|
+
['system', 'peers', 'peer', :inet],
|
177
|
+
['system', 'peers', 'data_center', :varchar],
|
178
|
+
['system', 'peers', 'host_id', :uuid],
|
179
|
+
['system', 'peers', 'rpc_address', :inet],
|
180
|
+
]
|
181
|
+
end
|
182
|
+
|
183
|
+
let :data_centers do
|
184
|
+
Hash.new('dc1')
|
185
|
+
end
|
186
|
+
|
187
|
+
let :additional_nodes do
|
188
|
+
Array.new(5) { IPAddr.new("127.0.#{rand(255)}.#{rand(255)}") }
|
189
|
+
end
|
190
|
+
|
191
|
+
before do
|
192
|
+
uuid_generator = TimeUuid::Generator.new
|
193
|
+
additional_rpc_addresses = additional_nodes.dup
|
194
|
+
io_reactor.on_connection do |connection|
|
195
|
+
connection[:spec_host_id] = uuid_generator.next
|
196
|
+
connection[:spec_data_center] = data_centers[connection.host]
|
197
|
+
connection.handle_request do |request|
|
198
|
+
case request
|
199
|
+
when Protocol::StartupRequest
|
200
|
+
Protocol::ReadyResponse.new
|
201
|
+
when Protocol::QueryRequest
|
202
|
+
case request.cql
|
203
|
+
when /FROM system\.local/
|
204
|
+
row = {'host_id' => connection[:spec_host_id], 'data_center' => connection[:spec_data_center]}
|
205
|
+
Protocol::RowsResultResponse.new([row], local_metadata)
|
206
|
+
when /FROM system\.peers/
|
207
|
+
other_host_ids = connections.reject { |c| c[:spec_host_id] == connection[:spec_host_id] }.map { |c| c[:spec_host_id] }
|
208
|
+
until other_host_ids.size >= 2
|
209
|
+
other_host_ids << uuid_generator.next
|
210
|
+
end
|
211
|
+
rows = other_host_ids.map do |host_id|
|
212
|
+
ip = additional_rpc_addresses.shift
|
213
|
+
{'host_id' => host_id, 'data_center' => data_centers[ip], 'rpc_address' => ip}
|
214
|
+
end
|
215
|
+
Protocol::RowsResultResponse.new(rows, peer_metadata)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'connects to the other nodes in the cluster' do
|
223
|
+
client.connect.get
|
224
|
+
connections.should have(3).items
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'connects to the other nodes in the same data center' do
|
228
|
+
data_centers[additional_nodes[1]] = 'dc2'
|
229
|
+
client.connect.get
|
230
|
+
connections.should have(2).items
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'connects to the other nodes in same data centers as the seed nodes' do
|
234
|
+
data_centers['host2'] = 'dc2'
|
235
|
+
data_centers[additional_nodes[1]] = 'dc2'
|
236
|
+
c = described_class.new(connection_options.merge(hosts: %w[host1 host2]))
|
237
|
+
c.connect.get
|
238
|
+
connections.should have(3).items
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'only connects to the other nodes in the cluster it is not already connected do' do
|
242
|
+
c = described_class.new(connection_options.merge(hosts: %w[host1 host2]))
|
243
|
+
c.connect.get
|
244
|
+
connections.should have(3).items
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'handles the case when it is already connected to all nodes' do
|
248
|
+
c = described_class.new(connection_options.merge(hosts: %w[host1 host2 host3 host4]))
|
249
|
+
c.connect.get
|
250
|
+
connections.should have(4).items
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'accepts that some nodes are down' do
|
254
|
+
io_reactor.node_down(additional_nodes.first.to_s)
|
255
|
+
client.connect.get
|
256
|
+
connections.should have(2).items
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
87
260
|
it 're-raises any errors raised' do
|
88
261
|
io_reactor.stub(:connect).and_raise(ArgumentError)
|
89
262
|
expect { client.connect.get }.to raise_error(ArgumentError)
|
@@ -102,24 +275,45 @@ module Cql
|
|
102
275
|
end
|
103
276
|
|
104
277
|
it 'is not connected while connecting' do
|
278
|
+
go = false
|
105
279
|
io_reactor.stop.get
|
106
|
-
|
107
|
-
client.
|
108
|
-
|
109
|
-
|
280
|
+
io_reactor.before_startup { sleep 0.01 until go }
|
281
|
+
client.connect
|
282
|
+
begin
|
283
|
+
client.should_not be_connected
|
284
|
+
ensure
|
285
|
+
go = true
|
286
|
+
end
|
110
287
|
end
|
111
288
|
|
112
289
|
context 'when the server requests authentication' do
|
113
|
-
|
114
|
-
|
115
|
-
|
290
|
+
def accepting_request_handler(request, *)
|
291
|
+
case request
|
292
|
+
when Protocol::StartupRequest
|
293
|
+
Protocol::AuthenticateResponse.new('com.example.Auth')
|
294
|
+
when Protocol::CredentialsRequest
|
295
|
+
Protocol::ReadyResponse.new
|
116
296
|
end
|
117
297
|
end
|
118
298
|
|
299
|
+
def denying_request_handler(request, *)
|
300
|
+
case request
|
301
|
+
when Protocol::StartupRequest
|
302
|
+
Protocol::AuthenticateResponse.new('com.example.Auth')
|
303
|
+
when Protocol::CredentialsRequest
|
304
|
+
Protocol::ErrorResponse.new(256, 'No way, José')
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
before do
|
309
|
+
handle_request(&method(:accepting_request_handler))
|
310
|
+
end
|
311
|
+
|
119
312
|
it 'sends credentials' do
|
120
313
|
client = described_class.new(connection_options.merge(credentials: {'username' => 'foo', 'password' => 'bar'}))
|
121
314
|
client.connect.get
|
122
|
-
|
315
|
+
request = requests.find { |rq| rq == Protocol::CredentialsRequest.new('username' => 'foo', 'password' => 'bar') }
|
316
|
+
request.should_not be_nil, 'expected a credentials request to have been sent'
|
123
317
|
end
|
124
318
|
|
125
319
|
it 'raises an error when no credentials have been given' do
|
@@ -128,17 +322,13 @@ module Cql
|
|
128
322
|
end
|
129
323
|
|
130
324
|
it 'raises an error when the server responds with an error to the credentials request' do
|
131
|
-
|
132
|
-
connection.queue_response(Protocol::ErrorResponse.new(256, 'No way, José'))
|
133
|
-
end
|
325
|
+
handle_request(&method(:denying_request_handler))
|
134
326
|
client = described_class.new(connection_options.merge(credentials: {'username' => 'foo', 'password' => 'bar'}))
|
135
327
|
expect { client.connect.get }.to raise_error(AuthenticationError)
|
136
328
|
end
|
137
329
|
|
138
330
|
it 'shuts down the client when there is an authentication error' do
|
139
|
-
|
140
|
-
connection.queue_response(Protocol::ErrorResponse.new(256, 'No way, José'))
|
141
|
-
end
|
331
|
+
handle_request(&method(:denying_request_handler))
|
142
332
|
client = described_class.new(connection_options.merge(credentials: {'username' => 'foo', 'password' => 'bar'}))
|
143
333
|
client.connect.get rescue nil
|
144
334
|
client.should_not be_connected
|
@@ -175,14 +365,13 @@ module Cql
|
|
175
365
|
end
|
176
366
|
|
177
367
|
describe '#use' do
|
178
|
-
before do
|
179
|
-
client.connect.get
|
180
|
-
end
|
181
|
-
|
182
368
|
it 'executes a USE query' do
|
183
|
-
|
184
|
-
|
369
|
+
handle_request do |request|
|
370
|
+
if request.is_a?(Protocol::QueryRequest) && request.cql == 'USE system'
|
371
|
+
Protocol::SetKeyspaceResultResponse.new('system')
|
372
|
+
end
|
185
373
|
end
|
374
|
+
client.connect.get
|
186
375
|
client.use('system').get
|
187
376
|
last_request.should == Protocol::QueryRequest.new('USE system', :one)
|
188
377
|
end
|
@@ -192,7 +381,7 @@ module Cql
|
|
192
381
|
io_reactor.stop.get
|
193
382
|
io_reactor.start.get
|
194
383
|
|
195
|
-
c = described_class.new(connection_options.merge(
|
384
|
+
c = described_class.new(connection_options.merge(hosts: %w[h1.example.com h2.example.com h3.example.com]))
|
196
385
|
c.connect.get
|
197
386
|
|
198
387
|
c.use('system').get
|
@@ -205,12 +394,18 @@ module Cql
|
|
205
394
|
end
|
206
395
|
|
207
396
|
it 'knows which keyspace it changed to' do
|
208
|
-
|
397
|
+
handle_request do |request|
|
398
|
+
if request.is_a?(Protocol::QueryRequest) && request.cql == 'USE system'
|
399
|
+
Protocol::SetKeyspaceResultResponse.new('system')
|
400
|
+
end
|
401
|
+
end
|
402
|
+
client.connect.get
|
209
403
|
client.use('system').get
|
210
404
|
client.keyspace.should == 'system'
|
211
405
|
end
|
212
406
|
|
213
407
|
it 'raises an error if the keyspace name is not valid' do
|
408
|
+
client.connect.get
|
214
409
|
expect { client.use('system; DROP KEYSPACE system').get }.to raise_error(InvalidKeyspaceNameError)
|
215
410
|
end
|
216
411
|
end
|
@@ -232,7 +427,11 @@ module Cql
|
|
232
427
|
|
233
428
|
context 'with a void CQL query' do
|
234
429
|
it 'returns nil' do
|
235
|
-
|
430
|
+
handle_request do |request|
|
431
|
+
if request.is_a?(Protocol::QueryRequest) && request.cql =~ /UPDATE/
|
432
|
+
Protocol::VoidResultResponse.new
|
433
|
+
end
|
434
|
+
end
|
236
435
|
result = client.execute('UPDATE stuff SET thing = 1 WHERE id = 3').get
|
237
436
|
result.should be_nil
|
238
437
|
end
|
@@ -240,13 +439,21 @@ module Cql
|
|
240
439
|
|
241
440
|
context 'with a USE query' do
|
242
441
|
it 'returns nil' do
|
243
|
-
|
442
|
+
handle_request do |request|
|
443
|
+
if request.is_a?(Protocol::QueryRequest) && request.cql == 'USE system'
|
444
|
+
Protocol::SetKeyspaceResultResponse.new('system')
|
445
|
+
end
|
446
|
+
end
|
244
447
|
result = client.execute('USE system').get
|
245
448
|
result.should be_nil
|
246
449
|
end
|
247
450
|
|
248
451
|
it 'knows which keyspace it changed to' do
|
249
|
-
|
452
|
+
handle_request do |request|
|
453
|
+
if request.is_a?(Protocol::QueryRequest) && request.cql == 'USE system'
|
454
|
+
Protocol::SetKeyspaceResultResponse.new('system')
|
455
|
+
end
|
456
|
+
end
|
250
457
|
client.execute('USE system').get
|
251
458
|
client.keyspace.should == 'system'
|
252
459
|
end
|
@@ -256,12 +463,14 @@ module Cql
|
|
256
463
|
io_reactor.stop.get
|
257
464
|
io_reactor.start.get
|
258
465
|
|
259
|
-
|
260
|
-
|
466
|
+
handle_request do |request, connection|
|
467
|
+
if request.is_a?(Protocol::QueryRequest) && request.cql == 'USE system'
|
468
|
+
Protocol::SetKeyspaceResultResponse.new('system')
|
469
|
+
end
|
470
|
+
end
|
261
471
|
|
262
|
-
|
263
|
-
|
264
|
-
connections.find { |c| c.host == 'h3.example.com' }.queue_response(Protocol::SetKeyspaceResultResponse.new('system'))
|
472
|
+
c = described_class.new(connection_options.merge(hosts: %w[h1.example.com h2.example.com h3.example.com]))
|
473
|
+
c.connect.get
|
265
474
|
|
266
475
|
c.execute('USE system', :one).get
|
267
476
|
c.keyspace.should == 'system'
|
@@ -285,10 +494,17 @@ module Cql
|
|
285
494
|
end
|
286
495
|
|
287
496
|
let :result do
|
288
|
-
last_connection.queue_response(Protocol::RowsResultResponse.new(rows, metadata))
|
289
497
|
client.execute('SELECT * FROM things').get
|
290
498
|
end
|
291
499
|
|
500
|
+
before do
|
501
|
+
handle_request do |request|
|
502
|
+
if request.is_a?(Protocol::QueryRequest) && request.cql =~ /FROM things/
|
503
|
+
Protocol::RowsResultResponse.new(rows, metadata)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
292
508
|
it 'returns an Enumerable of rows' do
|
293
509
|
row_count = 0
|
294
510
|
result.each do |row|
|
@@ -327,13 +543,19 @@ module Cql
|
|
327
543
|
end
|
328
544
|
|
329
545
|
context 'when the response is an error' do
|
546
|
+
before do
|
547
|
+
handle_request do |request|
|
548
|
+
if request.is_a?(Protocol::QueryRequest) && request.cql =~ /FROM things/
|
549
|
+
Protocol::ErrorResponse.new(0xabcd, 'Blurgh')
|
550
|
+
end
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
330
554
|
it 'raises an error' do
|
331
|
-
last_connection.queue_response(Protocol::ErrorResponse.new(0xabcd, 'Blurgh'))
|
332
555
|
expect { client.execute('SELECT * FROM things').get }.to raise_error(QueryError, 'Blurgh')
|
333
556
|
end
|
334
557
|
|
335
558
|
it 'decorates the error with the CQL that caused it' do
|
336
|
-
last_connection.queue_response(Protocol::ErrorResponse.new(0xabcd, 'Blurgh'))
|
337
559
|
begin
|
338
560
|
client.execute('SELECT * FROM things').get
|
339
561
|
rescue QueryError => e
|
@@ -354,6 +576,14 @@ module Cql
|
|
354
576
|
[['stuff', 'things', 'item', :varchar]]
|
355
577
|
end
|
356
578
|
|
579
|
+
before do
|
580
|
+
handle_request do |request|
|
581
|
+
if request.is_a?(Protocol::PrepareRequest)
|
582
|
+
Protocol::PreparedResultResponse.new(id, metadata)
|
583
|
+
end
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
357
587
|
before do
|
358
588
|
client.connect.get
|
359
589
|
end
|
@@ -364,26 +594,22 @@ module Cql
|
|
364
594
|
end
|
365
595
|
|
366
596
|
it 'returns a prepared statement' do
|
367
|
-
last_connection.queue_response(Protocol::PreparedResultResponse.new('A' * 32, [['stuff', 'things', 'item', :varchar]]))
|
368
597
|
statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
|
369
598
|
statement.should_not be_nil
|
370
599
|
end
|
371
600
|
|
372
601
|
it 'executes a prepared statement' do
|
373
|
-
last_connection.queue_response(Protocol::PreparedResultResponse.new(id, metadata))
|
374
602
|
statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
|
375
603
|
statement.execute('foo').get
|
376
604
|
last_request.should == Protocol::ExecuteRequest.new(id, metadata, ['foo'], :quorum)
|
377
605
|
end
|
378
606
|
|
379
607
|
it 'returns a prepared statement that knows the metadata' do
|
380
|
-
last_connection.queue_response(Protocol::PreparedResultResponse.new(id, metadata))
|
381
608
|
statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
|
382
609
|
statement.metadata['item'].type == :varchar
|
383
610
|
end
|
384
611
|
|
385
612
|
it 'executes a prepared statement with a specific consistency level' do
|
386
|
-
last_connection.queue_response(Protocol::PreparedResultResponse.new(id, metadata))
|
387
613
|
statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
|
388
614
|
statement.execute('thing', :local_quorum).get
|
389
615
|
last_request.should == Protocol::ExecuteRequest.new(id, metadata, ['thing'], :local_quorum)
|
@@ -398,7 +624,11 @@ module Cql
|
|
398
624
|
|
399
625
|
context 'when there is an error preparing the request' do
|
400
626
|
it 'returns a failed future' do
|
401
|
-
|
627
|
+
handle_request do |request|
|
628
|
+
if request.is_a?(Protocol::PrepareRequest)
|
629
|
+
Protocol::PreparedResultResponse.new(id, metadata)
|
630
|
+
end
|
631
|
+
end
|
402
632
|
statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
|
403
633
|
f = statement.execute
|
404
634
|
expect { f.get }.to raise_error(ArgumentError)
|
@@ -448,8 +678,12 @@ module Cql
|
|
448
678
|
end
|
449
679
|
|
450
680
|
it 'complains when #execute of a prepared statement is called after #close' do
|
681
|
+
handle_request do |request|
|
682
|
+
if request.is_a?(Protocol::PrepareRequest)
|
683
|
+
Protocol::PreparedResultResponse.new('A' * 32, [])
|
684
|
+
end
|
685
|
+
end
|
451
686
|
client.connect.get
|
452
|
-
last_connection.queue_response(Protocol::PreparedResultResponse.new('A' * 32, []))
|
453
687
|
statement = client.prepare('DELETE FROM stuff WHERE id = 3').get
|
454
688
|
client.close.get
|
455
689
|
expect { statement.execute.get }.to raise_error(NotConnectedError)
|