cql-rb 1.2.2 → 2.0.0.pre0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +4 -0
  3. data/README.md +139 -17
  4. data/lib/cql/client.rb +237 -8
  5. data/lib/cql/client/asynchronous_client.rb +138 -54
  6. data/lib/cql/client/asynchronous_prepared_statement.rb +41 -6
  7. data/lib/cql/client/authenticators.rb +46 -0
  8. data/lib/cql/client/batch.rb +115 -0
  9. data/lib/cql/client/connector.rb +255 -0
  10. data/lib/cql/client/execute_options_decoder.rb +25 -9
  11. data/lib/cql/client/keyspace_changer.rb +5 -5
  12. data/lib/cql/client/peer_discovery.rb +33 -0
  13. data/lib/cql/client/query_result.rb +124 -1
  14. data/lib/cql/client/request_runner.rb +4 -2
  15. data/lib/cql/client/synchronous_client.rb +14 -2
  16. data/lib/cql/client/synchronous_prepared_statement.rb +19 -1
  17. data/lib/cql/future.rb +97 -50
  18. data/lib/cql/io/connection.rb +0 -1
  19. data/lib/cql/io/io_reactor.rb +1 -1
  20. data/lib/cql/protocol.rb +8 -1
  21. data/lib/cql/protocol/cql_protocol_handler.rb +2 -2
  22. data/lib/cql/protocol/decoding.rb +10 -15
  23. data/lib/cql/protocol/frame_decoder.rb +2 -1
  24. data/lib/cql/protocol/frame_encoder.rb +5 -4
  25. data/lib/cql/protocol/requests/auth_response_request.rb +31 -0
  26. data/lib/cql/protocol/requests/batch_request.rb +59 -0
  27. data/lib/cql/protocol/requests/credentials_request.rb +1 -1
  28. data/lib/cql/protocol/requests/execute_request.rb +45 -17
  29. data/lib/cql/protocol/requests/options_request.rb +1 -1
  30. data/lib/cql/protocol/requests/prepare_request.rb +1 -1
  31. data/lib/cql/protocol/requests/query_request.rb +97 -5
  32. data/lib/cql/protocol/requests/register_request.rb +1 -1
  33. data/lib/cql/protocol/requests/startup_request.rb +4 -4
  34. data/lib/cql/protocol/response.rb +2 -2
  35. data/lib/cql/protocol/responses/auth_challenge_response.rb +25 -0
  36. data/lib/cql/protocol/responses/auth_success_response.rb +25 -0
  37. data/lib/cql/protocol/responses/authenticate_response.rb +1 -1
  38. data/lib/cql/protocol/responses/detailed_error_response.rb +1 -1
  39. data/lib/cql/protocol/responses/error_response.rb +3 -2
  40. data/lib/cql/protocol/responses/event_response.rb +3 -2
  41. data/lib/cql/protocol/responses/prepared_result_response.rb +10 -6
  42. data/lib/cql/protocol/responses/raw_rows_result_response.rb +27 -0
  43. data/lib/cql/protocol/responses/ready_response.rb +1 -1
  44. data/lib/cql/protocol/responses/result_response.rb +2 -2
  45. data/lib/cql/protocol/responses/rows_result_response.rb +43 -23
  46. data/lib/cql/protocol/responses/schema_change_event_response.rb +1 -1
  47. data/lib/cql/protocol/responses/schema_change_result_response.rb +1 -1
  48. data/lib/cql/protocol/responses/set_keyspace_result_response.rb +1 -1
  49. data/lib/cql/protocol/responses/status_change_event_response.rb +1 -1
  50. data/lib/cql/protocol/responses/supported_response.rb +1 -1
  51. data/lib/cql/protocol/responses/void_result_response.rb +1 -1
  52. data/lib/cql/protocol/type_converter.rb +2 -2
  53. data/lib/cql/uuid.rb +2 -2
  54. data/lib/cql/version.rb +1 -1
  55. data/spec/cql/client/asynchronous_client_spec.rb +493 -50
  56. data/spec/cql/client/asynchronous_prepared_statement_spec.rb +193 -11
  57. data/spec/cql/client/authenticators_spec.rb +56 -0
  58. data/spec/cql/client/batch_spec.rb +277 -0
  59. data/spec/cql/client/connector_spec.rb +606 -0
  60. data/spec/cql/client/execute_options_decoder_spec.rb +95 -0
  61. data/spec/cql/client/keyspace_changer_spec.rb +8 -8
  62. data/spec/cql/client/peer_discovery_spec.rb +92 -0
  63. data/spec/cql/client/query_result_spec.rb +352 -0
  64. data/spec/cql/client/request_runner_spec.rb +31 -5
  65. data/spec/cql/client/synchronous_client_spec.rb +44 -1
  66. data/spec/cql/client/synchronous_prepared_statement_spec.rb +63 -1
  67. data/spec/cql/future_spec.rb +50 -2
  68. data/spec/cql/protocol/cql_protocol_handler_spec.rb +16 -5
  69. data/spec/cql/protocol/decoding_spec.rb +16 -6
  70. data/spec/cql/protocol/encoding_spec.rb +3 -1
  71. data/spec/cql/protocol/frame_encoder_spec.rb +99 -50
  72. data/spec/cql/protocol/requests/auth_response_request_spec.rb +62 -0
  73. data/spec/cql/protocol/requests/batch_request_spec.rb +155 -0
  74. data/spec/cql/protocol/requests/credentials_request_spec.rb +1 -1
  75. data/spec/cql/protocol/requests/execute_request_spec.rb +184 -71
  76. data/spec/cql/protocol/requests/options_request_spec.rb +1 -1
  77. data/spec/cql/protocol/requests/prepare_request_spec.rb +1 -1
  78. data/spec/cql/protocol/requests/query_request_spec.rb +255 -32
  79. data/spec/cql/protocol/requests/register_request_spec.rb +1 -1
  80. data/spec/cql/protocol/requests/startup_request_spec.rb +12 -6
  81. data/spec/cql/protocol/responses/auth_challenge_response_spec.rb +31 -0
  82. data/spec/cql/protocol/responses/auth_success_response_spec.rb +31 -0
  83. data/spec/cql/protocol/responses/authenticate_response_spec.rb +2 -1
  84. data/spec/cql/protocol/responses/detailed_error_response_spec.rb +14 -7
  85. data/spec/cql/protocol/responses/error_response_spec.rb +4 -2
  86. data/spec/cql/protocol/responses/event_response_spec.rb +7 -4
  87. data/spec/cql/protocol/responses/prepared_result_response_spec.rb +89 -34
  88. data/spec/cql/protocol/responses/raw_rows_result_response_spec.rb +66 -0
  89. data/spec/cql/protocol/responses/ready_response_spec.rb +1 -1
  90. data/spec/cql/protocol/responses/result_response_spec.rb +19 -7
  91. data/spec/cql/protocol/responses/rows_result_response_spec.rb +56 -11
  92. data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +2 -1
  93. data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +2 -1
  94. data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +1 -1
  95. data/spec/cql/protocol/responses/status_change_event_response_spec.rb +2 -1
  96. data/spec/cql/protocol/responses/supported_response_spec.rb +2 -1
  97. data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +2 -1
  98. data/spec/cql/protocol/responses/void_result_response_spec.rb +1 -1
  99. data/spec/cql/protocol/type_converter_spec.rb +21 -4
  100. data/spec/cql/uuid_spec.rb +10 -3
  101. data/spec/integration/client_spec.rb +251 -28
  102. data/spec/integration/protocol_spec.rb +213 -62
  103. data/spec/integration/regression_spec.rb +4 -1
  104. data/spec/integration/uuid_spec.rb +4 -1
  105. data/spec/support/fake_io_reactor.rb +5 -5
  106. metadata +36 -7
  107. data/lib/cql/client/connection_helper.rb +0 -181
  108. data/spec/cql/client/connection_helper_spec.rb +0 -429
