cql-rb 1.2.2 → 2.0.0.pre0

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