cql-rb 2.0.0.pre0 → 2.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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