@@ -4,8 +4,12 @@ require 'spec_helper'
4
4
 
5
5
 
6
6
  describe 'Protocol parsing and communication' do
7
+ let :protocol_version do
8
+ 2
9
+ end
10
+
7
11
  let! :io_reactor do
8
- ir = Cql::Io::IoReactor.new(Cql::Protocol::CqlProtocolHandler)
12
+ ir = Cql::Io::IoReactor.new(lambda { |*args| Cql::Protocol::CqlProtocolHandler.new(*args, protocol_version) })
9
13
  ir.start
10
14
  connections << ir.connect(ENV['CASSANDRA_HOST'], 9042, 5).value
11
15
  ir
@@ -26,24 +30,42 @@ describe 'Protocol parsing and communication' do
26
30
  end
27
31
  end
28
32
 
33
+ def authentication_enabled?
34
+ ir = Cql::Io::IoReactor.new(lambda { |*args| Cql::Protocol::CqlProtocolHandler.new(*args, protocol_version) })
35
+ ir.start
36
+ connected = ir.connect(ENV['CASSANDRA_HOST'], 9042, 5)
37
+ started = connected.flat_map do |connection|
38
+ connection.send_request(Cql::Protocol::StartupRequest.new('3.1.0'))
39
+ end
40
+ response = started.value
41
+ required = response.is_a?(Cql::Protocol::AuthenticateResponse)
42
+ ir.stop.value
43
+ required
44
+ end
45
+
46
+
29
47
  def raw_execute_request(request)
