cql-rb 1.2.2 → 2.0.0.pre0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +4 -0
- data/README.md +139 -17
- data/lib/cql/client.rb +237 -8
- data/lib/cql/client/asynchronous_client.rb +138 -54
- data/lib/cql/client/asynchronous_prepared_statement.rb +41 -6
- data/lib/cql/client/authenticators.rb +46 -0
- data/lib/cql/client/batch.rb +115 -0
- data/lib/cql/client/connector.rb +255 -0
- data/lib/cql/client/execute_options_decoder.rb +25 -9
- data/lib/cql/client/keyspace_changer.rb +5 -5
- data/lib/cql/client/peer_discovery.rb +33 -0
- data/lib/cql/client/query_result.rb +124 -1
- data/lib/cql/client/request_runner.rb +4 -2
- data/lib/cql/client/synchronous_client.rb +14 -2
- data/lib/cql/client/synchronous_prepared_statement.rb +19 -1
- data/lib/cql/future.rb +97 -50
- data/lib/cql/io/connection.rb +0 -1
- data/lib/cql/io/io_reactor.rb +1 -1
- data/lib/cql/protocol.rb +8 -1
- data/lib/cql/protocol/cql_protocol_handler.rb +2 -2
- data/lib/cql/protocol/decoding.rb +10 -15
- data/lib/cql/protocol/frame_decoder.rb +2 -1
- data/lib/cql/protocol/frame_encoder.rb +5 -4
- data/lib/cql/protocol/requests/auth_response_request.rb +31 -0
- data/lib/cql/protocol/requests/batch_request.rb +59 -0
- data/lib/cql/protocol/requests/credentials_request.rb +1 -1
- data/lib/cql/protocol/requests/execute_request.rb +45 -17
- data/lib/cql/protocol/requests/options_request.rb +1 -1
- data/lib/cql/protocol/requests/prepare_request.rb +1 -1
- data/lib/cql/protocol/requests/query_request.rb +97 -5
- data/lib/cql/protocol/requests/register_request.rb +1 -1
- data/lib/cql/protocol/requests/startup_request.rb +4 -4
- data/lib/cql/protocol/response.rb +2 -2
- data/lib/cql/protocol/responses/auth_challenge_response.rb +25 -0
- data/lib/cql/protocol/responses/auth_success_response.rb +25 -0
- data/lib/cql/protocol/responses/authenticate_response.rb +1 -1
- data/lib/cql/protocol/responses/detailed_error_response.rb +1 -1
- data/lib/cql/protocol/responses/error_response.rb +3 -2
- data/lib/cql/protocol/responses/event_response.rb +3 -2
- data/lib/cql/protocol/responses/prepared_result_response.rb +10 -6
- data/lib/cql/protocol/responses/raw_rows_result_response.rb +27 -0
- data/lib/cql/protocol/responses/ready_response.rb +1 -1
- data/lib/cql/protocol/responses/result_response.rb +2 -2
- data/lib/cql/protocol/responses/rows_result_response.rb +43 -23
- data/lib/cql/protocol/responses/schema_change_event_response.rb +1 -1
- data/lib/cql/protocol/responses/schema_change_result_response.rb +1 -1
- data/lib/cql/protocol/responses/set_keyspace_result_response.rb +1 -1
- data/lib/cql/protocol/responses/status_change_event_response.rb +1 -1
- data/lib/cql/protocol/responses/supported_response.rb +1 -1
- data/lib/cql/protocol/responses/void_result_response.rb +1 -1
- data/lib/cql/protocol/type_converter.rb +2 -2
- data/lib/cql/uuid.rb +2 -2
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/asynchronous_client_spec.rb +493 -50
- data/spec/cql/client/asynchronous_prepared_statement_spec.rb +193 -11
- data/spec/cql/client/authenticators_spec.rb +56 -0
- data/spec/cql/client/batch_spec.rb +277 -0
- data/spec/cql/client/connector_spec.rb +606 -0
- data/spec/cql/client/execute_options_decoder_spec.rb +95 -0
- data/spec/cql/client/keyspace_changer_spec.rb +8 -8
- data/spec/cql/client/peer_discovery_spec.rb +92 -0
- data/spec/cql/client/query_result_spec.rb +352 -0
- data/spec/cql/client/request_runner_spec.rb +31 -5
- data/spec/cql/client/synchronous_client_spec.rb +44 -1
- data/spec/cql/client/synchronous_prepared_statement_spec.rb +63 -1
- data/spec/cql/future_spec.rb +50 -2
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +16 -5
- data/spec/cql/protocol/decoding_spec.rb +16 -6
- data/spec/cql/protocol/encoding_spec.rb +3 -1
- data/spec/cql/protocol/frame_encoder_spec.rb +99 -50
- data/spec/cql/protocol/requests/auth_response_request_spec.rb +62 -0
- data/spec/cql/protocol/requests/batch_request_spec.rb +155 -0
- data/spec/cql/protocol/requests/credentials_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/execute_request_spec.rb +184 -71
- data/spec/cql/protocol/requests/options_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/prepare_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/query_request_spec.rb +255 -32
- data/spec/cql/protocol/requests/register_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/startup_request_spec.rb +12 -6
- data/spec/cql/protocol/responses/auth_challenge_response_spec.rb +31 -0
- data/spec/cql/protocol/responses/auth_success_response_spec.rb +31 -0
- data/spec/cql/protocol/responses/authenticate_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/detailed_error_response_spec.rb +14 -7
- data/spec/cql/protocol/responses/error_response_spec.rb +4 -2
- data/spec/cql/protocol/responses/event_response_spec.rb +7 -4
- data/spec/cql/protocol/responses/prepared_result_response_spec.rb +89 -34
- data/spec/cql/protocol/responses/raw_rows_result_response_spec.rb +66 -0
- data/spec/cql/protocol/responses/ready_response_spec.rb +1 -1
- data/spec/cql/protocol/responses/result_response_spec.rb +19 -7
- data/spec/cql/protocol/responses/rows_result_response_spec.rb +56 -11
- data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +1 -1
- data/spec/cql/protocol/responses/status_change_event_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/supported_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/void_result_response_spec.rb +1 -1
- data/spec/cql/protocol/type_converter_spec.rb +21 -4
- data/spec/cql/uuid_spec.rb +10 -3
- data/spec/integration/client_spec.rb +251 -28
- data/spec/integration/protocol_spec.rb +213 -62
- data/spec/integration/regression_spec.rb +4 -1
- data/spec/integration/uuid_spec.rb +4 -1
- data/spec/support/fake_io_reactor.rb +5 -5
- metadata +36 -7
- data/lib/cql/client/connection_helper.rb +0 -181
- data/spec/cql/client/connection_helper_spec.rb +0 -429
@@ -35,7 +35,11 @@ module Cql
|
|
35
35
|
|
36
36
|
describe '#execute' do
|
37
37
|
let :rows_response do
|
38
|
-
Protocol::RowsResultResponse.new(rows, metadata, nil)
|
38
|
+
Protocol::RowsResultResponse.new(rows, metadata, nil, nil)
|
39
|
+
end
|
40
|
+
|
41
|
+
let :raw_rows_response do
|
42
|
+
Protocol::RawRowsResultResponse.new(2, ByteBuffer.new("\x00\x00\x00\x02\x00\x00\x00\x01a\x00\x00\x00\x01b"), nil, nil)
|
39
43
|
end
|
40
44
|
|
41
45
|
let :void_response do
|
@@ -43,7 +47,7 @@ module Cql
|
|
43
47
|
end
|
44
48
|
|
45
49
|
let :prepared_response do
|
46
|
-
Protocol::PreparedResultResponse.new("\x2a", metadata, nil)
|
50
|
+
Protocol::PreparedResultResponse.new("\x2a", metadata, nil, nil)
|
47
51
|
end
|
48
52
|
|
49
53
|
let :error_response do
|
@@ -84,12 +88,19 @@ module Cql
|
|
84
88
|
result.should have(3).items
|
85
89
|
end
|
86
90
|
|
91
|
+
it 'transforms a RawRowsResultResponse to a LazyQueryResult, and mixes in the specified metadata' do
|
92
|
+
metadata = [['ks', 'tbl', 'col', :varchar]]
|
93
|
+
connection.stub(:send_request).and_return(Future.resolved(raw_rows_response))
|
94
|
+
result = runner.execute(connection, request, nil, metadata).value
|
95
|
+
result.to_a.should == [{'col' => 'a'}, {'col' => 'b'}]
|
96
|
+
end
|
97
|
+
|
87
98
|
it 'transforms a VoidResultResponse to a VoidResult' do
|
88
99
|
result = run(void_response)
|
89
100
|
result.should be_a(VoidResult)
|
90
101
|
end
|
91
102
|
|
92
|
-
it 'transforms
|
103
|
+
it 'transforms an AuthenticateResponse to an authentication required object' do
|
93
104
|
result = run(authenticate_response)
|
94
105
|
result.should be_a(AuthenticationRequired)
|
95
106
|
result.authentication_class.should == 'TheAuthenticator'
|
@@ -107,7 +118,7 @@ module Cql
|
|
107
118
|
|
108
119
|
it 'sets the #cql field of QueryError when the request is a query request' do
|
109
120
|
begin
|
110
|
-
run(error_response, Protocol::QueryRequest.new('SELECT * FROM everything', :all))
|
121
|
+
run(error_response, Protocol::QueryRequest.new('SELECT * FROM everything', nil, nil, :all))
|
111
122
|
rescue QueryError => e
|
112
123
|
e.cql.should == 'SELECT * FROM everything'
|
113
124
|
else
|
@@ -147,7 +158,7 @@ module Cql
|
|
147
158
|
end
|
148
159
|
|
149
160
|
it 'returns a QueryResult that knows its trace ID' do
|
150
|
-
connection.stub(:send_request).with(request, anything).and_return(Future.resolved(Protocol::RowsResultResponse.new(rows, metadata, trace_id)))
|
161
|
+
connection.stub(:send_request).with(request, anything).and_return(Future.resolved(Protocol::RowsResultResponse.new(rows, metadata, nil, trace_id)))
|
151
162
|
response = runner.execute(connection, request).value
|
152
163
|
response.trace_id.should == trace_id
|
153
164
|
end
|
@@ -158,6 +169,21 @@ module Cql
|
|
158
169
|
response.trace_id.should == trace_id
|
159
170
|
end
|
160
171
|
end
|
172
|
+
|
173
|
+
context 'when the response has a paging state' do
|
174
|
+
it 'returns a QueryResult that knows its paging state' do
|
175
|
+
connection.stub(:send_request).with(request, anything).and_return(Future.resolved(Protocol::RowsResultResponse.new(rows, metadata, 'foobaz', nil)))
|
176
|
+
response = runner.execute(connection, request).value
|
177
|
+
response.paging_state.should == 'foobaz'
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'returns a LazyQueryResult that knows its paging state' do
|
181
|
+
metadata = [['ks', 'tbl', 'col', :varchar]]
|
182
|
+
connection.stub(:send_request).with(request, anything).and_return(Future.resolved(Protocol::RawRowsResultResponse.new(2, ByteBuffer.new("\x00\x00\x00\x02\x00\x00\x00\x01a\x00\x00\x00\x01b"), 'bazbuzz', nil)))
|
183
|
+
response = runner.execute(connection, request, nil, metadata).value
|
184
|
+
response.paging_state.should == 'bazbuzz'
|
185
|
+
end
|
186
|
+
end
|
161
187
|
end
|
162
188
|
end
|
163
189
|
end
|
@@ -75,13 +75,26 @@ module Cql
|
|
75
75
|
future.stub(:value).and_return(result)
|
76
76
|
client.execute('SELECT * FROM something', :one).should equal(result)
|
77
77
|
end
|
78
|
+
|
79
|
+
it 'wraps AsynchronousPagedQueryResult in a synchronous wrapper' do
|
80
|
+
cql = 'SELECT * FROM something'
|
81
|
+
request = double(:request, cql: cql, values: [])
|
82
|
+
async_result = double(:result, paging_state: 'somepagingstate')
|
83
|
+
options = {:page_size => 10}
|
84
|
+
async_client.stub(:execute).and_return(Future.resolved(AsynchronousQueryPagedQueryResult.new(async_client, request, async_result, options)))
|
85
|
+
result1 = client.execute(cql, options)
|
86
|
+
result2 = result1.next_page
|
87
|
+
async_client.should have_received(:execute).with('SELECT * FROM something', page_size: 10, paging_state: 'somepagingstate')
|
88
|
+
result2.should be_a(SynchronousPagedQueryResult)
|
89
|
+
end
|
78
90
|
end
|
79
91
|
|
80
92
|
describe '#prepare' do
|
81
93
|
it 'calls #prepare on the async client, waits for the result and returns a SynchronousFuture' do
|
82
94
|
result = double(:result)
|
83
95
|
metadata = double(:metadata)
|
84
|
-
|
96
|
+
result_metadata = double(:result_metadata)
|
97
|
+
async_statement = double(:async_statement, metadata: metadata, result_metadata: result_metadata)
|
85
98
|
another_future = double(:another_future)
|
86
99
|
async_client.stub(:prepare).with('SELECT * FROM something').and_return(future)
|
87
100
|
future.stub(:value).and_return(async_statement)
|
@@ -93,6 +106,36 @@ module Cql
|
|
93
106
|
end
|
94
107
|
end
|
95
108
|
|
109
|
+
describe '#batch' do
|
110
|
+
let :batch do
|
111
|
+
double(:batch)
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'when called without a block' do
|
115
|
+
it 'delegates to the asynchronous client and wraps the returned object in a synchronous wrapper' do
|
116
|
+
async_client.stub(:batch).with(:unlogged, trace: true).and_return(batch)
|
117
|
+
batch.stub(:execute).and_return(Cql::Future.resolved(VoidResult.new))
|
118
|
+
b = client.batch(:unlogged, trace: true)
|
119
|
+
b.execute.should be_a(VoidResult)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'when called with a block' do
|
124
|
+
it 'delegates to the asynchronous client' do
|
125
|
+
async_client.stub(:batch).with(:counter, trace: true).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
|
126
|
+
yielded_batch = nil
|
127
|
+
client.batch(:counter, trace: true) { |b| yielded_batch = b }
|
128
|
+
yielded_batch.should equal(batch)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'waits for the operation to complete' do
|
132
|
+
async_client.stub(:batch).with(:counter, {}).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
|
133
|
+
result = client.batch(:counter) { |b| }
|
134
|
+
result.should be_a(VoidResult)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
96
139
|
describe '#async' do
|
97
140
|
it 'returns an asynchronous client' do
|
98
141
|
client.async.should equal(async_client)
|
@@ -11,13 +11,17 @@ module Cql
|
|
11
11
|
end
|
12
12
|
|
13
13
|
let :async_statement do
|
14
|
-
double(:async_statement, metadata: metadata)
|
14
|
+
double(:async_statement, metadata: metadata, result_metadata: result_metadata)
|
15
15
|
end
|
16
16
|
|
17
17
|
let :metadata do
|
18
18
|
double(:metadata)
|
19
19
|
end
|
20
20
|
|
21
|
+
let :result_metadata do
|
22
|
+
double(:result_metadata)
|
23
|
+
end
|
24
|
+
|
21
25
|
let :promise do
|
22
26
|
Promise.new
|
23
27
|
end
|
@@ -32,6 +36,12 @@ module Cql
|
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
39
|
+
describe '#result_metadata' do
|
40
|
+
it 'returns the async statement\'s result metadata' do
|
41
|
+
statement.result_metadata.should equal(async_statement.result_metadata)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
35
45
|
describe '#execute' do
|
36
46
|
it 'it calls #execute on the async statement and waits for the result' do
|
37
47
|
result = double(:result)
|
@@ -39,6 +49,58 @@ module Cql
|
|
39
49
|
promise.fulfill(result)
|
40
50
|
statement.execute('one', 'two', :three).should equal(result)
|
41
51
|
end
|
52
|
+
|
53
|
+
it 'wraps AsynchronousPagedQueryResult in a synchronous wrapper' do
|
54
|
+
request = double(:request, values: ['one', 'two'])
|
55
|
+
async_result = double(:result, paging_state: 'somepagingstate')
|
56
|
+
options = {:page_size => 10}
|
57
|
+
async_statement.stub(:execute).and_return(Future.resolved(AsynchronousPreparedPagedQueryResult.new(async_statement, request, async_result, options)))
|
58
|
+
result1 = statement.execute('one', 'two', options)
|
59
|
+
result2 = result1.next_page
|
60
|
+
async_statement.should have_received(:execute).with('one', 'two', page_size: 10, paging_state: 'somepagingstate')
|
61
|
+
result2.should be_a(SynchronousPagedQueryResult)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#batch' do
|
66
|
+
let :batch do
|
67
|
+
double(:batch)
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when called without a block' do
|
71
|
+
it 'delegates to the asynchronous statement and wraps the returned object in a synchronous wrapper' do
|
72
|
+
async_statement.stub(:batch).with(:unlogged, trace: true).and_return(batch)
|
73
|
+
batch.stub(:execute).and_return(Cql::Future.resolved(VoidResult.new))
|
74
|
+
b = statement.batch(:unlogged, trace: true)
|
75
|
+
b.execute.should be_a(VoidResult)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when called with a block' do
|
80
|
+
it 'delegates to the asynchronous statement' do
|
81
|
+
async_statement.stub(:batch).with(:counter, trace: true).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
|
82
|
+
yielded_batch = nil
|
83
|
+
statement.batch(:counter, trace: true) { |b| yielded_batch = b }
|
84
|
+
yielded_batch.should equal(batch)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'waits for the operation to complete' do
|
88
|
+
async_statement.stub(:batch).with(:counter, anything).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
|
89
|
+
result = statement.batch(:counter) { |b| }
|
90
|
+
result.should be_a(VoidResult)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#add_to_batch' do
|
96
|
+
it 'delegates to the async statement' do
|
97
|
+
batch = double(:batch)
|
98
|
+
connection = double(:connection)
|
99
|
+
bound_arguments = [1, 2, 3]
|
100
|
+
async_statement.stub(:add_to_batch)
|
101
|
+
statement.add_to_batch(batch, connection, bound_arguments)
|
102
|
+
async_statement.should have_received(:add_to_batch).with(batch, connection, bound_arguments)
|
103
|
+
end
|
42
104
|
end
|
43
105
|
|
44
106
|
describe '#pipeline' do
|
data/spec/cql/future_spec.rb
CHANGED
@@ -393,6 +393,33 @@ module Cql
|
|
393
393
|
mapped_value.should == 3 * 2
|
394
394
|
end
|
395
395
|
|
396
|
+
it 'will be fulfilled with the specified value' do
|
397
|
+
mapped_value = nil
|
398
|
+
p = Promise.new
|
399
|
+
f = p.future.map(7)
|
400
|
+
f.on_value { |v| mapped_value = v }
|
401
|
+
p.fulfill(3)
|
402
|
+
mapped_value.should == 7
|
403
|
+
end
|
404
|
+
|
405
|
+
it 'will be fulfilled with the result of the given block, even if a value is specified' do
|
406
|
+
mapped_value = nil
|
407
|
+
p = Promise.new
|
408
|
+
f = p.future.map(7) { |v| v * 2 }
|
409
|
+
f.on_value { |v| mapped_value = v }
|
410
|
+
p.fulfill(3)
|
411
|
+
mapped_value.should == 3 * 2
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'will be fulfilled with nil when neither value nor block is specified' do
|
415
|
+
mapped_value = 3
|
416
|
+
p = Promise.new
|
417
|
+
f = p.future.map
|
418
|
+
f.on_value { |v| mapped_value = v }
|
419
|
+
p.fulfill(3)
|
420
|
+
mapped_value.should be_nil
|
421
|
+
end
|
422
|
+
|
396
423
|
it 'fails when the original future fails' do
|
397
424
|
failed = false
|
398
425
|
p = Promise.new
|
@@ -432,13 +459,34 @@ module Cql
|
|
432
459
|
|
433
460
|
describe '#recover' do
|
434
461
|
context 'returns a new future that' do
|
435
|
-
it 'becomes fulfilled with a value when the source future fails' do
|
462
|
+
it 'becomes fulfilled with a value created by the block when the source future fails' do
|
436
463
|
p = Promise.new
|
437
464
|
f = p.future.recover { 'foo' }
|
438
465
|
p.fail(error)
|
439
466
|
f.value.should == 'foo'
|
440
467
|
end
|
441
468
|
|
469
|
+
it 'becomes fulfilled with a specfied value when the source future fails' do
|
470
|
+
p = Promise.new
|
471
|
+
f = p.future.recover('bar')
|
472
|
+
p.fail(error)
|
473
|
+
f.value.should == 'bar'
|
474
|
+
end
|
475
|
+
|
476
|
+
it 'becomes fulfilled with a value created by the block even when a value is specified when the source future fails' do
|
477
|
+
p = Promise.new
|
478
|
+
f = p.future.recover('bar') { 'foo' }
|
479
|
+
p.fail(error)
|
480
|
+
f.value.should == 'foo'
|
481
|
+
end
|
482
|
+
|
483
|
+
it 'becomes fulfilled with nil value when no value nor block is specified and the source future fails' do
|
484
|
+
p = Promise.new
|
485
|
+
f = p.future.recover
|
486
|
+
p.fail(error)
|
487
|
+
f.value.should be_nil
|
488
|
+
end
|
489
|
+
|
442
490
|
it 'yields the error to the block' do
|
443
491
|
p = Promise.new
|
444
492
|
f = p.future.recover { |e| e.message }
|
@@ -644,7 +692,7 @@ module Cql
|
|
644
692
|
described_class.resolved('hello world')
|
645
693
|
end
|
646
694
|
|
647
|
-
it '
|
695
|
+
it 'is resolved' do
|
648
696
|
future.should be_resolved
|
649
697
|
end
|
650
698
|
|
@@ -7,7 +7,7 @@ module Cql
|
|
7
7
|
module Protocol
|
8
8
|
describe CqlProtocolHandler do
|
9
9
|
let :protocol_handler do
|
10
|
-
described_class.new(connection, scheduler)
|
10
|
+
described_class.new(connection, scheduler, 1)
|
11
11
|
end
|
12
12
|
|
13
13
|
let :connection do
|
@@ -114,7 +114,7 @@ module Cql
|
|
114
114
|
|
115
115
|
context 'when a compressor is specified' do
|
116
116
|
let :protocol_handler do
|
117
|
-
described_class.new(connection, scheduler, compressor)
|
117
|
+
described_class.new(connection, scheduler, 1, compressor)
|
118
118
|
end
|
119
119
|
|
120
120
|
let :compressor do
|
@@ -147,8 +147,19 @@ module Cql
|
|
147
147
|
f2 = protocol_handler.send_request(request)
|
148
148
|
connection.data_listener.call("\x81\x01\x00\x08\x00\x00\x00\x12FAKECOMPRESSEDBODY")
|
149
149
|
connection.data_listener.call("\x81\x01\x01\x08\x00\x00\x00\x12FAKECOMPRESSEDBODY")
|
150
|
-
f1.value.should == Protocol::PreparedResultResponse.new(id, [["cql_rb_911", "users", "user_name", :varchar]], nil)
|
151
|
-
f2.value.should == Protocol::PreparedResultResponse.new(id, [["cql_rb_911", "users", "user_name", :varchar]], nil)
|
150
|
+
f1.value.should == Protocol::PreparedResultResponse.new(id, [["cql_rb_911", "users", "user_name", :varchar]], nil, nil)
|
151
|
+
f2.value.should == Protocol::PreparedResultResponse.new(id, [["cql_rb_911", "users", "user_name", :varchar]], nil, nil)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when a protocol version is specified' do
|
156
|
+
let :protocol_handler do
|
157
|
+
described_class.new(connection, scheduler, 7)
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'sets the protocol version in the header' do
|
161
|
+
protocol_handler.send_request(request)
|
162
|
+
buffer.to_s[0].should == "\x07"
|
152
163
|
end
|
153
164
|
end
|
154
165
|
|
@@ -266,7 +277,7 @@ module Cql
|
|
266
277
|
end
|
267
278
|
|
268
279
|
it 'registers the keyspace it has changed to' do
|
269
|
-
f = protocol_handler.send_request(Protocol::QueryRequest.new('USE hello', :one))
|
280
|
+
f = protocol_handler.send_request(Protocol::QueryRequest.new('USE hello', nil, nil, :one))
|
270
281
|
connection.data_listener.call([0x81, 0, 0, 8, 4 + 2 + 5, 3, 5].pack('C4N2n') + 'hello')
|
271
282
|
f.value
|
272
283
|
protocol_handler.keyspace.should == 'hello'
|
@@ -100,8 +100,8 @@ module Cql
|
|
100
100
|
end
|
101
101
|
|
102
102
|
it 'decodes a negative long' do
|
103
|
-
buffer = ByteBuffer.new("\xff\
|
104
|
-
Decoding.read_long!(buffer).should == -
|
103
|
+
buffer = ByteBuffer.new("\xff\xee\xdd\xcc\xbb\xaa\x99\x88")
|
104
|
+
Decoding.read_long!(buffer).should == 0xffeeddccbbaa9988 - 0x10000000000000000
|
105
105
|
end
|
106
106
|
|
107
107
|
it 'consumes the bytes' do
|
@@ -162,8 +162,8 @@ module Cql
|
|
162
162
|
end
|
163
163
|
|
164
164
|
it 'decodes a negative int' do
|
165
|
-
buffer = ByteBuffer.new("\xff\
|
166
|
-
Decoding.read_int!(buffer).should == -
|
165
|
+
buffer = ByteBuffer.new("\xff\xee\xdd\xcc")
|
166
|
+
Decoding.read_int!(buffer).should == 0xffeeddcc - 0x100000000
|
167
167
|
end
|
168
168
|
|
169
169
|
it 'consumes the bytes' do
|
@@ -470,14 +470,24 @@ module Cql
|
|
470
470
|
Decoding.read_consistency!(buffer).should == :each_quorum
|
471
471
|
end
|
472
472
|
|
473
|
+
it 'decodes SERIAL' do
|
474
|
+
buffer = ByteBuffer.new("\x00\x08")
|
475
|
+
Decoding.read_consistency!(buffer).should == :serial
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'decodes LOCAL_SERIAL' do
|
479
|
+
buffer = ByteBuffer.new("\x00\x09")
|
480
|
+
Decoding.read_consistency!(buffer).should == :local_serial
|
481
|
+
end
|
482
|
+
|
473
483
|
it 'decodes LOCAL_ONE' do
|
474
|
-
buffer = ByteBuffer.new("\x00\
|
484
|
+
buffer = ByteBuffer.new("\x00\x0a")
|
475
485
|
Decoding.read_consistency!(buffer).should == :local_one
|
476
486
|
end
|
477
487
|
|
478
488
|
it 'raises an exception for an unknown consistency' do
|
479
489
|
expect { Decoding.read_consistency!(ByteBuffer.new("\xff\xff")) }.to raise_error(DecodingError)
|
480
|
-
expect { Decoding.read_consistency!(ByteBuffer.new("\x00\
|
490
|
+
expect { Decoding.read_consistency!(ByteBuffer.new("\x00\x0f")) }.to raise_error(DecodingError)
|
481
491
|
end
|
482
492
|
end
|
483
493
|
|
@@ -238,7 +238,9 @@ module Cql
|
|
238
238
|
:all => "\x00\x05",
|
239
239
|
:local_quorum => "\x00\x06",
|
240
240
|
:each_quorum => "\x00\x07",
|
241
|
-
:
|
241
|
+
:serial => "\x00\x08",
|
242
|
+
:local_serial => "\x00\x09",
|
243
|
+
:local_one => "\x00\x0a",
|
242
244
|
}.each do |consistency, expected_encoding|
|
243
245
|
it "encodes #{consistency}" do
|
244
246
|
Encoding.write_consistency(buffer, consistency)
|
@@ -6,86 +6,135 @@ require 'spec_helper'
|
|
6
6
|
module Cql
|
7
7
|
module Protocol
|
8
8
|
describe FrameEncoder do
|
9
|
-
let :encoder do
|
10
|
-
described_class.new
|
11
|
-
end
|
12
|
-
|
13
9
|
describe '#encode_frame' do
|
14
|
-
|
15
|
-
request
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
let :request do
|
11
|
+
double(:request)
|
12
|
+
end
|
13
|
+
|
14
|
+
let :compressor do
|
15
|
+
double(:compressor)
|
19
16
|
end
|
20
17
|
|
21
|
-
|
18
|
+
before do
|
19
|
+
request.stub(:opcode).and_return(0x77)
|
20
|
+
request.stub(:trace?).and_return(false)
|
21
|
+
request.stub(:write) { |pv, bb| bb }
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'asks the request to write itself to a buffer' do
|
25
|
+
encoder = described_class.new(1)
|
26
|
+
encoder.encode_frame(request)
|
27
|
+
request.should have_received(:write).with(anything, an_instance_of(ByteBuffer))
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'appends what the request wrote to the specified buffer, after a header' do
|
22
31
|
buffer = ByteBuffer.new('hello')
|
23
|
-
request
|
24
|
-
|
25
|
-
|
26
|
-
buffer.to_s.should ==
|
32
|
+
request.stub(:write) { |pv, bb| bb << "\x01\x02\x03" }
|
33
|
+
encoder = described_class.new(1)
|
34
|
+
encoder.encode_frame(request, 0, buffer)
|
35
|
+
buffer.to_s[ 0, 5].should == 'hello'
|
36
|
+
buffer.to_s[13, 3].should == "\x01\x02\x03"
|
27
37
|
end
|
28
38
|
|
29
39
|
it 'returns the specified buffer' do
|
30
40
|
buffer = ByteBuffer.new('hello')
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
encoded_frame.should equal(buffer)
|
41
|
+
encoder = described_class.new(1)
|
42
|
+
returned_buffer = encoder.encode_frame(request, 0, buffer)
|
43
|
+
returned_buffer.should equal(buffer)
|
35
44
|
end
|
36
45
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
46
|
+
it 'passes the protocol version to the request' do
|
47
|
+
encoder = described_class.new(7)
|
48
|
+
encoder.encode_frame(request)
|
49
|
+
request.should have_received(:write).with(7, anything)
|
50
|
+
end
|
41
51
|
|
42
|
-
|
43
|
-
|
44
|
-
|
52
|
+
it 'encodes a header with the specified protocol version' do
|
53
|
+
encoder = described_class.new(7)
|
54
|
+
buffer = encoder.encode_frame(request)
|
55
|
+
buffer.to_s[0].should == "\x07"
|
56
|
+
end
|
45
57
|
|
46
|
-
|
47
|
-
|
48
|
-
|
58
|
+
it 'encodes a header with the tracing flag set' do
|
59
|
+
request.stub(:trace?).and_return(true)
|
60
|
+
encoder = described_class.new(1)
|
61
|
+
buffer = encoder.encode_frame(request)
|
62
|
+
buffer.to_s[1].should == "\x02"
|
63
|
+
end
|
49
64
|
|
50
|
-
|
51
|
-
|
52
|
-
|
65
|
+
it 'encodes a header with the specified stream ID' do
|
66
|
+
encoder = described_class.new(1)
|
67
|
+
buffer = encoder.encode_frame(request, 9)
|
68
|
+
buffer.to_s[2].should == "\x09"
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'complains when the stream ID is less than 0 or more than 127' do
|
72
|
+
encoder = described_class.new(1)
|
73
|
+
expect { encoder.encode_frame(request, -1) }.to raise_error(InvalidStreamIdError)
|
74
|
+
expect { encoder.encode_frame(request, 128) }.to raise_error(InvalidStreamIdError)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'encodes a header with the right opcode' do
|
78
|
+
encoder = described_class.new(1)
|
79
|
+
buffer = encoder.encode_frame(request, 9)
|
80
|
+
buffer.to_s[3].should == "\x77"
|
81
|
+
end
|
53
82
|
|
83
|
+
it 'encodes the body size' do
|
84
|
+
request.stub(:write).and_return(ByteBuffer.new('helloworld'))
|
85
|
+
encoder = described_class.new(1)
|
86
|
+
buffer = encoder.encode_frame(request, 9)
|
87
|
+
buffer.to_s[4, 4].should == "\x00\x00\x00\x0a"
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when a compressor has been specified' do
|
54
91
|
before do
|
55
|
-
|
56
|
-
|
92
|
+
request.stub(:compressable?).and_return(true)
|
93
|
+
request.stub(:write).and_return(ByteBuffer.new('helloworld'))
|
94
|
+
compressor.stub(:compress?).and_return(true)
|
95
|
+
compressor.stub(:compress).with('helloworld').and_return('COMPRESSEDFRAME')
|
57
96
|
end
|
58
97
|
|
59
|
-
it '
|
60
|
-
|
98
|
+
it 'compresses the request' do
|
99
|
+
encoder = described_class.new(1, compressor)
|
100
|
+
buffer = encoder.encode_frame(request)
|
101
|
+
buffer.to_s[8, 100].should == 'COMPRESSEDFRAME'
|
61
102
|
end
|
62
103
|
|
63
|
-
it 'sets the
|
64
|
-
|
104
|
+
it 'sets the compression flag' do
|
105
|
+
encoder = described_class.new(1, compressor)
|
106
|
+
buffer = encoder.encode_frame(request)
|
107
|
+
buffer.to_s[1, 1].should == "\x01"
|
65
108
|
end
|
66
109
|
|
67
|
-
it '
|
68
|
-
|
69
|
-
|
110
|
+
it 'sets both the compression flag and the tracing flag' do
|
111
|
+
request.stub(:trace?).and_return(true)
|
112
|
+
encoder = described_class.new(1, compressor)
|
113
|
+
buffer = encoder.encode_frame(request)
|
114
|
+
buffer.to_s[1, 1].should == "\x03"
|
70
115
|
end
|
71
116
|
|
72
|
-
it '
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
compressed_frame.to_s[1].should == "\x03"
|
117
|
+
it 'encodes the compressed body size' do
|
118
|
+
encoder = described_class.new(1, compressor)
|
119
|
+
buffer = encoder.encode_frame(request)
|
120
|
+
buffer.to_s[4, 4].should == "\x00\x00\x00\x0f"
|
77
121
|
end
|
78
122
|
|
79
|
-
it 'does not compress
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
123
|
+
it 'does not compress uncompressable frames' do
|
124
|
+
request.stub(:compressable?).and_return(false)
|
125
|
+
encoder = described_class.new(1, compressor)
|
126
|
+
buffer = encoder.encode_frame(request)
|
127
|
+
compressor.should_not have_received(:compress?)
|
128
|
+
compressor.should_not have_received(:compress)
|
84
129
|
end
|
85
130
|
end
|
86
131
|
end
|
87
132
|
|
88
133
|
describe '#change_stream_id' do
|
134
|
+
let :encoder do
|
135
|
+
described_class.new
|
136
|
+
end
|
137
|
+
|
89
138
|
it 'changes the stream ID byte' do
|
90
139
|
buffer = ByteBuffer.new("\x01\x00\x03\x02\x00\x00\x00\x00")
|
91
140
|
encoder.change_stream_id(99, buffer)
|