cql-rb 1.0.0.pre0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,290 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ module Cql
7
+ module Io
8
+ describe IoReactor do
9
+ let :host do
10
+ Socket.gethostname
11
+ end
12
+
13
+ let :port do
14
+ 34535
15
+ end
16
+
17
+ let :server do
18
+ FakeServer.new(port)
19
+ end
20
+
21
+ let :io_reactor do
22
+ described_class.new(connection_timeout: 1)
23
+ end
24
+
25
+ before do
26
+ server.start!
27
+ end
28
+
29
+ after do
30
+ io_reactor.stop.get if io_reactor.running?
31
+ server.stop!
32
+ end
33
+
34
+ describe '#initialize' do
35
+ it 'does not connect' do
36
+ described_class.new
37
+ sleep(0.1)
38
+ server.connects.should == 0
39
+ end
40
+ end
41
+
42
+ describe '#running?' do
43
+ it 'is initially false' do
44
+ io_reactor.should_not be_running
45
+ end
46
+
47
+ it 'is true when started' do
48
+ io_reactor.start.get
49
+ io_reactor.should be_running
50
+ end
51
+
52
+ it 'is true when starting' do
53
+ f = io_reactor.start
54
+ io_reactor.should be_running
55
+ f.get
56
+ end
57
+
58
+ it 'is false when stopped' do
59
+ io_reactor.start.get
60
+ io_reactor.stop.get
61
+ io_reactor.should_not be_running
62
+ end
63
+ end
64
+
65
+ describe '#stop' do
66
+ it 'closes all connections' do
67
+ io_reactor.start.get
68
+ f1 = io_reactor.add_connection(host, port)
69
+ f2 = io_reactor.add_connection(host, port)
70
+ f3 = io_reactor.add_connection(host, port)
71
+ f4 = io_reactor.add_connection(host, port)
72
+ Future.combine(f1, f2, f3, f4).get
73
+ io_reactor.stop.get
74
+ server.await_disconnects!(4)
75
+ server.disconnects.should == 4
76
+ end
77
+
78
+ it 'succeeds connection futures when stopping while connecting' do
79
+ f = io_reactor.add_connection(host, port + 9)
80
+ io_reactor.start
81
+ io_reactor.stop
82
+ f.get
83
+ end
84
+ end
85
+
86
+ describe '#add_connection' do
87
+ before do
88
+ io_reactor.start.get
89
+ end
90
+
91
+ it 'connects to the specified host and port' do
92
+ future = io_reactor.add_connection(host, port)
93
+ future.get
94
+ server.await_connects!(1)
95
+ server.connects.should == 1
96
+ end
97
+
98
+ it 'yields the connection ID when completed' do
99
+ future = io_reactor.add_connection(host, port)
100
+ future.get.should_not be_nil
101
+ end
102
+
103
+ it 'fails the returned future when it cannot connect to the host' do
104
+ future = io_reactor.add_connection('example.com', port)
105
+ expect { future.get }.to raise_error(ConnectionError)
106
+ end
107
+
108
+ it 'fails the returned future when it cannot connect to the port' do
109
+ future = io_reactor.add_connection(host, 9999)
110
+ expect { future.get }.to raise_error(ConnectionError)
111
+ end
112
+
113
+ it 'times out quickly when it cannot connect' do
114
+ started_at = Time.now
115
+ begin
116
+ future = io_reactor.add_connection(host, 9999)
117
+ future.get
118
+ rescue ConnectionError
119
+ end
120
+ time_taken = (Time.now - started_at).to_f
121
+ time_taken.should be < 1.5
122
+ end
123
+
124
+ it 'can be called before the reactor is started' do
125
+ r = described_class.new(connection_timeout: 1)
126
+ f1 = r.add_connection(host, port)
127
+ f2 = r.start
128
+ f2.get
129
+ f1.get
130
+ end
131
+ end
132
+
133
+ describe '#queue_request' do
134
+ it 'eventually sends the request' do
135
+ io_reactor.start
136
+ io_reactor.add_connection(host, port).get
137
+ io_reactor.queue_request(Cql::Protocol::StartupRequest.new)
138
+ sleep(0.01) until server.received_bytes.size > 0
139
+ server.received_bytes[3, 1].should == "\x01"
140
+ end
141
+
142
+ it 'can be called before the reactor is started' do
143
+ io_reactor.queue_request(Cql::Protocol::StartupRequest.new)
144
+ io_reactor.start
145
+ io_reactor.add_connection(host, port).get
146
+ sleep(0.01) until server.received_bytes.size > 0
147
+ server.received_bytes[3, 1].should == "\x01"
148
+ end
149
+
150
+ it 'queues requests when all connections are busy' do
151
+ request = Cql::Protocol::QueryRequest.new('UPDATE x SET y = 1 WHERE z = 2', :one)
152
+
153
+ io_reactor.start
154
+ io_reactor.add_connection(host, port).get
155
+
156
+ futures = 200.times.map do
157
+ io_reactor.queue_request(request)
158
+ end
159
+
160
+ 128.times do |i|
161
+ server.broadcast!("\x81\x00#{[i].pack('c')}\b\x00\x00\x00\x04\x00\x00\x00\x01")
162
+ end
163
+
164
+ Future.combine(*futures.shift(128)).get
165
+
166
+ 128.times do |i|
167
+ server.broadcast!("\x81\x00#{[i].pack('c')}\b\x00\x00\x00\x04\x00\x00\x00\x01")
168
+ end
169
+
170
+ Future.combine(*futures).get
171
+ end
172
+
173
+ it 'performs the request using the connection with the given ID' do
174
+ future = Future.new
175
+ request = Cql::Protocol::StartupRequest.new
176
+ response = "\x81\x00\x00\x02\x00\x00\x00\x00"
177
+
178
+ io_reactor.start.on_complete do
179
+ io_reactor.add_connection(host, port).on_complete do |c1_id|
180
+ io_reactor.add_connection(host, port).on_complete do |c2_id|
181
+ q1_future = io_reactor.queue_request(request, c2_id)
182
+ q2_future = io_reactor.queue_request(request, c1_id)
183
+
184
+ Future.combine(q1_future, q2_future).on_complete do |(_, q1_id), (_, q2_id)|
185
+ future.complete!([c1_id, c2_id, q1_id, q2_id])
186
+ end
187
+
188
+ server.await_connects!(2)
189
+ server.broadcast!(response.dup)
190
+ end
191
+ end
192
+ end
193
+
194
+ connection1_id, connection2_id, query1_id, query2_id = future.value
195
+
196
+ connection1_id.should_not be_nil
197
+ connection2_id.should_not be_nil
198
+ query1_id.should == connection2_id
199
+ query2_id.should == connection1_id
200
+ end
201
+
202
+ it 'fails if the connection does not exist' do
203
+ f = io_reactor.start.flat_map do
204
+ io_reactor.add_connection(host, port).flat_map do
205
+ io_reactor.queue_request(Cql::Protocol::StartupRequest.new, 1234)
206
+ end
207
+ end
208
+ expect { f.get }.to raise_error(ConnectionNotFoundError)
209
+ end
210
+
211
+ it 'fails if the connection is busy' do
212
+ f = io_reactor.start.flat_map do
213
+ io_reactor.add_connection(host, port).flat_map do
214
+ io_reactor.add_connection(host, port).flat_map do |connection_id|
215
+ 200.times do
216
+ io_reactor.queue_request(Cql::Protocol::OptionsRequest.new, connection_id)
217
+ end
218
+ io_reactor.queue_request(Cql::Protocol::OptionsRequest.new, connection_id)
219
+ end
220
+ end
221
+ end
222
+ expect { f.get }.to raise_error(ConnectionBusyError)
223
+ end
224
+
225
+ it 'fails if the connection is busy, when there is only one connection' do
226
+ pending 'as it is the reactor doesn\'t try to deliver requests when all connections are busy'
227
+ end
228
+
229
+ it 'yields the response when completed' do
230
+ response = nil
231
+ io_reactor.start
232
+ io_reactor.add_connection(host, port).get
233
+ f = io_reactor.queue_request(Cql::Protocol::StartupRequest.new)
234
+ f.on_complete do |r, _|
235
+ response = r
236
+ end
237
+ server.broadcast!("\x81\x00\x00\x02\x00\x00\x00\x00")
238
+ sleep(0.01) until response
239
+ response.should == Cql::Protocol::ReadyResponse.new
240
+ end
241
+
242
+ it 'yields the connection ID when completed' do
243
+ connection = nil
244
+ io_reactor.start
245
+ io_reactor.add_connection(host, port).get
246
+ f = io_reactor.queue_request(Cql::Protocol::StartupRequest.new)
247
+ f.on_complete do |_, c|
248
+ connection = c
249
+ end
250
+ server.broadcast!("\x81\x00\x00\x02\x00\x00\x00\x00")
251
+ sleep(0.01) until connection
252
+ connection.should_not be_nil
253
+ end
254
+ end
255
+
256
+ describe '#add_event_listener' do
257
+ it 'calls the listener when frames with stream ID -1 arrives' do
258
+ event = nil
259
+ io_reactor.start
260
+ io_reactor.add_connection(host, port).get
261
+ io_reactor.add_event_listener { |e| event = e }
262
+ server.broadcast!("\x81\x00\xFF\f\x00\x00\x00+\x00\rSCHEMA_CHANGE\x00\aDROPPED\x00\nkeyspace01\x00\x05users")
263
+ sleep(0.01) until event
264
+ event.should == Cql::Protocol::SchemaChangeEventResponse.new('DROPPED', 'keyspace01', 'users')
265
+ end
266
+ end
267
+
268
+ context 'when errors occur' do
269
+ context 'in the IO loop' do
270
+ before do
271
+ bad_request = stub(:request)
272
+ bad_request.stub(:opcode).and_raise(StandardError.new('Blurgh'))
273
+ io_reactor.start
274
+ io_reactor.add_connection(host, port).get
275
+ io_reactor.queue_request(bad_request)
276
+ end
277
+
278
+ it 'stops' do
279
+ sleep(0.1)
280
+ io_reactor.should_not be_running
281
+ end
282
+
283
+ it 'fails the future returned from #stop' do
284
+ expect { io_reactor.stop.get }.to raise_error('Blurgh')
285
+ end
286
+ end
287
+ end
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,464 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ module Cql
7
+ module Protocol
8
+ describe Decoding do
9
+ describe '#read_byte!' do
10
+ let :buffer do
11
+ "\xab"
12
+ end
13
+
14
+ it 'decodes a raw byte' do
15
+ Decoding.read_byte!(buffer).should == 0xab
16
+ end
17
+
18
+ it 'consumes the byte' do
19
+ Decoding.read_byte!(buffer)
20
+ buffer.should be_empty
21
+ end
22
+
23
+ it 'raises an error when there is no byte available' do
24
+ expect { Decoding.read_byte!('') }.to raise_error(DecodingError)
25
+ end
26
+ end
27
+
28
+ describe '#read_varint!' do
29
+ it 'decodes a variable length integer' do
30
+ Decoding.read_varint!("\x03\x9EV \x15\f\x03\x9DK\x18\xCDI\\$?\a[", 17).should == 1231312312331283012830129382342342412123
31
+ end
32
+
33
+ it 'decodes a negative variable length integer' do
34
+ Decoding.read_varint!("\xC9v\x8D:\x86", 5).should == -234234234234
35
+ end
36
+
37
+ it 'decodes an unsigned variable length integer' do
38
+ Decoding.read_varint!("\xC9v\x8D:\x86", 5, false).should == 865277393542
39
+ end
40
+
41
+ it 'consumes the bytes' do
42
+ buffer = "\x03\x9EV \x15\f\x03\x9DK\x18\xCDI\\$?\a[\x01\x02\x03"
43
+ Decoding.read_varint!(buffer, 17)
44
+ buffer.should == "\x01\x02\x03"
45
+ end
46
+
47
+ it 'raises an error when there is not enough bytes available' do
48
+ expect { Decoding.read_varint!("\xC9v\x8D:", 7) }.to raise_error(DecodingError)
49
+ end
50
+ end
51
+
52
+ describe '#read_decimal!' do
53
+ let :buffer do
54
+ "\x00\x00\x00\x12\r'\xFDI\xAD\x80f\x11g\xDCfV\xAA"
55
+ end
56
+
57
+ it 'decodes a decimal to a BigDecimal' do
58
+ Decoding.read_decimal!(buffer, buffer.length).should == BigDecimal.new('1042342234234.123423435647768234')
59
+ end
60
+
61
+ it 'consumes the bytes' do
62
+ buffer << 'HELLO'
63
+ Decoding.read_decimal!(buffer, buffer.length - 5)
64
+ buffer.should == 'HELLO'
65
+ end
66
+
67
+ it 'defaults to using the buffer length' do
68
+ Decoding.read_decimal!(buffer.dup).should == Decoding.read_decimal!(buffer, buffer.length)
69
+ end
70
+
71
+ it 'raises an error when there is not enough bytes available' do
72
+ expect { Decoding.read_decimal!(buffer[0, 3], 7) }.to raise_error(DecodingError)
73
+ end
74
+ end
75
+
76
+ describe '#read_long!' do
77
+ it 'decodes a long' do
78
+ Decoding.read_long!("\x00\x00\xca\xfe\xba\xbe\x00\x00").should == 0x0000cafebabe0000
79
+ end
80
+
81
+ it 'consumes the bytes' do
82
+ buffer = "\xca\xfe\xba\xbe\xca\xfe\xba\xbe\xca\xfe\xba\xbe"
83
+ Decoding.read_long!(buffer)
84
+ buffer.should == "\xca\xfe\xba\xbe"
85
+ end
86
+
87
+ it 'raises an error when there is not enough bytes available' do
88
+ expect { Decoding.read_long!("\xca\xfe\xba\xbe\x00") }.to raise_error(DecodingError)
89
+ end
90
+ end
91
+
92
+ describe '#read_double!' do
93
+ it 'decodes a double' do
94
+ Decoding.read_double!("@\xC3\x88\x0F\xC2\x7F\x9DU").should == 10000.123123123
95
+ end
96
+
97
+ it 'consumes the bytes' do
98
+ buffer = "@\xC3\x88\x0F\xC2\x7F\x9DUxyz"
99
+ Decoding.read_double!(buffer)
100
+ buffer.should == 'xyz'
101
+ end
102
+
103
+ it 'raises an error when there is not enough bytes available' do
104
+ expect { Decoding.read_double!("@\xC3\x88\x0F") }.to raise_error(DecodingError)
105
+ end
106
+ end
107
+
108
+ describe '#read_float!' do
109
+ it 'decodes a float' do
110
+ Decoding.read_float!("AB\x14{").should be_within(0.00001).of(12.13)
111
+ end
112
+
113
+ it 'consumes the bytes' do
114
+ buffer = "AB\x14{xyz"
115
+ Decoding.read_float!(buffer)
116
+ buffer.should == 'xyz'
117
+ end
118
+
119
+ it 'raises an error when there is not enough bytes available' do
120
+ expect { Decoding.read_float!("\x0F") }.to raise_error(DecodingError)
121
+ end
122
+ end
123
+
124
+ describe '#read_int!' do
125
+ let :buffer do
126
+ "\x00\xff\x00\xff"
127
+ end
128
+
129
+ it 'decodes an int' do
130
+ Decoding.read_int!(buffer).should == 0x00ff00ff
131
+ end
132
+
133
+ it 'consumes the bytes' do
134
+ buffer << "\xab\xcd"
135
+ Decoding.read_int!(buffer)
136
+ buffer.should == "\xab\xcd"
137
+ end
138
+
139
+ it 'raises an error when there are not enough bytes in the buffer' do
140
+ expect { Decoding.read_int!("\x01\xab") }.to raise_error(DecodingError)
141
+ end
142
+ end
143
+
144
+ describe '#read_short!' do
145
+ let :buffer do
146
+ "\x00\x02"
147
+ end
148
+
149
+ it 'decodes a short' do
150
+ Decoding.read_short!(buffer).should == 2
151
+ end
152
+
153
+ it 'consumes the bytes' do
154
+ buffer << "\xff\xff"
155
+ Decoding.read_short!(buffer)
156
+ buffer.should == "\xff\xff"
157
+ end
158
+
159
+ it 'raises an error when there are not enough bytes in the buffer' do
160
+ expect { Decoding.read_short!("\x01") }.to raise_error(DecodingError)
161
+ end
162
+ end
163
+
164
+ describe '#read_string!' do
165
+ let :buffer do
166
+ "\x00\x0bhej och hå"
167
+ end
168
+
169
+ it 'decodes a string' do
170
+ Decoding.read_string!(buffer).should == 'hej och hå'.force_encoding(::Encoding::UTF_8)
171
+ end
172
+
173
+ it 'decodes a string as UTF-8' do
174
+ Decoding.read_string!(buffer).encoding.should == ::Encoding::UTF_8
175
+ end
176
+
177
+ it 'decodes an empty string' do
178
+ Decoding.read_string!("\x00\x00").should be_empty
179
+ end
180
+
181
+ it 'consumes the bytes' do
182
+ buffer << "\xff\xff"
183
+ Decoding.read_string!(buffer)
184
+ buffer.should == "\xff\xff"
185
+ end
186
+
187
+ it 'raises an error when there are not enough bytes in the buffer' do
188
+ expect { Decoding.read_string!(buffer.slice(0, 5)) }.to raise_error(DecodingError)
189
+ end
190
+ end
191
+
192
+ describe '#read_long_string!' do
193
+ let :buffer do
194
+ "\x00\x01\x00\00" << ('x' * 0x10000)
195
+ end
196
+
197
+ it 'decodes a string' do
198
+ Decoding.read_long_string!(buffer.dup).should start_with('xxx')
199
+ Decoding.read_long_string!(buffer).length.should == 0x10000
200
+ end
201
+
202
+ it 'decodes a string as UTF-8' do
203
+ Decoding.read_long_string!(buffer).encoding.should == ::Encoding::UTF_8
204
+ end
205
+
206
+ it 'consumes the bytes' do
207
+ buffer << "\xff\xff"
208
+ Decoding.read_long_string!(buffer)
209
+ buffer.should == "\xff\xff"
210
+ end
211
+
212
+ it 'raises an error when there are not enough bytes in the buffer' do
213
+ expect { Decoding.read_long_string!(buffer.slice(0, 246)) }.to raise_error(DecodingError)
214
+ end
215
+ end
216
+
217
+ describe '#read_uuid!' do
218
+ let :buffer do
219
+ "\xA4\xA7\t\x00$\xE1\x11\xDF\x89$\x00\x1F\xF3Y\x17\x11"
220
+ end
221
+
222
+ it 'decodes a UUID' do
223
+ Decoding.read_uuid!(buffer).should == Uuid.new('a4a70900-24e1-11df-8924-001ff3591711')
224
+ end
225
+
226
+ it 'consumes the bytes' do
227
+ Decoding.read_uuid!(buffer)
228
+ buffer.should be_empty
229
+ end
230
+
231
+ it 'raises an error when there a not enough bytes in the buffer' do
232
+ expect { Decoding.read_uuid!(buffer[2, 5]) }.to raise_error(DecodingError)
233
+ end
234
+ end
235
+
236
+ describe '#read_string_list!' do
237
+ let :buffer do
238
+ "\x00\x02\x00\x05hello\x00\x05world"
239
+ end
240
+
241
+ it 'decodes a string list' do
242
+ Decoding.read_string_list!(buffer).should == %w[hello world]
243
+ end
244
+
245
+ it 'decodes an empty string list' do
246
+ Decoding.read_string_list!("\x00\x00").should == []
247
+ end
248
+
249
+ it 'consumes the bytes' do
250
+ buffer << "\xff\xff"
251
+ Decoding.read_string_list!(buffer)
252
+ buffer.should == "\xff\xff"
253
+ end
254
+
255
+ it 'raises an error when there are not enough bytes in the buffer' do
256
+ expect { Decoding.read_string_list!(buffer.slice(0, 13)) }.to raise_error(DecodingError)
257
+ end
258
+ end
259
+
260
+ describe '#read_bytes!' do
261
+ let :buffer do
262
+ "\x00\x01\x00\x00" << ("\x42" * 0x10000)
263
+ end
264
+
265
+ it 'decodes a byte array' do
266
+ Decoding.read_bytes!(buffer).should == ("\x42" * 0x10000)
267
+ end
268
+
269
+ it 'decodes an empty byte array' do
270
+ Decoding.read_bytes!("\x00\x00\x00\x00").should == ''
271
+ end
272
+
273
+ it 'returns an ASCII-8BIT encoded string' do
274
+ Decoding.read_bytes!("\x00\x00\x00\x01\xaa").encoding.should == ::Encoding::BINARY
275
+ end
276
+
277
+ it 'decodes null' do
278
+ Decoding.read_bytes!("\x80\x00\x00\x00").should be_nil
279
+ end
280
+
281
+ it 'consumes the bytes' do
282
+ buffer << "\xab\xcd"
283
+ Decoding.read_bytes!(buffer)
284
+ buffer.should == "\xab\xcd"
285
+ end
286
+
287
+ it 'raises an error when there are not enough bytes in the buffer' do
288
+ expect { Decoding.read_bytes!(buffer[0, 10]) }.to raise_error(DecodingError)
289
+ end
290
+ end
291
+
292
+ describe '#read_short_bytes!' do
293
+ let :buffer do
294
+ "\x01\x00" << ("\x42" * 0x100)
295
+ end
296
+
297
+ it 'decodes a byte array' do
298
+ Decoding.read_short_bytes!(buffer).should == ("\x42" * 0x100)
299
+ end
300
+
301
+ it 'decodes an empty byte array' do
302
+ Decoding.read_short_bytes!("\x00\x00\x00\x00").should == ''
303
+ end
304
+
305
+ it 'returns an ASCII-8BIT encoded string' do
306
+ Decoding.read_short_bytes!("\x00\x00\x00\x01\xaa").encoding.should == ::Encoding::BINARY
307
+ end
308
+
309
+ it 'decodes null' do
310
+ Decoding.read_short_bytes!("\x80\x00").should be_nil
311
+ end
312
+
313
+ it 'consumes the bytes' do
314
+ buffer << "\xab\xcd"
315
+ Decoding.read_short_bytes!(buffer)
316
+ buffer.should == "\xab\xcd"
317
+ end
318
+
319
+ it 'raises an error when there are not enough bytes in the buffer' do
320
+ expect { Decoding.read_short_bytes!(buffer[0, 10]) }.to raise_error(DecodingError)
321
+ end
322
+ end
323
+
324
+ describe '#read_option!' do
325
+ it 'decodes an option ID and value with instructions from a block' do
326
+ id, value = Decoding.read_option!("\x00\x01\x00\x03foo") do |id, buffer|
327
+ Decoding.read_string!(buffer)
328
+ end
329
+ id.should == 1
330
+ value.should == 'foo'
331
+ end
332
+
333
+ it 'decodes an option ID and nil value when there is no block' do
334
+ id, value = Decoding.read_option!("\xaa\xbb")
335
+ id.should == 0xaabb
336
+ value.should be_nil
337
+ end
338
+
339
+ it 'consumes the bytes' do
340
+ buffer = "\x00\x01\x00\x03\xab"
341
+ id, value = Decoding.read_option!(buffer) do |id, buffer|
342
+ Decoding.read_short!(buffer)
343
+ end
344
+ buffer.should == "\xab"
345
+ end
346
+
347
+ it 'raises an error when there are not enough bytes in the buffer' do
348
+ expect { Decoding.read_option!("\xaa") }.to raise_error(DecodingError)
349
+ end
350
+ end
351
+
352
+ describe '#read_inet!' do
353
+ it 'decodes an IPv4 + port pair' do
354
+ ip_addr, port = Decoding.read_inet!("\x04\x00\x00\x00\x00\x00\x00#R")
355
+ ip_addr.should == IPAddr.new('0.0.0.0')
356
+ port.should == 9042
357
+ end
358
+
359
+ it 'decodes an IPv6 + port pair' do
360
+ ip_addr, port = Decoding.read_inet!("\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00#R")
361
+ ip_addr.should == IPAddr.new('::1')
362
+ port.should == 9042
363
+ end
364
+
365
+ it 'consumes the bytes' do
366
+ buffer = "\x04\x00\x00\x00\x00\x00\x00#R\xff\xaa"
367
+ Decoding.read_inet!(buffer)
368
+ buffer.should == "\xff\xaa"
369
+ end
370
+
371
+ it 'raises an error when there are not enough bytes in the buffer' do
372
+ expect { Decoding.read_inet!("\x04\x00\x00\x00\x00\x00\x00") }.to raise_error(DecodingError)
373
+ expect { Decoding.read_inet!("\x04\x00\x00\x00") }.to raise_error(DecodingError)
374
+ end
375
+ end
376
+
377
+ describe '#read_consistency!' do
378
+ it 'decodes ANY' do
379
+ Decoding.read_consistency!("\x00\x00").should == :any
380
+ end
381
+
382
+ it 'decodes ONE' do
383
+ Decoding.read_consistency!("\x00\x01").should == :one
384
+ end
385
+
386
+ it 'decodes TWO' do
387
+ Decoding.read_consistency!("\x00\x02").should == :two
388
+ end
389
+
390
+ it 'decodes THREE' do
391
+ Decoding.read_consistency!("\x00\x03").should == :three
392
+ end
393
+
394
+ it 'decodes QUORUM' do
395
+ Decoding.read_consistency!("\x00\x04").should == :quorum
396
+ end
397
+
398
+ it 'decodes ALL' do
399
+ Decoding.read_consistency!("\x00\x05").should == :all
400
+ end
401
+
402
+ it 'decodes LOCAL_QUORUM' do
403
+ Decoding.read_consistency!("\x00\x06").should == :local_quorum
404
+ end
405
+
406
+ it 'decodes EACH_QUORUM' do
407
+ Decoding.read_consistency!("\x00\x07").should == :each_quorum
408
+ end
409
+
410
+ it 'raises an exception for an unknown consistency' do
411
+ expect { Decoding.read_consistency!("\xff\xff") }.to raise_error(DecodingError)
412
+ end
413
+ end
414
+
415
+ describe '#read_string_map!' do
416
+ let :buffer do
417
+ "\x00\x02\x00\x05hello\x00\x05world\x00\x03foo\x00\x03bar"
418
+ end
419
+
420
+ it 'decodes a string multimap' do
421
+ Decoding.read_string_map!(buffer).should == {'hello' => 'world', 'foo' => 'bar'}
422
+ end
423
+
424
+ it 'decodes an empty string map' do
425
+ Decoding.read_string_map!("\x00\x00").should == {}
426
+ end
427
+
428
+ it 'consumes the bytes' do
429
+ buffer << "\xff"
430
+ Decoding.read_string_map!(buffer)
431
+ buffer.should == "\xff"
432
+ end
433
+
434
+ it 'raises an error when there are not enough bytes in the buffer' do
435
+ expect { Decoding.read_string_map!(buffer.slice(0, 20)) }.to raise_error(DecodingError)
436
+ end
437
+ end
438
+
439
+ describe '#read_string_multimap!' do
440
+ let :buffer do
441
+ "\x00\x02\x00\x0bCQL_VERSION\x00\x01\x00\x053.0.0\x00\x0bCOMPRESSION\x00\x02\x00\x06snappy\x00\x04gzip"
442
+ end
443
+
444
+ it 'decodes a string multimap' do
445
+ Decoding.read_string_multimap!(buffer).should == {'CQL_VERSION' => ['3.0.0'], 'COMPRESSION' => ['snappy', 'gzip']}
446
+ end
447
+
448
+ it 'decodes an empty string multimap' do
449
+ Decoding.read_string_multimap!("\x00\x00").should == {}
450
+ end
451
+
452
+ it 'consumes the bytes' do
453
+ buffer << "\xff"
454
+ Decoding.read_string_multimap!(buffer)
455
+ buffer.should == "\xff"
456
+ end
457
+
458
+ it 'raises an error when there are not enough bytes in the buffer' do
459
+ expect { Decoding.read_string_multimap!(buffer.slice(0, 40)) }.to raise_error(DecodingError)
460
+ end
461
+ end
462
+ end
463
+ end
464
+ end