30
48
  connection = connections.first
31
49
  connection.send_request(request).value
32
50
  end
33
51
 
34
- def execute_request(request)
52
+ def execute_request(request, auto_authenticate=true)
35
53
  response = raw_execute_request(request)
36
- if response.is_a?(Cql::Protocol::AuthenticateResponse)
54
+ if response.is_a?(Cql::Protocol::AuthenticateResponse) && auto_authenticate
37
55
  unless response.authentication_class == 'org.apache.cassandra.auth.PasswordAuthenticator'
38
56
  raise "Cassandra required an unsupported authenticator: #{response.authentication_class}"
39
57
  end
40
- response = execute_request(Cql::Protocol::CredentialsRequest.new('username' => 'cassandra', 'password' => 'cassandra'))
58
+ if protocol_version == 1
59
+ response = execute_request(Cql::Protocol::CredentialsRequest.new('username' => 'cassandra', 'password' => 'cassandra'))
60
+ else
61
+ response = execute_request(Cql::Protocol::AuthResponseRequest.new("\x00cassandra\x00cassandra"))
62
+ end
41
63
  end
42
64
  response
43
65
  end
44
66
 
45
67
  def query(cql, consistency=:one)
46
- response = execute_request(Cql::Protocol::QueryRequest.new(cql, consistency))
68
+ response = execute_request(Cql::Protocol::QueryRequest.new(cql, nil, nil, consistency))
47
69
  raise response.to_s if response.is_a?(Cql::Protocol::ErrorResponse)
48
70
  response
49
71
  end
@@ -103,60 +125,87 @@ describe 'Protocol parsing and communication' do
103
125
  response.options.should have_key('CQL_VERSION')
104
126
  end
105
127
 
128
+ it 'sends a bad STARTUP and receives ERROR' do
129
+ response = execute_request(Cql::Protocol::StartupRequest.new('9.9.9'))
130
+ response.code.should == 10
131
+ response.message.should include('not supported')
132
+ end
133
+
106
134
  context 'when authentication is not required' do
107
135
  it 'sends STARTUP and receives READY' do
108
- response = execute_request(Cql::Protocol::StartupRequest.new)
109
- response.should be_a(Cql::Protocol::ReadyResponse)
110
- end
111
-
112
- it 'sends a bad STARTUP and receives ERROR' do
113
- response = execute_request(Cql::Protocol::StartupRequest.new('9.9.9'))
114
- response.code.should == 10
115
- response.message.should include('not supported')
136
+ pending('authentication required', if: authentication_enabled?) do
137
+ response = execute_request(Cql::Protocol::StartupRequest.new('3.1.0'), false)
138
+ response.should be_a(Cql::Protocol::ReadyResponse)
139
+ end
116
140
  end
117
141
  end
118
142
 
119
143
  context 'when authentication is required' do
120
- let :authentication_enabled do
121
- ir = Cql::Io::IoReactor.new(Cql::Protocol::CqlProtocolHandler)
122
- ir.start
123
- connected = ir.connect(ENV['CASSANDRA_HOST'], 9042, 5)
124
- started = connected.flat_map do |connection|
125
- connection.send_request(Cql::Protocol::StartupRequest.new)
126
- end
127
- response = started.value
128
- required = response.is_a?(Cql::Protocol::AuthenticateResponse)
129
- ir.stop.value
130
- required
131
- end
144
+ context 'and the protocol version is 1' do
145
+ let :protocol_version do
146
+ 1
147
+ end
132
148
 
133
- it 'sends STARTUP and receives AUTHENTICATE' do
134
- pending('authentication not configured', unless: authentication_enabled) do
135
- response = raw_execute_request(Cql::Protocol::StartupRequest.new)
136
- response.should be_a(Cql::Protocol::AuthenticateResponse)
149
+ it 'sends STARTUP and receives AUTHENTICATE' do
150
+ pending('authentication not configured', unless: authentication_enabled?) do
151
+ response = raw_execute_request(Cql::Protocol::StartupRequest.new('3.1.0'))
152
+ response.should be_a(Cql::Protocol::AuthenticateResponse)
153
+ end
137
154
  end
