cql-rb 1.2.2 → 2.0.0.pre0
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/.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)
|