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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -2
  3. data/lib/cql.rb +8 -3
  4. data/lib/cql/client.rb +21 -356
  5. data/lib/cql/client/authenticators.rb +70 -0
  6. data/lib/cql/client/batch.rb +54 -0
  7. data/lib/cql/client/{asynchronous_client.rb → client.rb} +241 -6
  8. data/lib/cql/client/connector.rb +3 -2
  9. data/lib/cql/client/{asynchronous_prepared_statement.rb → prepared_statement.rb} +103 -0
  10. data/lib/cql/protocol.rb +1 -2
  11. data/lib/cql/protocol/cql_byte_buffer.rb +285 -0
  12. data/lib/cql/protocol/cql_protocol_handler.rb +3 -3
  13. data/lib/cql/protocol/frame_decoder.rb +3 -3
  14. data/lib/cql/protocol/frame_encoder.rb +2 -2
  15. data/lib/cql/protocol/request.rb +0 -2
  16. data/lib/cql/protocol/requests/auth_response_request.rb +2 -2
  17. data/lib/cql/protocol/requests/batch_request.rb +10 -10
  18. data/lib/cql/protocol/requests/credentials_request.rb +2 -2
  19. data/lib/cql/protocol/requests/execute_request.rb +13 -13
  20. data/lib/cql/protocol/requests/options_request.rb +2 -2
  21. data/lib/cql/protocol/requests/prepare_request.rb +2 -2
  22. data/lib/cql/protocol/requests/query_request.rb +13 -13
  23. data/lib/cql/protocol/requests/register_request.rb +2 -2
  24. data/lib/cql/protocol/requests/startup_request.rb +2 -2
  25. data/lib/cql/protocol/response.rb +2 -4
  26. data/lib/cql/protocol/responses/auth_challenge_response.rb +2 -2
  27. data/lib/cql/protocol/responses/auth_success_response.rb +2 -2
  28. data/lib/cql/protocol/responses/authenticate_response.rb +2 -2
  29. data/lib/cql/protocol/responses/detailed_error_response.rb +15 -15
  30. data/lib/cql/protocol/responses/error_response.rb +4 -4
  31. data/lib/cql/protocol/responses/event_response.rb +3 -3
  32. data/lib/cql/protocol/responses/prepared_result_response.rb +4 -4
  33. data/lib/cql/protocol/responses/raw_rows_result_response.rb +1 -1
  34. data/lib/cql/protocol/responses/ready_response.rb +1 -1
  35. data/lib/cql/protocol/responses/result_response.rb +3 -3
  36. data/lib/cql/protocol/responses/rows_result_response.rb +22 -22
  37. data/lib/cql/protocol/responses/schema_change_event_response.rb +2 -2
  38. data/lib/cql/protocol/responses/schema_change_result_response.rb +2 -2
  39. data/lib/cql/protocol/responses/set_keyspace_result_response.rb +2 -2
  40. data/lib/cql/protocol/responses/status_change_event_response.rb +2 -2
  41. data/lib/cql/protocol/responses/supported_response.rb +2 -2
  42. data/lib/cql/protocol/responses/void_result_response.rb +1 -1
  43. data/lib/cql/protocol/type_converter.rb +78 -81
  44. data/lib/cql/time_uuid.rb +6 -0
  45. data/lib/cql/uuid.rb +2 -1
  46. data/lib/cql/version.rb +1 -1
  47. data/spec/cql/client/batch_spec.rb +8 -8
  48. data/spec/cql/client/{asynchronous_client_spec.rb → client_spec.rb} +162 -0
  49. data/spec/cql/client/connector_spec.rb +13 -3
  50. data/spec/cql/client/{asynchronous_prepared_statement_spec.rb → prepared_statement_spec.rb} +148 -1
  51. data/spec/cql/client/request_runner_spec.rb +2 -2
  52. data/spec/cql/protocol/cql_byte_buffer_spec.rb +895 -0
  53. data/spec/cql/protocol/cql_protocol_handler_spec.rb +1 -1
  54. data/spec/cql/protocol/frame_decoder_spec.rb +14 -14
  55. data/spec/cql/protocol/frame_encoder_spec.rb +7 -7
  56. data/spec/cql/protocol/requests/auth_response_request_spec.rb +4 -4
  57. data/spec/cql/protocol/requests/batch_request_spec.rb +21 -21
  58. data/spec/cql/protocol/requests/credentials_request_spec.rb +2 -2
  59. data/spec/cql/protocol/requests/execute_request_spec.rb +13 -13
  60. data/spec/cql/protocol/requests/options_request_spec.rb +1 -1
  61. data/spec/cql/protocol/requests/prepare_request_spec.rb +2 -2
  62. data/spec/cql/protocol/requests/query_request_spec.rb +13 -13
  63. data/spec/cql/protocol/requests/register_request_spec.rb +2 -2
  64. data/spec/cql/protocol/requests/startup_request_spec.rb +4 -4
  65. data/spec/cql/protocol/responses/auth_challenge_response_spec.rb +5 -5
  66. data/spec/cql/protocol/responses/auth_success_response_spec.rb +5 -5
  67. data/spec/cql/protocol/responses/authenticate_response_spec.rb +3 -3
  68. data/spec/cql/protocol/responses/detailed_error_response_spec.rb +15 -15
  69. data/spec/cql/protocol/responses/error_response_spec.rb +5 -5
  70. data/spec/cql/protocol/responses/event_response_spec.rb +8 -8
  71. data/spec/cql/protocol/responses/prepared_result_response_spec.rb +7 -7
  72. data/spec/cql/protocol/responses/raw_rows_result_response_spec.rb +1 -1
  73. data/spec/cql/protocol/responses/ready_response_spec.rb +2 -2
  74. data/spec/cql/protocol/responses/result_response_spec.rb +16 -16
  75. data/spec/cql/protocol/responses/rows_result_response_spec.rb +21 -21
  76. data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +3 -3
  77. data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +3 -3
  78. data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +2 -2
  79. data/spec/cql/protocol/responses/status_change_event_response_spec.rb +3 -3
  80. data/spec/cql/protocol/responses/supported_response_spec.rb +3 -3
  81. data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +3 -3
  82. data/spec/cql/protocol/responses/void_result_response_spec.rb +2 -2
  83. data/spec/cql/protocol/type_converter_spec.rb +25 -13
  84. data/spec/cql/time_uuid_spec.rb +17 -4
  85. data/spec/cql/uuid_spec.rb +5 -1
  86. data/spec/integration/protocol_spec.rb +48 -42
  87. data/spec/spec_helper.rb +0 -1
  88. metadata +27 -39
  89. data/lib/cql/byte_buffer.rb +0 -177
  90. data/lib/cql/client/synchronous_client.rb +0 -79
  91. data/lib/cql/client/synchronous_prepared_statement.rb +0 -63
  92. data/lib/cql/future.rb +0 -515
  93. data/lib/cql/io.rb +0 -15
  94. data/lib/cql/io/connection.rb +0 -220
  95. data/lib/cql/io/io_reactor.rb +0 -349
  96. data/lib/cql/protocol/decoding.rb +0 -187
  97. data/lib/cql/protocol/encoding.rb +0 -114
  98. data/spec/cql/byte_buffer_spec.rb +0 -337
  99. data/spec/cql/client/synchronous_client_spec.rb +0 -170
  100. data/spec/cql/client/synchronous_prepared_statement_spec.rb +0 -155
  101. data/spec/cql/future_spec.rb +0 -737
  102. data/spec/cql/io/connection_spec.rb +0 -484
  103. data/spec/cql/io/io_reactor_spec.rb +0 -402
  104. data/spec/cql/protocol/decoding_spec.rb +0 -547
  105. data/spec/cql/protocol/encoding_spec.rb +0 -386
  106. data/spec/integration/io_spec.rb +0 -283
  107. data/spec/support/fake_server.rb +0 -106