138
- end
139
155
 
140
- it 'ignores the AUTHENTICATE response and receives ERROR' do
141
- pending('authentication not configured', unless: authentication_enabled) do
142
- raw_execute_request(Cql::Protocol::StartupRequest.new)
143
- response = raw_execute_request(Cql::Protocol::RegisterRequest.new('TOPOLOGY_CHANGE'))
144
- response.code.should == 10
156
+ it 'ignores the AUTHENTICATE response and receives ERROR' do
157
+ pending('authentication not configured', unless: authentication_enabled?) do
158
+ raw_execute_request(Cql::Protocol::StartupRequest.new('3.1.0'))
159
+ response = raw_execute_request(Cql::Protocol::RegisterRequest.new('TOPOLOGY_CHANGE'))
160
+ response.code.should == 10
161
+ end
145
162
  end
146
- end
147
163
 
148
- it 'sends STARTUP followed by CREDENTIALS and receives READY' do
149
- raw_execute_request(Cql::Protocol::StartupRequest.new)
150
- response = raw_execute_request(Cql::Protocol::CredentialsRequest.new('username' => 'cassandra', 'password' => 'cassandra'))
151
- response.should be_a(Cql::Protocol::ReadyResponse)
164
+ it 'sends STARTUP followed by CREDENTIALS and receives READY' do
165
+ raw_execute_request(Cql::Protocol::StartupRequest.new('3.1.0'))
166
+ response = raw_execute_request(Cql::Protocol::CredentialsRequest.new('username' => 'cassandra', 'password' => 'cassandra'))
167
+ response.should be_a(Cql::Protocol::ReadyResponse)
168
+ end
169
+
170
+ it 'sends bad username and password in CREDENTIALS and receives ERROR' do
171
+ pending('authentication not configured', unless: authentication_enabled?) do
172
+ raw_execute_request(Cql::Protocol::StartupRequest.new('3.1.0'))
173
+ response = raw_execute_request(Cql::Protocol::CredentialsRequest.new('username' => 'foo', 'password' => 'bar'))
174
+ response.code.should == 0x100
175
+ end
176
+ end
152
177
  end
153
178
 
154
- it 'sends bad username and password in CREDENTIALS and receives ERROR' do
155
- pending('authentication not configured', unless: authentication_enabled) do
156
- raw_execute_request(Cql::Protocol::StartupRequest.new)
157
- response = raw_execute_request(Cql::Protocol::CredentialsRequest.new('username' => 'foo', 'password' => 'bar'))
158
- response.code.should == 0x100
159
- response.message.should include('Username and/or password are incorrect')
179
+ context 'and the protocol version is 2' do
180
+ it 'sends STARTUP and receives AUTHENTICATE' do
181
+ pending('authentication not configured', unless: authentication_enabled?) do
182
+ response = raw_execute_request(Cql::Protocol::StartupRequest.new('3.1.0'))
183
+ response.should be_a(Cql::Protocol::AuthenticateResponse)
184
+ end
185
+ end
186
+
187
+ it 'ignores the AUTHENTICATE response and receives ERROR' do
188
+ pending('authentication not configured', unless: authentication_enabled?) do
189
+ raw_execute_request(Cql::Protocol::StartupRequest.new('3.1.0'))
190
+ response = raw_execute_request(Cql::Protocol::RegisterRequest.new('TOPOLOGY_CHANGE'))
191
+ response.code.should == 10
192
+ end
193
+ end
194
+
195
+ it 'sends STARTUP followed by AUTH_RESPONSE and receives AUTH_SUCCESS' do
196
+ pending('authentication not configured', unless: authentication_enabled?) do
197
+ raw_execute_request(Cql::Protocol::StartupRequest.new('3.1.0'))
198
+ response = raw_execute_request(Cql::Protocol::AuthResponseRequest.new("\x00cassandra\x00cassandra"))
199
+ response.should be_a(Cql::Protocol::AuthSuccessResponse)
200
+ end
201
+ end
202
+
203
+ it 'sends bad username and password in AUTH_RESPONSE and receives ERROR' do
204
+ pending('authentication not configured', unless: authentication_enabled?) do
205
+ raw_execute_request(Cql::Protocol::StartupRequest.new('3.1.0'))
206
+ response = raw_execute_request(Cql::Protocol::AuthResponseRequest.new("\x00cassandra\x00ardnassac"))
207
+ response.code.should == 0x100
208
+ end
160
209
  end
161
210
  end
162
211
  end
