cql-rb 2.0.0.pre0 → 2.0.0.pre1
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/README.md +14 -2
- data/lib/cql.rb +8 -3
- data/lib/cql/client.rb +21 -356
- data/lib/cql/client/authenticators.rb +70 -0
- data/lib/cql/client/batch.rb +54 -0
- data/lib/cql/client/{asynchronous_client.rb → client.rb} +241 -6
- data/lib/cql/client/connector.rb +3 -2
- data/lib/cql/client/{asynchronous_prepared_statement.rb → prepared_statement.rb} +103 -0
- data/lib/cql/protocol.rb +1 -2
- data/lib/cql/protocol/cql_byte_buffer.rb +285 -0
- data/lib/cql/protocol/cql_protocol_handler.rb +3 -3
- data/lib/cql/protocol/frame_decoder.rb +3 -3
- data/lib/cql/protocol/frame_encoder.rb +2 -2
- data/lib/cql/protocol/request.rb +0 -2
- data/lib/cql/protocol/requests/auth_response_request.rb +2 -2
- data/lib/cql/protocol/requests/batch_request.rb +10 -10
- data/lib/cql/protocol/requests/credentials_request.rb +2 -2
- data/lib/cql/protocol/requests/execute_request.rb +13 -13
- data/lib/cql/protocol/requests/options_request.rb +2 -2
- data/lib/cql/protocol/requests/prepare_request.rb +2 -2
- data/lib/cql/protocol/requests/query_request.rb +13 -13
- data/lib/cql/protocol/requests/register_request.rb +2 -2
- data/lib/cql/protocol/requests/startup_request.rb +2 -2
- data/lib/cql/protocol/response.rb +2 -4
- data/lib/cql/protocol/responses/auth_challenge_response.rb +2 -2
- data/lib/cql/protocol/responses/auth_success_response.rb +2 -2
- data/lib/cql/protocol/responses/authenticate_response.rb +2 -2
- data/lib/cql/protocol/responses/detailed_error_response.rb +15 -15
- data/lib/cql/protocol/responses/error_response.rb +4 -4
- data/lib/cql/protocol/responses/event_response.rb +3 -3
- data/lib/cql/protocol/responses/prepared_result_response.rb +4 -4
- data/lib/cql/protocol/responses/raw_rows_result_response.rb +1 -1
- data/lib/cql/protocol/responses/ready_response.rb +1 -1
- data/lib/cql/protocol/responses/result_response.rb +3 -3
- data/lib/cql/protocol/responses/rows_result_response.rb +22 -22
- data/lib/cql/protocol/responses/schema_change_event_response.rb +2 -2
- data/lib/cql/protocol/responses/schema_change_result_response.rb +2 -2
- data/lib/cql/protocol/responses/set_keyspace_result_response.rb +2 -2
- data/lib/cql/protocol/responses/status_change_event_response.rb +2 -2
- data/lib/cql/protocol/responses/supported_response.rb +2 -2
- data/lib/cql/protocol/responses/void_result_response.rb +1 -1
- data/lib/cql/protocol/type_converter.rb +78 -81
- data/lib/cql/time_uuid.rb +6 -0
- data/lib/cql/uuid.rb +2 -1
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/batch_spec.rb +8 -8
- data/spec/cql/client/{asynchronous_client_spec.rb → client_spec.rb} +162 -0
- data/spec/cql/client/connector_spec.rb +13 -3
- data/spec/cql/client/{asynchronous_prepared_statement_spec.rb → prepared_statement_spec.rb} +148 -1
- data/spec/cql/client/request_runner_spec.rb +2 -2
- data/spec/cql/protocol/cql_byte_buffer_spec.rb +895 -0
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +1 -1
- data/spec/cql/protocol/frame_decoder_spec.rb +14 -14
- data/spec/cql/protocol/frame_encoder_spec.rb +7 -7
- data/spec/cql/protocol/requests/auth_response_request_spec.rb +4 -4
- data/spec/cql/protocol/requests/batch_request_spec.rb +21 -21
- data/spec/cql/protocol/requests/credentials_request_spec.rb +2 -2
- data/spec/cql/protocol/requests/execute_request_spec.rb +13 -13
- data/spec/cql/protocol/requests/options_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/prepare_request_spec.rb +2 -2
- data/spec/cql/protocol/requests/query_request_spec.rb +13 -13
- data/spec/cql/protocol/requests/register_request_spec.rb +2 -2
- data/spec/cql/protocol/requests/startup_request_spec.rb +4 -4
- data/spec/cql/protocol/responses/auth_challenge_response_spec.rb +5 -5
- data/spec/cql/protocol/responses/auth_success_response_spec.rb +5 -5
- data/spec/cql/protocol/responses/authenticate_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/detailed_error_response_spec.rb +15 -15
- data/spec/cql/protocol/responses/error_response_spec.rb +5 -5
- data/spec/cql/protocol/responses/event_response_spec.rb +8 -8
- data/spec/cql/protocol/responses/prepared_result_response_spec.rb +7 -7
- data/spec/cql/protocol/responses/raw_rows_result_response_spec.rb +1 -1
- data/spec/cql/protocol/responses/ready_response_spec.rb +2 -2
- data/spec/cql/protocol/responses/result_response_spec.rb +16 -16
- data/spec/cql/protocol/responses/rows_result_response_spec.rb +21 -21
- data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +2 -2
- data/spec/cql/protocol/responses/status_change_event_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/supported_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/void_result_response_spec.rb +2 -2
- data/spec/cql/protocol/type_converter_spec.rb +25 -13
- data/spec/cql/time_uuid_spec.rb +17 -4
- data/spec/cql/uuid_spec.rb +5 -1
- data/spec/integration/protocol_spec.rb +48 -42
- data/spec/spec_helper.rb +0 -1
- metadata +27 -39
- data/lib/cql/byte_buffer.rb +0 -177
- data/lib/cql/client/synchronous_client.rb +0 -79
- data/lib/cql/client/synchronous_prepared_statement.rb +0 -63
- data/lib/cql/future.rb +0 -515
- data/lib/cql/io.rb +0 -15
- data/lib/cql/io/connection.rb +0 -220
- data/lib/cql/io/io_reactor.rb +0 -349
- data/lib/cql/protocol/decoding.rb +0 -187
- data/lib/cql/protocol/encoding.rb +0 -114
- data/spec/cql/byte_buffer_spec.rb +0 -337
- data/spec/cql/client/synchronous_client_spec.rb +0 -170
- data/spec/cql/client/synchronous_prepared_statement_spec.rb +0 -155
- data/spec/cql/future_spec.rb +0 -737
- data/spec/cql/io/connection_spec.rb +0 -484
- data/spec/cql/io/io_reactor_spec.rb +0 -402
- data/spec/cql/protocol/decoding_spec.rb +0 -547
- data/spec/cql/protocol/encoding_spec.rb +0 -386
- data/spec/integration/io_spec.rb +0 -283
- data/spec/support/fake_server.rb +0 -106
@@ -204,7 +204,7 @@ module Cql
|
|
204
204
|
|
205
205
|
describe ConnectStep do
|
206
206
|
let :step do
|
207
|
-
described_class.new(io_reactor, 1111, 9, logger)
|
207
|
+
described_class.new(io_reactor, protocol_handler_factory, 1111, 9, logger)
|
208
208
|
end
|
209
209
|
|
210
210
|
let :pending_connection do
|
@@ -219,6 +219,14 @@ module Cql
|
|
219
219
|
double(:io_reactor)
|
220
220
|
end
|
221
221
|
|
222
|
+
let :protocol_handler do
|
223
|
+
double(:protocol_handler)
|
224
|
+
end
|
225
|
+
|
226
|
+
let :protocol_handler_factory do
|
227
|
+
proc { protocol_handler }
|
228
|
+
end
|
229
|
+
|
222
230
|
let :logger do
|
223
231
|
NullLogger.new
|
224
232
|
end
|
@@ -230,8 +238,10 @@ module Cql
|
|
230
238
|
describe '#run' do
|
231
239
|
before do
|
232
240
|
pending_connection.stub(:host).and_return('example.com')
|
233
|
-
pending_connection.stub(:with_connection).and_return(new_pending_connection)
|
234
|
-
io_reactor.stub(:connect)
|
241
|
+
pending_connection.stub(:with_connection).with(protocol_handler).and_return(new_pending_connection)
|
242
|
+
io_reactor.stub(:connect) do |_, _, _, &block|
|
243
|
+
Future.resolved(block.call(connection))
|
244
|
+
end
|
235
245
|
end
|
236
246
|
|
237
247
|
it 'connects using the connection details given' do
|
@@ -36,7 +36,7 @@ module Cql
|
|
36
36
|
end
|
37
37
|
|
38
38
|
let :raw_rows do
|
39
|
-
buffer =
|
39
|
+
buffer = Protocol::CqlByteBuffer.new("\x00\x00\x00\x03")
|
40
40
|
buffer << "\x00\x00\x00\x04\x00\x00\x00\x0b"
|
41
41
|
buffer << "\x00\x00\x00\x05hello"
|
42
42
|
buffer << "\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"
|
@@ -389,5 +389,152 @@ module Cql
|
|
389
389
|
end
|
390
390
|
end
|
391
391
|
end
|
392
|
+
|
393
|
+
describe SynchronousPreparedStatement do
|
394
|
+
let :statement do
|
395
|
+
described_class.new(async_statement)
|
396
|
+
end
|
397
|
+
|
398
|
+
let :async_statement do
|
399
|
+
double(:async_statement, metadata: metadata, result_metadata: result_metadata)
|
400
|
+
end
|
401
|
+
|
402
|
+
let :metadata do
|
403
|
+
double(:metadata)
|
404
|
+
end
|
405
|
+
|
406
|
+
let :result_metadata do
|
407
|
+
double(:result_metadata)
|
408
|
+
end
|
409
|
+
|
410
|
+
let :promise do
|
411
|
+
Promise.new
|
412
|
+
end
|
413
|
+
|
414
|
+
let :future do
|
415
|
+
promise.future
|
416
|
+
end
|
417
|
+
|
418
|
+
describe '#metadata' do
|
419
|
+
it 'returns the async statement\'s metadata' do
|
420
|
+
statement.metadata.should equal(async_statement.metadata)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe '#result_metadata' do
|
425
|
+
it 'returns the async statement\'s result metadata' do
|
426
|
+
statement.result_metadata.should equal(async_statement.result_metadata)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
describe '#execute' do
|
431
|
+
it 'it calls #execute on the async statement and waits for the result' do
|
432
|
+
result = double(:result)
|
433
|
+
async_statement.should_receive(:execute).with('one', 'two', :three).and_return(future)
|
434
|
+
promise.fulfill(result)
|
435
|
+
statement.execute('one', 'two', :three).should equal(result)
|
436
|
+
end
|
437
|
+
|
438
|
+
it 'wraps AsynchronousPagedQueryResult in a synchronous wrapper' do
|
439
|
+
request = double(:request, values: ['one', 'two'])
|
440
|
+
async_result = double(:result, paging_state: 'somepagingstate')
|
441
|
+
options = {:page_size => 10}
|
442
|
+
async_statement.stub(:execute).and_return(Future.resolved(AsynchronousPreparedPagedQueryResult.new(async_statement, request, async_result, options)))
|
443
|
+
result1 = statement.execute('one', 'two', options)
|
444
|
+
result2 = result1.next_page
|
445
|
+
async_statement.should have_received(:execute).with('one', 'two', page_size: 10, paging_state: 'somepagingstate')
|
446
|
+
result2.should be_a(SynchronousPagedQueryResult)
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
describe '#batch' do
|
451
|
+
let :batch do
|
452
|
+
double(:batch)
|
453
|
+
end
|
454
|
+
|
455
|
+
context 'when called without a block' do
|
456
|
+
it 'delegates to the asynchronous statement and wraps the returned object in a synchronous wrapper' do
|
457
|
+
async_statement.stub(:batch).with(:unlogged, trace: true).and_return(batch)
|
458
|
+
batch.stub(:execute).and_return(Cql::Future.resolved(VoidResult.new))
|
459
|
+
b = statement.batch(:unlogged, trace: true)
|
460
|
+
b.execute.should be_a(VoidResult)
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
context 'when called with a block' do
|
465
|
+
it 'delegates to the asynchronous statement' do
|
466
|
+
async_statement.stub(:batch).with(:counter, trace: true).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
|
467
|
+
yielded_batch = nil
|
468
|
+
statement.batch(:counter, trace: true) { |b| yielded_batch = b }
|
469
|
+
yielded_batch.should equal(batch)
|
470
|
+
end
|
471
|
+
|
472
|
+
it 'waits for the operation to complete' do
|
473
|
+
async_statement.stub(:batch).with(:counter, anything).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
|
474
|
+
result = statement.batch(:counter) { |b| }
|
475
|
+
result.should be_a(VoidResult)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
describe '#add_to_batch' do
|
481
|
+
it 'delegates to the async statement' do
|
482
|
+
batch = double(:batch)
|
483
|
+
connection = double(:connection)
|
484
|
+
bound_arguments = [1, 2, 3]
|
485
|
+
async_statement.stub(:add_to_batch)
|
486
|
+
statement.add_to_batch(batch, connection, bound_arguments)
|
487
|
+
async_statement.should have_received(:add_to_batch).with(batch, connection, bound_arguments)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
describe '#pipeline' do
|
492
|
+
it 'executes the statement multiple times and waits for all the results' do
|
493
|
+
result1 = double(:result1)
|
494
|
+
result2 = double(:result2)
|
495
|
+
async_statement.stub(:execute).with('one', 'two', :three).and_return(Future.resolved(result1))
|
496
|
+
async_statement.stub(:execute).with('four', 'file', :all).and_return(Future.resolved(result2))
|
497
|
+
results = statement.pipeline do |p|
|
498
|
+
p.execute('one', 'two', :three)
|
499
|
+
p.execute('four', 'file', :all)
|
500
|
+
end
|
501
|
+
results.should eql([result1, result2])
|
502
|
+
end
|
503
|
+
|
504
|
+
it 'does nothing when statements are executed' do
|
505
|
+
statement.pipeline { |p| }.should == []
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
describe '#async' do
|
510
|
+
it 'returns an asynchronous statement' do
|
511
|
+
statement.async.should equal(async_statement)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
context 'when exceptions are raised' do
|
516
|
+
it 'replaces the backtrace of the asynchronous call to make it less confusing' do
|
517
|
+
error = CqlError.new('Bork')
|
518
|
+
error.set_backtrace(['Hello', 'World'])
|
519
|
+
future.stub(:value).and_raise(error)
|
520
|
+
async_statement.stub(:execute).and_return(future)
|
521
|
+
begin
|
522
|
+
statement.execute('SELECT * FROM something')
|
523
|
+
rescue CqlError => e
|
524
|
+
e.backtrace.first.should match(%r{/prepared_statement.rb:\d+:in `execute'})
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
it 'does not replace the backtrace of non-CqlError errors' do
|
529
|
+
future.stub(:value).and_raise('Bork')
|
530
|
+
async_statement.stub(:execute).and_return(future)
|
531
|
+
begin
|
532
|
+
statement.execute('SELECT * FROM something')
|
533
|
+
rescue => e
|
534
|
+
e.backtrace.first.should_not match(%r{/prepared_statement.rb:\d+:in `execute'})
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
392
539
|
end
|
393
540
|
end
|
@@ -39,7 +39,7 @@ module Cql
|
|
39
39
|
end
|
40
40
|
|
41
41
|
let :raw_rows_response do
|
42
|
-
Protocol::RawRowsResultResponse.new(2,
|
42
|
+
Protocol::RawRowsResultResponse.new(2, Protocol::CqlByteBuffer.new("\x00\x00\x00\x02\x00\x00\x00\x01a\x00\x00\x00\x01b"), nil, nil)
|
43
43
|
end
|
44
44
|
|
45
45
|
let :void_response do
|
@@ -179,7 +179,7 @@ module Cql
|
|
179
179
|
|
180
180
|
it 'returns a LazyQueryResult that knows its paging state' do
|
181
181
|
metadata = [['ks', 'tbl', 'col', :varchar]]
|
182
|
-
connection.stub(:send_request).with(request, anything).and_return(Future.resolved(Protocol::RawRowsResultResponse.new(2,
|
182
|
+
connection.stub(:send_request).with(request, anything).and_return(Future.resolved(Protocol::RawRowsResultResponse.new(2, Protocol::CqlByteBuffer.new("\x00\x00\x00\x02\x00\x00\x00\x01a\x00\x00\x00\x01b"), 'bazbuzz', nil)))
|
183
183
|
response = runner.execute(connection, request, nil, metadata).value
|
184
184
|
response.paging_state.should == 'bazbuzz'
|
185
185
|
end
|
@@ -0,0 +1,895 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
|
6
|
+
module Cql
|
7
|
+
module Protocol
|
8
|
+
describe CqlByteBuffer do
|
9
|
+
let :buffer do
|
10
|
+
described_class.new
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#read_unsigned_byte' do
|
14
|
+
let :buffer do
|
15
|
+
described_class.new("\xab")
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'decodes a raw byte' do
|
19
|
+
buffer.read_unsigned_byte.should == 0xab
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'consumes the byte' do
|
23
|
+
buffer.read_unsigned_byte
|
24
|
+
buffer.should be_empty
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'raises an error when there is no byte available' do
|
28
|
+
expect { described_class.new.read_unsigned_byte }.to raise_error(DecodingError)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#read_varint' do
|
33
|
+
it 'decodes a variable length integer' do
|
34
|
+
buffer = described_class.new("\x03\x9EV \x15\f\x03\x9DK\x18\xCDI\\$?\a[")
|
35
|
+
buffer.read_varint(17).should == 1231312312331283012830129382342342412123
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'decodes a negative variable length integer' do
|
39
|
+
buffer = described_class.new("\xC9v\x8D:\x86")
|
40
|
+
buffer.read_varint(5).should == -234234234234
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'decodes an unsigned variable length integer' do
|
44
|
+
buffer = described_class.new("\xC9v\x8D:\x86")
|
45
|
+
buffer.read_varint(5, false).should == 865277393542
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'consumes the bytes' do
|
49
|
+
buffer = described_class.new("\x03\x9EV \x15\f\x03\x9DK\x18\xCDI\\$?\a[\x01\x02\x03")
|
50
|
+
buffer.read_varint(17)
|
51
|
+
buffer.should eql_bytes("\x01\x02\x03")
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'raises an error when there is not enough bytes available' do
|
55
|
+
buffer = described_class.new("\xC9v\x8D:")
|
56
|
+
expect { buffer.read_varint(7) }.to raise_error(DecodingError)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#read_decimal' do
|
61
|
+
let :buffer do
|
62
|
+
described_class.new("\x00\x00\x00\x12\r'\xFDI\xAD\x80f\x11g\xDCfV\xAA")
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'decodes a decimal to a BigDecimal' do
|
66
|
+
buffer.read_decimal.should == BigDecimal.new('1042342234234.123423435647768234')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'decodes a negative decimal' do
|
70
|
+
buffer = described_class.new("\x00\x00\x00\x12\xF2\xD8\x02\xB6R\x7F\x99\xEE\x98#\x99\xA9V")
|
71
|
+
buffer.read_decimal.should == BigDecimal.new('-1042342234234.123423435647768234')
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'decodes a positive decimal with only fractions' do
|
75
|
+
buffer = described_class.new("\x00\x00\x00\x13*\xF8\xC4\xDF\xEB]o")
|
76
|
+
buffer.read_decimal.should == BigDecimal.new('0.0012095473475870063')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'decodes a negative decimal with only fractions' do
|
80
|
+
buffer = described_class.new("\x00\x00\x00\x13\xD5\a;\x20\x14\xA2\x91")
|
81
|
+
buffer.read_decimal.should == BigDecimal.new('-0.0012095473475870063')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'consumes the bytes' do
|
85
|
+
buffer << 'HELLO'
|
86
|
+
buffer.read_decimal(buffer.length - 5)
|
87
|
+
buffer.should eql_bytes('HELLO')
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'defaults to using the buffer length' do
|
91
|
+
b1 = buffer
|
92
|
+
b2 = buffer.dup
|
93
|
+
b1.read_decimal.should == b2.read_decimal(b2.length)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'raises an error when there is not enough bytes available' do
|
97
|
+
b = described_class.new(buffer.read(3))
|
98
|
+
expect { b.read_decimal(7) }.to raise_error(DecodingError)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#read_long' do
|
103
|
+
it 'decodes a positive long' do
|
104
|
+
buffer = described_class.new("\x00\x00\xca\xfe\xba\xbe\x00\x00")
|
105
|
+
buffer.read_long.should == 0x0000cafebabe0000
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'decodes a negative long' do
|
109
|
+
buffer = described_class.new("\xff\xee\xdd\xcc\xbb\xaa\x99\x88")
|
110
|
+
buffer.read_long.should == 0xffeeddccbbaa9988 - 0x10000000000000000
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'consumes the bytes' do
|
114
|
+
buffer = described_class.new("\xca\xfe\xba\xbe\xca\xfe\xba\xbe\xca\xfe\xba\xbe")
|
115
|
+
buffer.read_long
|
116
|
+
buffer.should eql_bytes("\xca\xfe\xba\xbe")
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'raises an error when there is not enough bytes available' do
|
120
|
+
b = described_class.new("\xca\xfe\xba\xbe\x00")
|
121
|
+
expect { b.read_long }.to raise_error(DecodingError)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#read_double' do
|
126
|
+
it 'decodes a double' do
|
127
|
+
buffer = described_class.new("@\xC3\x88\x0F\xC2\x7F\x9DU")
|
128
|
+
buffer.read_double.should == 10000.123123123
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'consumes the bytes' do
|
132
|
+
buffer = described_class.new("@\xC3\x88\x0F\xC2\x7F\x9DUxyz")
|
133
|
+
buffer.read_double
|
134
|
+
buffer.should eql_bytes('xyz')
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'raises an error when there is not enough bytes available' do
|
138
|
+
buffer = described_class.new("@\xC3\x88\x0F")
|
139
|
+
expect { buffer.read_double }.to raise_error(DecodingError)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe '#read_float' do
|
144
|
+
it 'decodes a float' do
|
145
|
+
buffer = described_class.new("AB\x14{")
|
146
|
+
buffer.read_float.should be_within(0.00001).of(12.13)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'consumes the bytes' do
|
150
|
+
buffer = described_class.new("AB\x14{xyz")
|
151
|
+
buffer.read_float
|
152
|
+
buffer.should eql_bytes('xyz')
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'raises an error when there is not enough bytes available' do
|
156
|
+
buffer = described_class.new("\x0F")
|
157
|
+
expect { buffer.read_float }.to raise_error(DecodingError)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe '#read_signed_int' do
|
162
|
+
let :buffer do
|
163
|
+
described_class.new("\x00\xff\x00\xff")
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'decodes a positive int' do
|
167
|
+
buffer.read_signed_int.should == 0x00ff00ff
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'decodes a negative int' do
|
171
|
+
buffer = described_class.new("\xff\xee\xdd\xcc")
|
172
|
+
buffer.read_signed_int.should == 0xffeeddcc - 0x100000000
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'consumes the bytes' do
|
176
|
+
buffer << "\xab\xcd"
|
177
|
+
buffer.read_signed_int
|
178
|
+
buffer.should eql_bytes("\xab\xcd")
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
182
|
+
buffer = described_class.new("\x01\xab")
|
183
|
+
expect { buffer.read_signed_int }.to raise_error(DecodingError)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe '#read_unsigned_short' do
|
188
|
+
let :buffer do
|
189
|
+
described_class.new("\x00\x02")
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'decodes a short' do
|
193
|
+
buffer.read_unsigned_short.should == 2
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'consumes the bytes' do
|
197
|
+
buffer << "\xff\xff"
|
198
|
+
buffer.read_unsigned_short
|
199
|
+
buffer.should eql_bytes("\xff\xff")
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
203
|
+
buffer = described_class.new("\x01")
|
204
|
+
expect { buffer.read_unsigned_short }.to raise_error(DecodingError)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe '#read_string' do
|
209
|
+
let :buffer do
|
210
|
+
described_class.new("\x00\x0bhej och hå")
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'decodes a string' do
|
214
|
+
buffer.read_string.should == 'hej och hå'.force_encoding(::Encoding::UTF_8)
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'decodes a string as UTF-8' do
|
218
|
+
buffer.read_string.encoding.should == ::Encoding::UTF_8
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'decodes an empty string' do
|
222
|
+
buffer = described_class.new("\x00\x00")
|
223
|
+
buffer.read_string.should be_empty
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'consumes the bytes' do
|
227
|
+
buffer << "\xff\xff"
|
228
|
+
buffer.read_string
|
229
|
+
buffer.should eql_bytes("\xff\xff")
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
233
|
+
b = described_class.new(buffer.read(5))
|
234
|
+
expect { b.read_string }.to raise_error(DecodingError)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe '#read_long_string' do
|
239
|
+
let :buffer do
|
240
|
+
described_class.new("\x00\x01\x00\00" << ('x' * 0x10000))
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'decodes a string' do
|
244
|
+
str = buffer.read_long_string
|
245
|
+
str.should start_with('xxx')
|
246
|
+
str.length.should == 0x10000
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'decodes a string as UTF-8' do
|
250
|
+
buffer.read_long_string.encoding.should == ::Encoding::UTF_8
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'consumes the bytes' do
|
254
|
+
buffer << "\xff\xff"
|
255
|
+
buffer.read_long_string
|
256
|
+
buffer.should eql_bytes("\xff\xff")
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
260
|
+
b = described_class.new(buffer.read(246))
|
261
|
+
expect { b.read_long_string }.to raise_error(DecodingError)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
describe '#read_uuid' do
|
266
|
+
let :buffer do
|
267
|
+
described_class.new("\xA4\xA7\t\x00$\xE1\x11\xDF\x89$\x00\x1F\xF3Y\x17\x11")
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'decodes a UUID as a Cql::Uuid' do
|
271
|
+
buffer.read_uuid.should == Uuid.new('a4a70900-24e1-11df-8924-001ff3591711')
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'decodes a UUID as a Cql::TimeUuid' do
|
275
|
+
uuid = buffer.read_uuid(TimeUuid)
|
276
|
+
uuid.should == TimeUuid.new('a4a70900-24e1-11df-8924-001ff3591711')
|
277
|
+
uuid.should be_a(TimeUuid)
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'consumes the bytes' do
|
281
|
+
buffer.read_uuid
|
282
|
+
buffer.should be_empty
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'raises an error when there a not enough bytes in the buffer' do
|
286
|
+
b = described_class.new(buffer.discard(2).read(5))
|
287
|
+
expect { b.read_uuid }.to raise_error(DecodingError)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
describe '#read_string_list' do
|
292
|
+
let :buffer do
|
293
|
+
described_class.new("\x00\x02\x00\x05hello\x00\x05world")
|
294
|
+
end
|
295
|
+
|
296
|
+
it 'decodes a string list' do
|
297
|
+
buffer.read_string_list.should == %w[hello world]
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'decodes an empty string list' do
|
301
|
+
buffer = described_class.new("\x00\x00")
|
302
|
+
buffer.read_string_list.should == []
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'consumes the bytes' do
|
306
|
+
buffer << "\xff\xff"
|
307
|
+
buffer.read_string_list
|
308
|
+
buffer.should eql_bytes("\xff\xff")
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
312
|
+
b = described_class.new(buffer.read(13))
|
313
|
+
expect { b.read_string_list }.to raise_error(DecodingError)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
describe '#read_bytes' do
|
318
|
+
let :buffer do
|
319
|
+
described_class.new("\x00\x01\x00\x00" << ("\x42" * 0x10000))
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'decodes a byte array' do
|
323
|
+
buffer.read_bytes.should eql_bytes("\x42" * 0x10000)
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'decodes an empty byte array' do
|
327
|
+
buffer = described_class.new("\x00\x00\x00\x00")
|
328
|
+
buffer.read_bytes.should be_empty
|
329
|
+
end
|
330
|
+
|
331
|
+
it 'decodes null' do
|
332
|
+
buffer = described_class.new("\x80\x00\x00\x00")
|
333
|
+
buffer.read_bytes.should be_nil
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'consumes the bytes' do
|
337
|
+
buffer << "\xab\xcd"
|
338
|
+
buffer.read_bytes
|
339
|
+
buffer.should eql_bytes("\xab\xcd")
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
343
|
+
b = described_class.new(buffer.read(10))
|
344
|
+
expect { b.read_bytes }.to raise_error(DecodingError)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
describe '#read_short_bytes' do
|
349
|
+
let :buffer do
|
350
|
+
described_class.new("\x01\x00" << ("\x42" * 0x100))
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'decodes a byte array' do
|
354
|
+
buffer.read_short_bytes.should eql_bytes("\x42" * 0x100)
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'decodes an empty byte array' do
|
358
|
+
buffer = described_class.new("\x00\x00\x00\x00")
|
359
|
+
buffer.read_short_bytes.should be_empty
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'decodes null' do
|
363
|
+
buffer = described_class.new("\x80\x00")
|
364
|
+
buffer.read_short_bytes.should be_nil
|
365
|
+
end
|
366
|
+
|
367
|
+
it 'consumes the bytes' do
|
368
|
+
buffer << "\xab\xcd"
|
369
|
+
buffer.read_short_bytes
|
370
|
+
buffer.should eql_bytes("\xab\xcd")
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
374
|
+
b = described_class.new(buffer.read(10))
|
375
|
+
expect { b.read_short_bytes }.to raise_error(DecodingError)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
describe '#read_option' do
|
380
|
+
it 'decodes an option ID and value with instructions from a block' do
|
381
|
+
buffer = described_class.new("\x00\x01\x00\x03foo")
|
382
|
+
id, value = buffer.read_option do |id, buffer|
|
383
|
+
buffer.read_string
|
384
|
+
end
|
385
|
+
id.should == 1
|
386
|
+
value.should == 'foo'
|
387
|
+
end
|
388
|
+
|
389
|
+
it 'decodes an option ID and nil value when there is no block' do
|
390
|
+
buffer = described_class.new("\xaa\xbb")
|
391
|
+
id, value = buffer.read_option
|
392
|
+
id.should == 0xaabb
|
393
|
+
value.should be_nil
|
394
|
+
end
|
395
|
+
|
396
|
+
it 'consumes the bytes' do
|
397
|
+
buffer = described_class.new("\x00\x01\x00\x03\xab")
|
398
|
+
id, value = buffer.read_option do |id, buffer|
|
399
|
+
buffer.read_short
|
400
|
+
end
|
401
|
+
buffer.should eql_bytes("\xab")
|
402
|
+
end
|
403
|
+
|
404
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
405
|
+
b = described_class.new("\xaa")
|
406
|
+
expect { b.read_option }.to raise_error(DecodingError)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
describe '#read_inet' do
|
411
|
+
it 'decodes an IPv4 + port pair' do
|
412
|
+
buffer = described_class.new("\x04\x00\x00\x00\x00\x00\x00#R")
|
413
|
+
ip_addr, port = buffer.read_inet
|
414
|
+
ip_addr.should == IPAddr.new('0.0.0.0')
|
415
|
+
port.should == 9042
|
416
|
+
end
|
417
|
+
|
418
|
+
it 'decodes an IPv6 + port pair' do
|
419
|
+
buffer = described_class.new("\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00#R")
|
420
|
+
ip_addr, port = buffer.read_inet
|
421
|
+
ip_addr.should == IPAddr.new('::1')
|
422
|
+
port.should == 9042
|
423
|
+
end
|
424
|
+
|
425
|
+
it 'consumes the bytes' do
|
426
|
+
buffer = described_class.new("\x04\x00\x00\x00\x00\x00\x00#R\xff\xaa")
|
427
|
+
buffer.read_inet
|
428
|
+
buffer.should eql_bytes("\xff\xaa")
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
432
|
+
buffer1 = described_class.new("\x04\x00\x00\x00\x00\x00\x00")
|
433
|
+
expect { buffer1.read_inet }.to raise_error(DecodingError)
|
434
|
+
buffer2 = described_class.new("\x04\x00\x00\x00")
|
435
|
+
expect { buffer2.read_inet }.to raise_error(DecodingError)
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
describe '#read_consistency' do
|
440
|
+
{
|
441
|
+
:any => "\x00\x00",
|
442
|
+
:one => "\x00\x01",
|
443
|
+
:two => "\x00\x02",
|
444
|
+
:three => "\x00\x03",
|
445
|
+
:quorum => "\x00\x04",
|
446
|
+
:all => "\x00\x05",
|
447
|
+
:local_quorum => "\x00\x06",
|
448
|
+
:each_quorum => "\x00\x07",
|
449
|
+
:serial => "\x00\x08",
|
450
|
+
:local_serial => "\x00\x09",
|
451
|
+
:local_one => "\x00\x0a",
|
452
|
+
}.each do |consistency, bytes|
|
453
|
+
it "decodes #{consistency.to_s.upcase}" do
|
454
|
+
buffer = described_class.new(bytes)
|
455
|
+
buffer.read_consistency.should == consistency
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
it 'raises an exception for an unknown consistency' do
|
460
|
+
expect { CqlByteBuffer.new("\xff\xff").read_consistency }.to raise_error(DecodingError)
|
461
|
+
expect { CqlByteBuffer.new("\x00\x0f").read_consistency }.to raise_error(DecodingError)
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
describe '#read_string_map' do
|
466
|
+
let :buffer do
|
467
|
+
described_class.new("\x00\x02\x00\x05hello\x00\x05world\x00\x03foo\x00\x03bar")
|
468
|
+
end
|
469
|
+
|
470
|
+
it 'decodes a string multimap' do
|
471
|
+
buffer.read_string_map.should == {'hello' => 'world', 'foo' => 'bar'}
|
472
|
+
end
|
473
|
+
|
474
|
+
it 'decodes an empty string map' do
|
475
|
+
buffer = described_class.new("\x00\x00")
|
476
|
+
buffer.read_string_map.should == {}
|
477
|
+
end
|
478
|
+
|
479
|
+
it 'consumes the bytes' do
|
480
|
+
buffer << "\xff"
|
481
|
+
buffer.read_string_map
|
482
|
+
buffer.should eql_bytes("\xff")
|
483
|
+
end
|
484
|
+
|
485
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
486
|
+
b = described_class.new(buffer.read(20))
|
487
|
+
expect { b.read_string_map }.to raise_error(DecodingError)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
describe '#read_string_multimap' do
|
492
|
+
let :buffer do
|
493
|
+
described_class.new("\x00\x02\x00\x0bCQL_VERSION\x00\x01\x00\x053.0.0\x00\x0bCOMPRESSION\x00\x02\x00\x06snappy\x00\x04gzip")
|
494
|
+
end
|
495
|
+
|
496
|
+
it 'decodes a string multimap' do
|
497
|
+
buffer.read_string_multimap.should == {'CQL_VERSION' => ['3.0.0'], 'COMPRESSION' => ['snappy', 'gzip']}
|
498
|
+
end
|
499
|
+
|
500
|
+
it 'decodes an empty string multimap' do
|
501
|
+
buffer = described_class.new("\x00\x00")
|
502
|
+
buffer.read_string_multimap.should == {}
|
503
|
+
end
|
504
|
+
|
505
|
+
it 'consumes the bytes' do
|
506
|
+
buffer << "\xff"
|
507
|
+
buffer.read_string_multimap
|
508
|
+
buffer.should eql_bytes("\xff")
|
509
|
+
end
|
510
|
+
|
511
|
+
it 'raises an error when there are not enough bytes in the buffer' do
|
512
|
+
b = described_class.new(buffer.read(40))
|
513
|
+
expect { b.read_string_multimap }.to raise_error(DecodingError)
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
describe '#append_int' do
|
518
|
+
it 'encodes an int' do
|
519
|
+
buffer.append_int(2323234234)
|
520
|
+
buffer.should eql_bytes("\x8a\x79\xbd\xba")
|
521
|
+
end
|
522
|
+
|
523
|
+
it 'appends to the buffer' do
|
524
|
+
buffer << "\xab"
|
525
|
+
buffer.append_int(10)
|
526
|
+
buffer.should eql_bytes("\xab\x00\x00\x00\x0a")
|
527
|
+
end
|
528
|
+
|
529
|
+
it 'returns the buffer' do
|
530
|
+
result = buffer.append_int(2323234234)
|
531
|
+
result.should equal(buffer)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
describe '#append_short' do
|
536
|
+
it 'encodes a short' do
|
537
|
+
buffer.append_short(0xabcd)
|
538
|
+
buffer.should eql_bytes("\xab\xcd")
|
539
|
+
end
|
540
|
+
|
541
|
+
it 'appends to the buffer' do
|
542
|
+
buffer << "\xab"
|
543
|
+
buffer.append_short(10)
|
544
|
+
buffer.should eql_bytes("\xab\x00\x0a")
|
545
|
+
end
|
546
|
+
|
547
|
+
it 'returns the buffer' do
|
548
|
+
result = buffer.append_short(42)
|
549
|
+
result.should equal(buffer)
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
describe '#append_string' do
|
554
|
+
it 'encodes a string' do
|
555
|
+
buffer.append_string('hello')
|
556
|
+
buffer.should eql_bytes("\x00\x05hello")
|
557
|
+
end
|
558
|
+
|
559
|
+
it 'encodes a string with multibyte characters' do
|
560
|
+
buffer << "\xff"
|
561
|
+
str = 'I love π'
|
562
|
+
buffer.append_string(str)
|
563
|
+
buffer.should eql_bytes("\xff\x00\x09I love π")
|
564
|
+
end
|
565
|
+
|
566
|
+
it 'encodes an empty string' do
|
567
|
+
buffer.append_string('')
|
568
|
+
buffer.should eql_bytes("\x00\x00")
|
569
|
+
end
|
570
|
+
|
571
|
+
it 'encodes a non-string' do
|
572
|
+
buffer.append_string(42)
|
573
|
+
buffer.should eql_bytes("\x00\x0242")
|
574
|
+
end
|
575
|
+
|
576
|
+
it 'appends to the buffer' do
|
577
|
+
buffer << "\xab"
|
578
|
+
buffer.append_string('foo')
|
579
|
+
buffer.should eql_bytes("\xab\x00\x03foo")
|
580
|
+
end
|
581
|
+
|
582
|
+
it 'returns the buffer' do
|
583
|
+
result = buffer.append_string('hello')
|
584
|
+
result.should equal(buffer)
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
describe '#append_long_string' do
|
589
|
+
it 'encodes a string' do
|
590
|
+
buffer.append_long_string('hello world ' * 100_000)
|
591
|
+
buffer.read(45).should eql_bytes("\x00\x12\x4f\x80hello world hello world hello world hello")
|
592
|
+
end
|
593
|
+
|
594
|
+
it 'encodes a string with multibyte characters' do
|
595
|
+
buffer << "\xff"
|
596
|
+
str = 'I love π'
|
597
|
+
buffer.append_long_string(str)
|
598
|
+
buffer.should eql_bytes("\xff\x00\x00\x00\x09I love π")
|
599
|
+
end
|
600
|
+
|
601
|
+
it 'encodes an empty string' do
|
602
|
+
buffer.append_long_string('')
|
603
|
+
buffer.should eql_bytes("\x00\x00\x00\x00")
|
604
|
+
end
|
605
|
+
|
606
|
+
it 'appends to the buffer' do
|
607
|
+
buffer << "\xab"
|
608
|
+
buffer.append_long_string('foo')
|
609
|
+
buffer.should eql_bytes("\xab\x00\x00\x00\x03foo")
|
610
|
+
end
|
611
|
+
|
612
|
+
it 'returns the buffer' do
|
613
|
+
result = buffer.append_long_string('hello')
|
614
|
+
result.should equal(buffer)
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
describe '#append_uuid' do
|
619
|
+
let :uuid do
|
620
|
+
Uuid.new('a4a70900-24e1-11df-8924-001ff3591711')
|
621
|
+
end
|
622
|
+
|
623
|
+
it 'encodes an UUID' do
|
624
|
+
buffer.append_uuid(uuid)
|
625
|
+
buffer.should eql_bytes("\xA4\xA7\t\x00$\xE1\x11\xDF\x89$\x00\x1F\xF3Y\x17\x11")
|
626
|
+
end
|
627
|
+
|
628
|
+
it 'encodes a UUID as 16 bytes' do
|
629
|
+
buffer.append_uuid(Uuid.new('00000000-24e1-11df-8924-001ff3591711'))
|
630
|
+
buffer.size.should eql(16)
|
631
|
+
end
|
632
|
+
|
633
|
+
it 'appends to the buffer' do
|
634
|
+
buffer << 'FOO'
|
635
|
+
buffer.append_uuid(uuid)
|
636
|
+
buffer.read(3).should eql_bytes('FOO')
|
637
|
+
end
|
638
|
+
|
639
|
+
it 'returns the buffer' do
|
640
|
+
result = buffer.append_uuid(uuid)
|
641
|
+
result.should equal(buffer)
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
describe '#append_string_list' do
|
646
|
+
it 'encodes a string list' do
|
647
|
+
buffer.append_string_list(%w[foo bar hello world])
|
648
|
+
buffer.should eql_bytes("\x00\x04\x00\x03foo\x00\x03bar\x00\x05hello\x00\x05world")
|
649
|
+
end
|
650
|
+
|
651
|
+
it 'encodes a string with multibyte characters' do
|
652
|
+
buffer << "\xff"
|
653
|
+
str = %w[I love π]
|
654
|
+
buffer.append_string_list(str)
|
655
|
+
buffer.should eql_bytes("\xff\x00\x03\x00\x01I\x00\x04love\x00\x02π")
|
656
|
+
end
|
657
|
+
|
658
|
+
it 'encodes an empty string list' do
|
659
|
+
buffer.append_string_list([])
|
660
|
+
buffer.should eql_bytes("\x00\x00")
|
661
|
+
end
|
662
|
+
|
663
|
+
it 'appends to the buffer' do
|
664
|
+
buffer << "\xab"
|
665
|
+
buffer.append_string_list(%w[foo bar])
|
666
|
+
buffer.should eql_bytes("\xab\x00\x02\x00\x03foo\x00\x03bar")
|
667
|
+
end
|
668
|
+
|
669
|
+
it 'returns the buffer' do
|
670
|
+
result = buffer.append_string_list(%w[foo])
|
671
|
+
result.should equal(buffer)
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
describe '#append_bytes' do
|
676
|
+
it 'encodes a byte array' do
|
677
|
+
buffer.append_bytes("\xaa" * 2000)
|
678
|
+
buffer.should eql_bytes("\x00\x00\x07\xd0" << ("\xaa" * 2000))
|
679
|
+
end
|
680
|
+
|
681
|
+
it 'encodes a string with multibyte characters' do
|
682
|
+
buffer << "\xff"
|
683
|
+
str = 'I love π'
|
684
|
+
buffer.append_bytes(str)
|
685
|
+
buffer.should eql_bytes("\xff\x00\x00\x00\x09I love π")
|
686
|
+
end
|
687
|
+
|
688
|
+
it 'encodes nil' do
|
689
|
+
buffer.append_bytes(nil)
|
690
|
+
buffer.should eql_bytes("\xff\xff\xff\xff")
|
691
|
+
end
|
692
|
+
|
693
|
+
it 'appends to the buffer' do
|
694
|
+
buffer << "\xab"
|
695
|
+
buffer.append_bytes("\xf0\x0b\xbar")
|
696
|
+
buffer.should eql_bytes("\xab\x00\x00\x00\x04\xf0\x0b\xbar")
|
697
|
+
end
|
698
|
+
|
699
|
+
it 'returns the buffer' do
|
700
|
+
result = buffer.append_bytes("\xab")
|
701
|
+
result.should equal(buffer)
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
describe '#append_short_bytes' do
|
706
|
+
it 'encodes a byte array' do
|
707
|
+
buffer.append_short_bytes("\xaa\xbb\xcc")
|
708
|
+
buffer.should eql_bytes("\x00\x03\xaa\xbb\xcc")
|
709
|
+
end
|
710
|
+
|
711
|
+
it 'encodes a string with multibyte characters' do
|
712
|
+
buffer << "\xff"
|
713
|
+
str = 'I love π'
|
714
|
+
buffer.append_short_bytes(str)
|
715
|
+
buffer.should eql_bytes("\xff\x00\x09I love π")
|
716
|
+
end
|
717
|
+
|
718
|
+
it 'encodes nil' do
|
719
|
+
buffer.append_short_bytes(nil)
|
720
|
+
buffer.should eql_bytes("\xff\xff")
|
721
|
+
end
|
722
|
+
|
723
|
+
it 'appends to the buffer' do
|
724
|
+
buffer << "\xab"
|
725
|
+
buffer.append_short_bytes("\xf0\x0b\xbar")
|
726
|
+
buffer.should eql_bytes("\xab\x00\x04\xf0\x0b\xbar")
|
727
|
+
end
|
728
|
+
|
729
|
+
it 'returns the buffer' do
|
730
|
+
result = buffer.append_short_bytes("\xab")
|
731
|
+
result.should equal(buffer)
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
describe '#append_consistency' do
|
736
|
+
{
|
737
|
+
:any => "\x00\x00",
|
738
|
+
:one => "\x00\x01",
|
739
|
+
:two => "\x00\x02",
|
740
|
+
:three => "\x00\x03",
|
741
|
+
:quorum => "\x00\x04",
|
742
|
+
:all => "\x00\x05",
|
743
|
+
:local_quorum => "\x00\x06",
|
744
|
+
:each_quorum => "\x00\x07",
|
745
|
+
:serial => "\x00\x08",
|
746
|
+
:local_serial => "\x00\x09",
|
747
|
+
:local_one => "\x00\x0a",
|
748
|
+
}.each do |consistency, expected_encoding|
|
749
|
+
it "encodes #{consistency}" do
|
750
|
+
buffer.append_consistency(consistency)
|
751
|
+
buffer.should eql_bytes(expected_encoding)
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
755
|
+
it 'raises an exception for an unknown consistency' do
|
756
|
+
expect { buffer.append_consistency(:foo) }.to raise_error(EncodingError)
|
757
|
+
end
|
758
|
+
|
759
|
+
it 'appends to the buffer' do
|
760
|
+
buffer << "\xab"
|
761
|
+
buffer.append_consistency(:one)
|
762
|
+
buffer.should eql_bytes("\xab\x00\x01")
|
763
|
+
end
|
764
|
+
|
765
|
+
it 'returns the buffer' do
|
766
|
+
result = buffer.append_consistency(:quorum)
|
767
|
+
result.should equal(buffer)
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
describe '#append_string_map' do
|
772
|
+
it 'encodes a string map' do
|
773
|
+
buffer.append_string_map('HELLO' => 'world', 'foo' => 'bar')
|
774
|
+
buffer.should eql_bytes("\x00\x02\x00\x05HELLO\x00\x05world\x00\x03foo\x00\x03bar")
|
775
|
+
end
|
776
|
+
|
777
|
+
it 'encodes an empty map' do
|
778
|
+
buffer.append_string_map({})
|
779
|
+
buffer.should eql_bytes("\x00\x00")
|
780
|
+
end
|
781
|
+
|
782
|
+
it 'appends to the buffer' do
|
783
|
+
buffer << "\xab"
|
784
|
+
buffer.append_string_map('foo' => 'bar')
|
785
|
+
buffer.should eql_bytes("\xab\x00\x01\x00\x03foo\x00\x03bar")
|
786
|
+
end
|
787
|
+
|
788
|
+
it 'returns the buffer' do
|
789
|
+
result = buffer.append_string_map('HELLO' => 'world')
|
790
|
+
result.should equal(buffer)
|
791
|
+
end
|
792
|
+
end
|
793
|
+
|
794
|
+
describe '#append_long' do
|
795
|
+
it 'encodes a long' do
|
796
|
+
buffer.append_long(0x0123456789)
|
797
|
+
buffer.should eql_bytes("\x00\x00\x00\x01\x23\x45\x67\x89")
|
798
|
+
end
|
799
|
+
|
800
|
+
it 'appends to the buffer' do
|
801
|
+
buffer << "\x99"
|
802
|
+
buffer.append_long(0x0123456789)
|
803
|
+
buffer.should eql_bytes("\x99\x00\x00\x00\x01\x23\x45\x67\x89")
|
804
|
+
end
|
805
|
+
|
806
|
+
it 'returns the buffer' do
|
807
|
+
result = buffer.append_long(1)
|
808
|
+
result.should equal(buffer)
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
describe '#append_varint' do
|
813
|
+
it 'encodes a variable length integer' do
|
814
|
+
buffer.append_varint(1231312312331283012830129382342342412123)
|
815
|
+
buffer.should eql_bytes("\x03\x9EV \x15\f\x03\x9DK\x18\xCDI\\$?\a[")
|
816
|
+
end
|
817
|
+
|
818
|
+
it 'encodes a negative variable length integer' do
|
819
|
+
buffer.append_varint(-234234234234)
|
820
|
+
buffer.should eql_bytes("\xC9v\x8D:\x86")
|
821
|
+
end
|
822
|
+
|
823
|
+
it 'encodes a negative variable length integer' do
|
824
|
+
buffer.append_varint(-1)
|
825
|
+
buffer.should eql_bytes("\xff")
|
826
|
+
end
|
827
|
+
|
828
|
+
it 'appends to the buffer' do
|
829
|
+
buffer << "\x99"
|
830
|
+
buffer.append_varint(-234234234234)
|
831
|
+
buffer.should eql_bytes("\x99\xC9v\x8D:\x86")
|
832
|
+
end
|
833
|
+
|
834
|
+
it 'returns the buffer' do
|
835
|
+
result = buffer.append_varint(-234234234234)
|
836
|
+
result.should equal(buffer)
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
describe '#append_decimal' do
|
841
|
+
it 'encodes a BigDecimal as a decimal' do
|
842
|
+
buffer.append_decimal(BigDecimal.new('1042342234234.123423435647768234'))
|
843
|
+
buffer.should eql_bytes("\x00\x00\x00\x12\r'\xFDI\xAD\x80f\x11g\xDCfV\xAA")
|
844
|
+
end
|
845
|
+
|
846
|
+
it 'appends to the buffer' do
|
847
|
+
buffer << "\x99"
|
848
|
+
buffer.append_decimal(BigDecimal.new('1042342234234.123423435647768234'))
|
849
|
+
buffer.read(1).should eql_bytes("\x99")
|
850
|
+
end
|
851
|
+
|
852
|
+
it 'returns the buffer' do
|
853
|
+
result = buffer.append_decimal(BigDecimal.new('3.14'))
|
854
|
+
result.should equal(buffer)
|
855
|
+
end
|
856
|
+
end
|
857
|
+
|
858
|
+
describe '#append_double' do
|
859
|
+
it 'encodes a double' do
|
860
|
+
buffer.append_double(10000.123123123)
|
861
|
+
buffer.should eql_bytes("@\xC3\x88\x0F\xC2\x7F\x9DU")
|
862
|
+
end
|
863
|
+
|
864
|
+
it 'appends to the buffer' do
|
865
|
+
buffer << 'BEFORE'
|
866
|
+
buffer.append_double(10000.123123123)
|
867
|
+
buffer.read(6).should eql_bytes('BEFORE')
|
868
|
+
end
|
869
|
+
|
870
|
+
it 'returns the buffer' do
|
871
|
+
result = buffer.append_double(10000.123123123)
|
872
|
+
result.should equal(buffer)
|
873
|
+
end
|
874
|
+
end
|
875
|
+
|
876
|
+
describe '#append_float' do
|
877
|
+
it 'encodes a float' do
|
878
|
+
buffer.append_float(12.13)
|
879
|
+
buffer.should eql_bytes("AB\x14{")
|
880
|
+
end
|
881
|
+
|
882
|
+
it 'appends to the buffer' do
|
883
|
+
buffer << 'BEFORE'
|
884
|
+
buffer.append_float(12.13)
|
885
|
+
buffer.read(6).should eql_bytes('BEFORE')
|
886
|
+
end
|
887
|
+
|
888
|
+
it 'returns the buffer' do
|
889
|
+
result = buffer.append_float(12.13)
|
890
|
+
result.should equal(buffer)
|
891
|
+
end
|
892
|
+
end
|
893
|
+
end
|
894
|
+
end
|
895
|
+
end
|