@@ -1,386 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
-
6
- module Cql
7
- module Protocol
8
- describe Encoding do
9
- let :buffer do
10
- ByteBuffer.new
11
- end
12
-
13
- describe '#write_int' do
14
- it 'encodes an int' do
15
- Encoding.write_int(buffer, 2323234234)
16
- buffer.should eql_bytes("\x8a\x79\xbd\xba")
17
- end
18
-
19
- it 'appends to the buffer' do
20
- buffer << "\xab"
21
- Encoding.write_int(buffer, 10)
22
- buffer.should eql_bytes("\xab\x00\x00\x00\x0a")
23
- end
24
-
25
- it 'returns the buffer' do
26
- result = Encoding.write_int(buffer, 2323234234)
27
- result.should equal(buffer)
28
- end
29
- end
30
-
31
- describe '#write_short' do
32
- it 'encodes a short' do
33
- Encoding.write_short(buffer, 0xabcd)
34
- buffer.should eql_bytes("\xab\xcd")
35
- end
36
-
37
- it 'appends to the buffer' do
38
- buffer << "\xab"
39
- Encoding.write_short(buffer, 10)
40
- buffer.should eql_bytes("\xab\x00\x0a")
41
- end
42
-
43
- it 'returns the buffer' do
44
- result = Encoding.write_short(buffer, 42)
45
- result.should equal(buffer)
46
- end
47
- end
48
-
49
- describe '#write_string' do
50
- it 'encodes a string' do
51
- Encoding.write_string(buffer, 'hello')
52
- buffer.should eql_bytes("\x00\x05hello")
53
- end
54
-
55
- it 'encodes a string with multibyte characters' do
56
- buffer << "\xff"
57
- str = 'I love π'
58
- Encoding.write_string(buffer, str)
59
- buffer.should eql_bytes("\xff\x00\x09I love π")
60
- end
61
-
62
- it 'encodes an empty string' do
63
- Encoding.write_string(buffer, '')
64
- buffer.should eql_bytes("\x00\x00")
65
- end
66
-
67
- it 'encodes a non-string' do
68
- Encoding.write_string(buffer, 42)
69
- buffer.should eql_bytes("\x00\x0242")
70
- end
71
-
72
- it 'appends to the buffer' do
73
- buffer << "\xab"
74
- Encoding.write_string(buffer, 'foo')
75
- buffer.should eql_bytes("\xab\x00\x03foo")
76
- end
77
-
78
- it 'returns the buffer' do
79
- result = Encoding.write_string(buffer, 'hello')
80
- result.should equal(buffer)
81
- end
82
- end
83
-
84
- describe '#write_long_string' do
85
- it 'encodes a string' do
86
- Encoding.write_long_string(buffer, 'hello world ' * 100_000)
87
- buffer.read(45).should eql_bytes("\x00\x12\x4f\x80hello world hello world hello world hello")
88
- end
89
-
90
- it 'encodes a string with multibyte characters' do
91
- buffer << "\xff"
92
- str = 'I love π'
93
- Encoding.write_long_string(buffer, str)
94
- buffer.should eql_bytes("\xff\x00\x00\x00\x09I love π")
95
- end
96
-
97
- it 'encodes an empty string' do
98
- Encoding.write_long_string(buffer, '')
99
- buffer.should eql_bytes("\x00\x00\x00\x00")
100
- end
101
-
102
- it 'appends to the buffer' do
103
- buffer << "\xab"
104
- Encoding.write_long_string(buffer, 'foo')
105
- buffer.should eql_bytes("\xab\x00\x00\x00\x03foo")
106
- end
107
-
108
- it 'returns the buffer' do
109
- result = Encoding.write_long_string(buffer, 'hello')
110
- result.should equal(buffer)
111
- end
112
- end
113
-
114
- describe '#write_uuid' do
115
- let :uuid do
116
- Uuid.new('a4a70900-24e1-11df-8924-001ff3591711')
117
- end
118
-
119
- it 'encodes an UUID' do
120
- Encoding.write_uuid(buffer, uuid)
121
- buffer.should eql_bytes("\xA4\xA7\t\x00$\xE1\x11\xDF\x89$\x00\x1F\xF3Y\x17\x11")
122
- end
123
-
124
- it 'encodes a UUID as 16 bytes' do
125
- Encoding.write_uuid(buffer, Uuid.new('00000000-24e1-11df-8924-001ff3591711'))
126
- buffer.size.should eql(16)
127
- end
128
-
129
- it 'appends to the buffer' do
130
- buffer << 'FOO'
131
- Encoding.write_uuid(buffer, uuid)
132
- buffer.read(3).should eql_bytes('FOO')
133
- end
134
-
135
- it 'returns the buffer' do
136
- result = Encoding.write_uuid(buffer, uuid)
137
- result.should equal(buffer)
138
- end
139
- end
140
-
141
- describe '#write_string_list' do
142
- it 'encodes a string list' do
143
- Encoding.write_string_list(buffer, %w[foo bar hello world])
144
- buffer.should eql_bytes("\x00\x04\x00\x03foo\x00\x03bar\x00\x05hello\x00\x05world")
145
- end
146
-
147
- it 'encodes a string with multibyte characters' do
148
- buffer << "\xff"
149
- str = %w[I love π]
150
- Encoding.write_string_list(buffer, str)
151
- buffer.should eql_bytes("\xff\x00\x03\x00\x01I\x00\x04love\x00\x02π")
152
- end
153
-
154
- it 'encodes an empty string list' do
155
- Encoding.write_string_list(buffer, [])
156
- buffer.should eql_bytes("\x00\x00")
157
- end
158
-
159
- it 'appends to the buffer' do
160
- buffer << "\xab"
161
- Encoding.write_string_list(buffer, %w[foo bar])
162
- buffer.should eql_bytes("\xab\x00\x02\x00\x03foo\x00\x03bar")
163
- end
164
-
165
- it 'returns the buffer' do
166
- result = Encoding.write_string_list(buffer, %w[foo])
167
- result.should equal(buffer)
168
- end
169
- end
170
-
171
- describe '#write_bytes' do
172
- it 'encodes a byte array' do
173
- Encoding.write_bytes(buffer, "\xaa" * 2000)
174
- buffer.should eql_bytes("\x00\x00\x07\xd0" << ("\xaa" * 2000))
175
- end
176
-
177
- it 'encodes a string with multibyte characters' do
178
- buffer << "\xff"
179
- str = 'I love π'
180
- Encoding.write_bytes(buffer, str)
181
- buffer.should eql_bytes("\xff\x00\x00\x00\x09I love π")
182
- end
183
-
184
- it 'encodes nil' do
185
- Encoding.write_bytes(buffer, nil)
186
- buffer.should eql_bytes("\xff\xff\xff\xff")
187
- end
188
-
189
- it 'appends to the buffer' do
190
- buffer << "\xab"
191
- Encoding.write_bytes(buffer, "\xf0\x0b\xbar")
192
- buffer.should eql_bytes("\xab\x00\x00\x00\x04\xf0\x0b\xbar")
193
- end
194
-
195
- it 'returns the buffer' do
196
- result = Encoding.write_bytes(buffer, "\xab")
197
- result.should equal(buffer)
198
- end
199
- end
200
-
201
- describe '#write_short_bytes' do
202
- it 'encodes a byte array' do
203
- Encoding.write_short_bytes(buffer, "\xaa\xbb\xcc")
204
- buffer.should eql_bytes("\x00\x03\xaa\xbb\xcc")
205
- end
206
-
207
- it 'encodes a string with multibyte characters' do
208
- buffer << "\xff"
209
- str = 'I love π'
210
- Encoding.write_short_bytes(buffer, str)
211
- buffer.should eql_bytes("\xff\x00\x09I love π")
212
- end
213
-
214
- it 'encodes nil' do
215
- Encoding.write_short_bytes(buffer, nil)
216
- buffer.should eql_bytes("\xff\xff")
217
- end
218
-
219
- it 'appends to the buffer' do
220
- buffer << "\xab"
221
- Encoding.write_short_bytes(buffer, "\xf0\x0b\xbar")
222
- buffer.should eql_bytes("\xab\x00\x04\xf0\x0b\xbar")
223
- end
224
-
225
- it 'returns the buffer' do
226
- result = Encoding.write_short_bytes(buffer, "\xab")
227
- result.should equal(buffer)
228
- end
229
- end
230
-
231
- describe '#write_consistency' do
232
- {
233
- :any => "\x00\x00",
234
- :one => "\x00\x01",
235
- :two => "\x00\x02",
236
- :three => "\x00\x03",
237
- :quorum => "\x00\x04",
238
- :all => "\x00\x05",
239
- :local_quorum => "\x00\x06",
240
- :each_quorum => "\x00\x07",
241
- :serial => "\x00\x08",
242
- :local_serial => "\x00\x09",
243
- :local_one => "\x00\x0a",
244
- }.each do |consistency, expected_encoding|
245
- it "encodes #{consistency}" do
246
- Encoding.write_consistency(buffer, consistency)
247
- buffer.should eql_bytes(expected_encoding)
248
- end
249
- end
250
-
251
- it 'raises an exception for an unknown consistency' do
252
- expect { Encoding.write_consistency(buffer, :foo) }.to raise_error(EncodingError)
253
- end
254
-
255
- it 'appends to the buffer' do
256
- buffer << "\xab"
257
- Encoding.write_consistency(buffer, :one)
258
- buffer.should eql_bytes("\xab\x00\x01")
259
- end
260
-
261
- it 'returns the buffer' do
262
- result = Encoding.write_consistency(buffer, :quorum)
263
- result.should equal(buffer)
264
- end
265
- end
266
-
267
- describe '#write_string_map' do
268
- it 'encodes a string map' do
269
- Encoding.write_string_map(buffer, 'HELLO' => 'world', 'foo' => 'bar')
270
- buffer.should eql_bytes("\x00\x02\x00\x05HELLO\x00\x05world\x00\x03foo\x00\x03bar")
271
- end
272
-
273
- it 'encodes an empty map' do
274
- Encoding.write_string_map(buffer, {})
275
- buffer.should eql_bytes("\x00\x00")
276
- end
277
-
278
- it 'appends to the buffer' do
279
- buffer << "\xab"
280
- Encoding.write_string_map(buffer, 'foo' => 'bar')
281
- buffer.should eql_bytes("\xab\x00\x01\x00\x03foo\x00\x03bar")
282
- end
283
-
284
- it 'returns the buffer' do
285
- result = Encoding.write_string_map(buffer, 'HELLO' => 'world')
286
- result.should equal(buffer)
287
- end
288
- end
289
-
290
- describe '#write_long' do
291
- it 'encodes a long' do
292
- Encoding.write_long(buffer, 0x0123456789)
293
- buffer.should eql_bytes("\x00\x00\x00\x01\x23\x45\x67\x89")
294
- end
295
-
296
- it 'appends to the buffer' do
297
- buffer << "\x99"
298
- Encoding.write_long(buffer, 0x0123456789)
299
- buffer.should eql_bytes("\x99\x00\x00\x00\x01\x23\x45\x67\x89")
300
- end
301
-
302
- it 'returns the buffer' do
303
- result = Encoding.write_long(buffer, 1)
304
- result.should equal(buffer)
305
- end
306
- end
307
-
308
- describe '#write_varint' do
309
- it 'encodes a variable length integer' do
310
- Encoding.write_varint(buffer, 1231312312331283012830129382342342412123)
311
- buffer.should eql_bytes("\x03\x9EV \x15\f\x03\x9DK\x18\xCDI\\$?\a[")
312
- end
313
-
314
- it 'encodes a negative variable length integer' do
315
- Encoding.write_varint(buffer, -234234234234)
316
- buffer.should eql_bytes("\xC9v\x8D:\x86")
317
- end
318
-
319
- it 'appends to the buffer' do
320
- buffer << "\x99"
321
- Encoding.write_varint(buffer, -234234234234)
322
- buffer.should eql_bytes("\x99\xC9v\x8D:\x86")
323
- end
324
-
325
- it 'returns the buffer' do
326
- result = Encoding.write_varint(buffer, -234234234234)
327
- result.should equal(buffer)
328
- end
329
- end
330
-
331
- describe '#write_decimal' do
332
- it 'encodes a BigDecimal as a decimal' do
333
- Encoding.write_decimal(buffer, BigDecimal.new('1042342234234.123423435647768234'))
334
- buffer.should eql_bytes("\x00\x00\x00\x12\r'\xFDI\xAD\x80f\x11g\xDCfV\xAA")
335
- end
336
-
337
- it 'appends to the buffer' do
338
- buffer << "\x99"
339
- Encoding.write_decimal(buffer, BigDecimal.new('1042342234234.123423435647768234'))
340
- buffer.read(1).should eql_bytes("\x99")
341
- end
342
-
343
- it 'returns the buffer' do
344
- result = Encoding.write_decimal(buffer, BigDecimal.new('3.14'))
345
- result.should equal(buffer)
346
- end
347
- end
348
-
349
- describe '#write_double' do
350
- it 'encodes a double' do
351
- Encoding.write_double(buffer, 10000.123123123)
352
- buffer.should eql_bytes("@\xC3\x88\x0F\xC2\x7F\x9DU")
353
- end
354
-
355
- it 'appends to the buffer' do
356
- buffer << 'BEFORE'
357
- Encoding.write_double(buffer, 10000.123123123)
358
- buffer.read(6).should eql_bytes('BEFORE')
359
- end
360
-
361
- it 'returns the buffer' do
362
- result = Encoding.write_double(buffer, 10000.123123123)
363
- result.should equal(buffer)
364
- end
365
- end
366
-
367
- describe '#write_float' do
368
- it 'encodes a float' do
369
- Encoding.write_float(buffer, 12.13)
370
- buffer.should eql_bytes("AB\x14{")
371
- end
372
-
373
- it 'appends to the buffer' do
374
- buffer << 'BEFORE'
375
- Encoding.write_float(buffer, 12.13)
376
- buffer.read(6).should eql_bytes('BEFORE')
377
- end
378
-
379
- it 'returns the buffer' do
380
- result = Encoding.write_float(buffer, 12.13)
381
- result.should equal(buffer)
382
- end
383
- end
384
- end
385
- end
386
- end
@@ -1,283 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
-
6
- describe 'An IO reactor' do
7
- context 'with a generic server' do
8
- let :io_reactor do
9
- Cql::Io::IoReactor.new(IoSpec::TestConnection)
10
- end
11
-
12
- let :fake_server do
13
- FakeServer.new
14
- end
15
-
16
- before do
17
- fake_server.start!
18
- io_reactor.start
19
- end
20
-
21
- after do
22
- io_reactor.stop
23
- fake_server.stop!
24
- end
25
-
26
- it 'connects to the server' do
27
- io_reactor.connect(ENV['CASSANDRA_HOST'], fake_server.port, 1)
28
- fake_server.await_connects!(1)
29
- end
30
-
31
- it 'receives data' do
32
- protocol_handler = io_reactor.connect(ENV['CASSANDRA_HOST'], fake_server.port, 1).value
33
- fake_server.await_connects!(1)
34
- fake_server.broadcast!('hello world')
35
- await { protocol_handler.data.bytesize > 0 }
36
- protocol_handler.data.should == 'hello world'
37
- end
38
-
39
- it 'receives data on multiple connections' do
40
- protocol_handlers = Array.new(10) { io_reactor.connect(ENV['CASSANDRA_HOST'], fake_server.port, 1).value }
41
- fake_server.await_connects!(10)
42
- fake_server.broadcast!('hello world')
43
- await { protocol_handlers.all? { |c| c.data.bytesize > 0 } }
44
- protocol_handlers.sample.data.should == 'hello world'
45
- end
46
- end
47
-
48
- context 'when talking to Redis' do
49
- let :io_reactor do
50
- Cql::Io::IoReactor.new(IoSpec::RedisProtocolHandler)
51
- end
52
-
53
- let :protocol_handler do
54
- begin
55
- io_reactor.connect(ENV['CASSANDRA_HOST'], 6379, 1).value
56
- rescue Cql::Io::ConnectionError
57
- nil
58
- end
59
- end
60
-
61
- before do
62
- io_reactor.start.value
63
- end
64
-
65
- after do
66
- io_reactor.stop.value
67
- end
68
-
69
- it 'can set a value' do
70
- pending('Redis not running', unless: protocol_handler)
71
- response = protocol_handler.send_request('SET', 'foo', 'bar').value
72
- response.should == 'OK'
73
- end
74
-
75
- it 'can get a value' do
76
- pending('Redis not running', unless: protocol_handler)
77
- f = protocol_handler.send_request('SET', 'foo', 'bar').flat_map do
78
- protocol_handler.send_request('GET', 'foo')
79
- end
80
- f.value.should == 'bar'
81
- end
82
-
83
- it 'can delete values' do
84
- pending('Redis not running', unless: protocol_handler)
85
- f = protocol_handler.send_request('SET', 'hello', 'world').flat_map do
86
- protocol_handler.send_request('DEL', 'hello')
87
- end
88
- f.value.should == 1
89
- end
90
-
91
- it 'handles nil values' do
92
- pending('Redis not running', unless: protocol_handler)
93
- f = protocol_handler.send_request('DEL', 'hello').flat_map do
94
- protocol_handler.send_request('GET', 'hello')
95
- end
96
- f.value.should be_nil
97
- end
98
-
99
- it 'handles errors' do
100
- pending('Redis not running', unless: protocol_handler)
101
- f = protocol_handler.send_request('SET', 'foo')
102
- expect { f.value }.to raise_error("ERR wrong number of arguments for 'set' command")
103
- end
104
-
105
- it 'handles replies with multiple elements' do
106
- pending('Redis not running', unless: protocol_handler)
107
- f = protocol_handler.send_request('DEL', 'stuff')
108
- f.value
109
- f = protocol_handler.send_request('RPUSH', 'stuff', 'hello', 'world')
110
- f.value.should == 2
111
- f = protocol_handler.send_request('LRANGE', 'stuff', 0, 2)
112
- f.value.should == ['hello', 'world']
113
- end
114
-
115
- it 'handles nil values when reading multiple elements' do
116
- pending('Redis not running', unless: protocol_handler)
117
- protocol_handler.send_request('DEL', 'things')
118
- protocol_handler.send_request('HSET', 'things', 'hello', 'world')
119
- f = protocol_handler.send_request('HMGET', 'things', 'hello', 'foo')
120
- f.value.should == ['world', nil]
121
- end
122
- end
123
- end
124
-
125
- module IoSpec
126
- class TestConnection
127
- def initialize(connection, scheduler)
128
- @connection = connection
129
- @connection.on_data(&method(:receive_data))
130
- @lock = Mutex.new
131
- @data = Cql::ByteBuffer.new
132
- end
133
-
134
- def data
135
- @lock.synchronize { @data.to_s }
136
- end
137
-
138
- private
139
-
140
- def receive_data(new_data)
141
- @lock.synchronize { @data << new_data }
142
- end
143
- end
144
-
145
- class LineProtocolHandler
146
- def initialize(connection, scheduler)
147
- @connection = connection
148
- @connection.on_data(&method(:process_data))
149
- @lock = Mutex.new
150
- @buffer = ''
151
- @requests = []
152
- end
153
-
154
- def on_line(&listener)
155
- @line_listener = listener
156
- end
157
-
158
- def write(command_string)
159
- @connection.write(command_string)
160
- end
161
-
162
- def process_data(new_data)
163
- lines = []
164
- @lock.synchronize do
165
- @buffer << new_data
166
- while newline_index = @buffer.index("\r\n")
167
- line = @buffer.slice!(0, newline_index + 2)
168
- line.chomp!
169
- lines << line
170
- end
171
- end
172
- lines.each do |line|
173
- @line_listener.call(line) if @line_listener
174
- end
175
- end
176
- end
177
-
178
- class RedisProtocolHandler
179
- def initialize(connection, scheduler)
180
- @line_protocol = LineProtocolHandler.new(connection, scheduler)
181
- @line_protocol.on_line(&method(:handle_line))
182
- @lock = Mutex.new
183
- @responses = []
184
- @state = BaseState.new(method(:handle_response))
185
- end
186
-
187
- def send_request(*args)
188
- promise = Cql::Promise.new
189
- @lock.synchronize do
190
- @responses << promise
191
- end
192
- request = "*#{args.size}\r\n"
193
- args.each do |arg|
194
- arg_str = arg.to_s
195
- request << "$#{arg_str.bytesize}\r\n#{arg_str}\r\n"
196
- end
197
- @line_protocol.write(request)
198
- promise.future
199
- end
200
-
201
- def handle_response(result, error=false)
202
- promise = @lock.synchronize do
203
- @responses.shift
204
- end
205
- if error
206
- promise.fail(StandardError.new(result))
207
- else
208
- promise.fulfill(result)
209
- end
210
- end
211
-
212
- def handle_line(line)
213
- @state = @state.handle_line(line)
214
- end
215
-
216
- class State
217
- def initialize(result_handler)
218
- @result_handler = result_handler
219
- end
220
-
221
- def complete!(result)
222
- @result_handler.call(result)
223
- end
224
-
225
- def fail!(message)
226
- @result_handler.call(message, true)
227
- end
228
- end
229
-
230
- class BulkState < State
231
- def handle_line(line)
232
- complete!(line)
233
- BaseState.new(@result_handler)
234
- end
235
- end
236
-
237
- class MultiBulkState < State
238
- def initialize(result_handler, expected_elements)
239
- super(result_handler)
240
- @expected_elements = expected_elements
241
- @elements = []
242
- end
243
-
244
- def handle_line(line)
245
- if line.start_with?('$')
246
- line.slice!(0, 1)
247
- if line.to_i == -1
248
- @elements << nil
249
- end
250
- else
251
- @elements << line
252
- end
253
- if @elements.size == @expected_elements
254
- complete!(@elements)
255
- BaseState.new(@result_handler)
256
- else
257
- self
258
- end
259
- end
260
- end
261
-
262
- class BaseState < State
263
- def handle_line(line)
264
- next_state = self
265
- first_char = line.slice!(0, 1)
266
- case first_char
267
- when '+' then complete!(line)
268
- when ':' then complete!(line.to_i)
269
- when '-' then fail!(line)
270
- when '$'
271
- if line.to_i == -1
272
- complete!(nil)
273
- else
274
- next_state = BulkState.new(@result_handler)
275
- end
276
- when '*'
277
- next_state = MultiBulkState.new(@result_handler, line.to_i)
278
- end
279
- next_state
280
- end
281
- end
282
- end
283
- end