@@ -164,7 +213,7 @@ describe 'Protocol parsing and communication' do
164
213
 
165
214
  context 'when set up' do
166
215
  before do
167
- response = execute_request(Cql::Protocol::StartupRequest.new)
216
+ response = execute_request(Cql::Protocol::StartupRequest.new('3.1.0'))
168
217
  response
169
218
  end
170
219
 
@@ -201,7 +250,7 @@ describe 'Protocol parsing and communication' do
201
250
  end
202
251
 
203
252
  it 'sends a bad CQL string and receives ERROR' do
204
- response = execute_request(Cql::Protocol::QueryRequest.new('HELLO WORLD', :any))
253
+ response = execute_request(Cql::Protocol::QueryRequest.new('HELLO WORLD', nil, nil, :any))
205
254
  response.should be_a(Cql::Protocol::ErrorResponse)
206
255
  end
207
256
 
@@ -320,6 +369,69 @@ describe 'Protocol parsing and communication' do
320
369
  ]
321
370
  end
322
371
  end
372
+
373
+ it 'sends an INSERT command with bound values' do
374
+ in_keyspace_with_table do
375
+ cql = %<INSERT INTO users (user_name, email) VALUES (?, ?)>
376
+ response = execute_request(Cql::Protocol::QueryRequest.new(cql, ['sue', 'sue@inter.net'], nil, :one))
377
+ response.should be_void
378
+ end
379
+ end
380
+
381
+ it 'sends an UPDATE command with bound values' do
382
+ in_keyspace_with_table do
383
+ cql = %<UPDATE users SET email = ? WHERE user_name = ?>
384
+ response = execute_request(Cql::Protocol::QueryRequest.new(cql, ['sue@inter.net', 'sue'], nil, :one))
385
+ response.should be_void
386
+ end
387
+ end
388
+
389
+ it 'sends a SELECT command with bound values' do
390
+ in_keyspace_with_table do
391
+ query(%<INSERT INTO users (user_name, email) VALUES ('phil', 'phil@heck.com')>)
392
+ query(%<INSERT INTO users (user_name, email) VALUES ('sue', 'sue@inter.net')>)
393
+ cql = %<SELECT * FROM users WHERE user_name = ?>
394
+ response = execute_request(Cql::Protocol::QueryRequest.new(cql, ['sue'], nil, :one))
395
+ response.rows.should == [
396
+ {'user_name' => 'sue', 'email' => 'sue@inter.net', 'password' => nil}
397
+ ]
398
+ end
399
+ end
400
+
401
+ it 'guesses the types of bound values' do
402
+ in_keyspace do
403
+ query('CREATE TABLE types (a BIGINT PRIMARY KEY, b DOUBLE, c ASCII, d BOOLEAN, e TIMESTAMP, f UUID, g DECIMAL, h BLOB)')
404
+ cql = %<UPDATE types SET b = ?, c = ?, d = ?, e = ?, f = ?, g = ?, h = ? WHERE a = ?>
405
+ values = [123.456, 'foo', true, Time.now, Cql::TimeUuid::Generator.new.next, BigDecimal.new('0.01'), 'hello', 3]
406
+ response = execute_request(Cql::Protocol::QueryRequest.new(cql, values, nil, :one))
407
+ response.should be_void
408
+ end
409
+ end
410
+
411
+ it 'uses the provided type hints to encode bound values' do
412
+ in_keyspace do
413
+ query('CREATE TABLE types (a INT PRIMARY KEY, b FLOAT)')
414
+ cql = %<UPDATE types SET b = ? WHERE a = ?>
415
+ values = [123.456, 3]
416
+ hints = [:float, :int]
417
+ response = execute_request(Cql::Protocol::QueryRequest.new(cql, values, hints, :one))
418
+ response.should be_void
419
+ end
420
+ end
421
+
422
+ it 'sends a SELECT command with a page size and receives a ROWS RESULT with a paging state' do
423
+ in_keyspace_with_table do
424
+ 10.times do
425
+ query(%<INSERT INTO users (user_name, email) VALUES ('#{rand(234234).to_s(36)}', 'someone@somewhere.sx')>)
426
+ end
427
+ response = execute_request(Cql::Protocol::QueryRequest.new('SELECT * FROM users', nil, nil, :one, nil, 6))
428
+ response.paging_state.should_not be_nil
429
+ response.rows.size.should == 6
430
+ response = execute_request(Cql::Protocol::QueryRequest.new('SELECT * FROM users', nil, nil, :one, nil, 6, response.paging_state))
431
+ response.paging_state.should be_nil
432
+ response.rows.size.should == 4
433
+ end
434
+ end
323
435
  end
324
436
 
325
437
  context 'with PREPARE requests' do
@@ -335,20 +447,58 @@ describe 'Protocol parsing and communication' do
335
447
  in_keyspace do
336
448
  create_table_cql = %<CREATE TABLE stuff (id1 UUID, id2 VARINT, id3 TIMESTAMP, value1 DOUBLE, value2 TIMEUUID, value3 BLOB, PRIMARY KEY (id1, id2, id3))>
337
449
  insert_cql = %<INSERT INTO stuff (id1, id2, id3, value1, value2, value3) VALUES (?, ?, ?, ?, ?, ?)>
338
- create_response = execute_request(Cql::Protocol::QueryRequest.new(create_table_cql, :one))
450
+ create_response = execute_request(Cql::Protocol::QueryRequest.new(create_table_cql, nil, nil, :one))
339
451
  create_response.should_not be_a(Cql::Protocol::ErrorResponse)
340
452
  prepare_response = execute_request(Cql::Protocol::PrepareRequest.new(insert_cql))
341
453
  prepare_response.should_not be_a(Cql::Protocol::ErrorResponse)
342
- execute_response = execute_request(Cql::Protocol::ExecuteRequest.new(prepare_response.id, prepare_response.metadata, [Cql::Uuid.new('cfd66ccc-d857-4e90-b1e5-df98a3d40cd6'), -12312312312, Time.now, 345345.234234, Cql::Uuid.new('a4a70900-24e1-11df-8924-001ff3591711'), "\xab\xcd\xef".force_encoding(::Encoding::BINARY)], :one))
454
+ values = [Cql::Uuid.new('cfd66ccc-d857-4e90-b1e5-df98a3d40cd6'), -12312312312, Time.now, 345345.234234, Cql::Uuid.new('a4a70900-24e1-11df-8924-001ff3591711'), "\xab\xcd\xef".force_encoding(::Encoding::BINARY)]
455
+ execute_response = execute_request(Cql::Protocol::ExecuteRequest.new(prepare_response.id, prepare_response.metadata, values, nil, :one, nil, nil, nil, true))
343
456
  execute_response.should_not be_a(Cql::Protocol::ErrorResponse)
344
457
  end
345
458
  end
459
+
460
+ it 'sends an EXECUTE with a page size and receives a RESULT with a paging state' do
461
+ in_keyspace_with_table do
462
+ 10.times do
463
+ query(%<INSERT INTO users (user_name, email) VALUES ('#{rand(234234).to_s(36)}', 'someone@somewhere.sx')>)
464
+ end
465
+ response = execute_request(Cql::Protocol::PrepareRequest.new('SELECT * FROM users'))
466
+ statement_id = response.id
467
+ metadata = response.metadata
468
+ response = execute_request(Cql::Protocol::ExecuteRequest.new(statement_id, metadata, [], true, :one, nil, 6, nil))
469
+ response.paging_state.should_not be_nil
470
+ response.rows.size.should == 6
471
+ response = execute_request(Cql::Protocol::ExecuteRequest.new(statement_id, metadata, [], true, :one, nil, 6, response.paging_state))
472
+ response.paging_state.should be_nil
473
+ response.rows.size.should == 4
474
+ end
475
+ end
476
+ end
477
+
478
+ context 'with BATCH requests' do
479
+ it 'sends a BATCH request and receives RESULT' do
480
+ in_keyspace_with_table do
481
+ cql1 = %<INSERT INTO users (user_name, email) VALUES (?, ?)>
482
+ cql2 = %<UPDATE users SET email = ? WHERE user_name = 'sue'>
483
+ cql3 = %<INSERT INTO users (user_name, email) VALUES ('tim', 'tim@pim.com')>
484
+ prepared_response1 = execute_request(Cql::Protocol::PrepareRequest.new(cql1))
485
+ prepared_response2 = execute_request(Cql::Protocol::PrepareRequest.new(cql3))
486
+ request = Cql::Protocol::BatchRequest.new(0, :quorum)
487
+ request.add_query(cql1, ['sue', 'sue@inter.net'])
488
+ request.add_query(cql2, ['eve'])
489
+ request.add_query(cql3)
490
+ request.add_prepared(prepared_response1.id, prepared_response1.metadata, ['phil', 'phil@heck.com'])
491
+ request.add_prepared(prepared_response2.id, prepared_response2.metadata, [])
492
+ response = execute_request(request)
493
+ response.should be_void
494
+ end
495
+ end
346
496
  end
347
497
 
348
498
  context 'with tracing' do
349
499
  it 'sends a QUERY request with the tracing flag and receives a RESULT with a trace ID' do
350
500
  in_keyspace_with_table do
351
- response = execute_request(Cql::Protocol::QueryRequest.new('SELECT * FROM users', :quorum, true))
501
+ response = execute_request(Cql::Protocol::QueryRequest.new('SELECT * FROM users', nil, nil, :quorum, nil, nil, nil, true))
352
502
  response.trace_id.should_not be_nil
353
503
  end
354
504
  end
@@ -363,7 +513,7 @@ describe 'Protocol parsing and communication' do
363
513
  it 'sends an EXECUTE request with the tracing flag and receives a RESULT with a trace ID' do
364
514
  in_keyspace_with_table do
365
515
  prepare_response = execute_request(Cql::Protocol::PrepareRequest.new('SELECT * FROM users'))
366
- execute_response = execute_request(Cql::Protocol::ExecuteRequest.new(prepare_response.id, prepare_response.metadata, [], :one, true))
516
+ execute_response = execute_request(Cql::Protocol::ExecuteRequest.new(prepare_response.id, prepare_response.metadata, [], true, :one, nil, nil, nil, true))
367
517
  execute_response.trace_id.should_not be_nil
368
518
  end
369
519
  end
@@ -377,11 +527,11 @@ describe 'Protocol parsing and communication' do
377
527
  it 'sends a compressed request and receives a compressed response' do
378
528
  compressor.stub(:compress).and_call_original
379
529
  compressor.stub(:decompress).and_call_original
380
- io_reactor = Cql::Io::IoReactor.new(lambda { |*args| Cql::Protocol::CqlProtocolHandler.new(*args, compressor) })
530
+ io_reactor = Cql::Io::IoReactor.new(lambda { |*args| Cql::Protocol::CqlProtocolHandler.new(*args, protocol_version, compressor) })
381
531
  io_reactor.start.value
382
532
  begin
383
533
  connection = io_reactor.connect(ENV['CASSANDRA_HOST'], 9042, 0.1).value
384
- connection.send_request(Cql::Protocol::StartupRequest.new(nil, 'snappy')).value
534
+ connection.send_request(Cql::Protocol::StartupRequest.new('3.1.0', 'snappy')).value
385
535
  connection.send_request(Cql::Protocol::PrepareRequest.new('SELECT * FROM system.peers')).value
386
536
  compressor.should have_received(:compress).at_least(1).times
387
537
  compressor.should have_received(:decompress).at_least(1).times
@@ -399,10 +549,10 @@ describe 'Protocol parsing and communication' do
399
549
  it 'handles multiple concurrent requests' do
400
550
  in_keyspace_with_table do
401
551
  futures = 10.times.map do
402
- connection.send_request(Cql::Protocol::QueryRequest.new('SELECT * FROM users', :quorum))
552
+ connection.send_request(Cql::Protocol::QueryRequest.new('SELECT * FROM users', nil, nil, :quorum))
403
553
  end
404
554
 
405
- futures << connection.send_request(Cql::Protocol::QueryRequest.new(%<INSERT INTO users (user_name, email) VALUES ('sam', 'sam@ham.com')>, :one))
555
+ futures << connection.send_request(Cql::Protocol::QueryRequest.new(%<INSERT INTO users (user_name, email) VALUES ('sam', 'sam@ham.com')>, nil, nil, :one))
406
556
 
407
557
  Cql::Future.all(*futures).value
408
558
  end
@@ -413,7 +563,7 @@ describe 'Protocol parsing and communication' do
413
563
  threads = Array.new(10) do
414
564
  Thread.new do
415
565
  futures = 200.times.map do
416
- connection.send_request(Cql::Protocol::QueryRequest.new('SELECT * FROM users', :quorum))
566
+ connection.send_request(Cql::Protocol::QueryRequest.new('SELECT * FROM users', nil, nil, :quorum))
417
567
  end
418
568
  Cql::Future.all(*futures).value
419
569
  end
@@ -427,7 +577,7 @@ describe 'Protocol parsing and communication' do
427
577
 
428
578
  context 'in special circumstances' do
429
579
  it 'raises an exception when it cannot connect to Cassandra' do
430
- io_reactor = Cql::Io::IoReactor.new(Cql::Protocol::CqlProtocolHandler)
580
+ io_reactor = Cql::Io::IoReactor.new(lambda { |*args| Cql::Protocol::CqlProtocolHandler.new(*args, protocol_version) })
431
581
  io_reactor.start.value
432
582
  expect { io_reactor.connect('example.com', 9042, 0.1).value }.to raise_error(Cql::Io::ConnectionError)
433
583
  expect { io_reactor.connect('blackhole', 9042, 0.1).value }.to raise_error(Cql::Io::ConnectionError)
@@ -435,15 +585,16 @@ describe 'Protocol parsing and communication' do
435
585
  end
436
586
 
437
587
  it 'does nothing the second time #start is called' do
438
- io_reactor = Cql::Io::IoReactor.new(Cql::Protocol::CqlProtocolHandler)
588
+ io_reactor = Cql::Io::IoReactor.new(lambda { |*args| Cql::Protocol::CqlProtocolHandler.new(*args, 2) })
439
589
  io_reactor.start.value
440
590
  connection = io_reactor.connect(ENV['CASSANDRA_HOST'], 9042, 0.1).value
441
- response = connection.send_request(Cql::Protocol::StartupRequest.new).value
591
+ response = connection.send_request(Cql::Protocol::StartupRequest.new('3.1.0')).value
442
592
  if response.is_a?(Cql::Protocol::AuthenticateResponse)
443
- connection.send_request(Cql::Protocol::CredentialsRequest.new('username' => 'cassandra', 'password' => 'cassandra')).value
593
+ response = connection.send_request(Cql::Protocol::AuthResponseRequest.new("\x00cassandra\x00cassandra")).value
594
+ response.should be_a(Cql::Protocol::AuthSuccessResponse)
444
595
  end
445
596
  io_reactor.start.value
446
- response = connection.send_request(Cql::Protocol::QueryRequest.new('USE system', :any)).value
597
+ response = connection.send_request(Cql::Protocol::QueryRequest.new('USE system', nil, nil, :any)).value
447
598
  response.should_not be_a(Cql::Protocol::ErrorResponse)
448
599
  end
449
600
  end
@@ -5,7 +5,10 @@ require 'spec_helper'
5
5
 
6
6
  describe 'Regressions' do
7
7
  let :connection_options do
8
- {:host => ENV['CASSANDRA_HOST'], :credentials => {:username => 'cassandra', :password => 'cassandra'}}
8
+ {
9
+ :host => ENV['CASSANDRA_HOST'],
10
+ :credentials => {:username => 'cassandra', :password => 'cassandra'},
11
+ }
9
12
  end
10
13
 
11
14
  let :client do
@@ -5,7 +5,10 @@ require 'spec_helper'
5
5
 
6
6
  describe 'Loading and storing UUIDs' do
7
7
  let :connection_options do
8
- {:host => ENV['CASSANDRA_HOST'], :credentials => {:username => 'cassandra', :password => 'cassandra'}}
8
+ {
9
+ :host => ENV['CASSANDRA_HOST'],
10
+ :credentials => {:username => 'cassandra', :password => 'cassandra'},
11
+ }
9
12
  end
10
13
 
11
14
  let :client do
@@ -73,7 +73,7 @@ end
73
73
  class FakeConnection
74
74
  attr_reader :host, :port, :timeout, :requests, :keyspace
75
75
 
76
- def initialize(host, port, timeout)
76
+ def initialize(host, port, timeout, data={})
77
77
  @host = host
78
78
  @port = port
79
79
  @timeout = timeout
@@ -81,7 +81,7 @@ class FakeConnection
81
81
  @responses = []
82
82
  @closed = false
83
83
  @keyspace = nil
84
- @data = {}
84
+ @data = data
85
85
  @registered_event_types = []
86
86
  @event_listeners = []
87
87
  @closed_listeners = []
@@ -100,9 +100,9 @@ class FakeConnection
100
100
  !@closed
101
101
  end
102
102
 
103
- def close
103
+ def close(cause=nil)
104
104
  @closed = true
105
- @closed_listeners.each(&:call)
105
+ @closed_listeners.each { |listener| listener.call(cause) }
106
106
  end
107
107
 
108
108
  def handle_request(&handler)
@@ -151,7 +151,7 @@ class FakeConnection
151
151
  when Cql::Protocol::StartupRequest
152
152
  Cql::Protocol::ReadyResponse.new
153
153
  when Cql::Protocol::QueryRequest
154
- Cql::Protocol::RowsResultResponse.new([], [], nil)
154
+ Cql::Protocol::RowsResultResponse.new([], [], nil, nil)
155
155
  end
156
156
  end
157
157
  end