cql-rb 1.1.0.pre0 → 1.1.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.
@@ -1,7 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'spec_helper'
4
- require 'cql/client/client_shared'
5
4
 
6
5
 
7
6
  module Cql
@@ -99,6 +98,30 @@ module Cql
99
98
  client.async.should equal(async_client)
100
99
  end
101
100
  end
101
+
102
+ context 'when exceptions are raised' do
103
+ it 'replaces the backtrace of the asynchronous call to make it less confusing' do
104
+ error = CqlError.new('Bork')
105
+ error.set_backtrace(['Hello', 'World'])
106
+ future.stub(:get).and_raise(error)
107
+ async_client.stub(:execute).and_return(future)
108
+ begin
109
+ client.execute('SELECT * FROM something')
110
+ rescue CqlError => e
111
+ e.backtrace.first.should match(%r{/synchronous_client.rb:\d+:in `execute'})
112
+ end
113
+ end
114
+
115
+ it 'does not replace the backtrace of non-CqlError errors' do
116
+ future.stub(:get).and_raise('Bork')
117
+ async_client.stub(:execute).and_return(future)
118
+ begin
119
+ client.execute('SELECT * FROM something')
120
+ rescue => e
121
+ e.backtrace.first.should_not match(%r{/synchronous_client.rb:\d+:in `execute'})
122
+ end
123
+ end
124
+ end
102
125
  end
103
126
  end
104
127
  end
@@ -60,6 +60,30 @@ module Cql
60
60
  statement.async.should equal(async_statement)
61
61
  end
62
62
  end
63
+
64
+ context 'when exceptions are raised' do
65
+ it 'replaces the backtrace of the asynchronous call to make it less confusing' do
66
+ error = CqlError.new('Bork')
67
+ error.set_backtrace(['Hello', 'World'])
68
+ future.stub(:get).and_raise(error)
69
+ async_statement.stub(:execute).and_return(future)
70
+ begin
71
+ statement.execute('SELECT * FROM something')
72
+ rescue CqlError => e
73
+ e.backtrace.first.should match(%r{/synchronous_prepared_statement.rb:\d+:in `execute'})
74
+ end
75
+ end
76
+
77
+ it 'does not replace the backtrace of non-CqlError errors' do
78
+ future.stub(:get).and_raise('Bork')
79
+ async_statement.stub(:execute).and_return(future)
80
+ begin
81
+ statement.execute('SELECT * FROM something')
82
+ rescue => e
83
+ e.backtrace.first.should_not match(%r{/synchronous_prepared_statement.rb:\d+:in `execute'})
84
+ end
85
+ end
86
+ end
63
87
  end
64
88
  end
65
89
  end
@@ -223,6 +223,60 @@ module Cql
223
223
  end
224
224
  end
225
225
 
226
+ describe '.first' do
227
+ context 'it returns a new future which' do
228
+ it 'is complete when the first of the source futures is complete' do
229
+ f1 = Future.new
230
+ f2 = Future.new
231
+ f3 = Future.new
232
+ ff = Future.first(f1, f2, f3)
233
+ f2.complete!
234
+ ff.should be_complete
235
+ end
236
+
237
+ it 'completes with the value of the first source future' do
238
+ f1 = Future.new
239
+ f2 = Future.new
240
+ f3 = Future.new
241
+ ff = Future.first(f1, f2, f3)
242
+ f2.complete!('foo')
243
+ ff.get.should == 'foo'
244
+ end
245
+
246
+ it 'is unaffected by the completion of the other futures' do
247
+ f1 = Future.new
248
+ f2 = Future.new
249
+ f3 = Future.new
250
+ ff = Future.first(f1, f2, f3)
251
+ f2.complete!
252
+ f1.complete!
253
+ f3.complete!
254
+ end
255
+
256
+ it 'fails if all of the source futures fail' do
257
+ f1 = Future.new
258
+ f2 = Future.new
259
+ f3 = Future.new
260
+ ff = Future.first(f1, f2, f3)
261
+ f2.fail!(StandardError.new('bork'))
262
+ f1.fail!(StandardError.new('bork'))
263
+ f3.fail!(StandardError.new('bork'))
264
+ ff.should be_failed
265
+ end
266
+
267
+ it 'fails with the error of the last future to fail' do
268
+ f1 = Future.new
269
+ f2 = Future.new
270
+ f3 = Future.new
271
+ ff = Future.first(f1, f2, f3)
272
+ f2.fail!(StandardError.new('bork2'))
273
+ f1.fail!(StandardError.new('bork1'))
274
+ f3.fail!(StandardError.new('bork3'))
275
+ expect { ff.get }.to raise_error('bork3')
276
+ end
277
+ end
278
+ end
279
+
226
280
  describe '#map' do
227
281
  context 'returns a new future that' do
228
282
  it 'will complete with the result of the given block' do
@@ -271,6 +325,86 @@ module Cql
271
325
  end
272
326
  end
273
327
 
328
+ describe '#recover' do
329
+ context 'returns a new future that' do
330
+ it 'completes with a value when the source future fails' do
331
+ f1 = Future.new
332
+ f2 = f1.recover { 'foo' }
333
+ f1.fail!(StandardError.new('Bork!'))
334
+ f2.get.should == 'foo'
335
+ end
336
+
337
+ it 'yields the error to the block' do
338
+ f1 = Future.new
339
+ f2 = f1.recover { |e| e.message }
340
+ f1.fail!(StandardError.new('Bork!'))
341
+ f2.get.should == 'Bork!'
342
+ end
343
+
344
+ it 'completes with the value of the source future when the source future is successful' do
345
+ f1 = Future.new
346
+ f2 = f1.recover { 'foo' }
347
+ f1.complete!('bar')
348
+ f2.get.should == 'bar'
349
+ end
350
+
351
+ it 'fails with the error raised in the given block' do
352
+ f1 = Future.new
353
+ f2 = f1.recover { raise 'Snork!' }
354
+ f1.fail!(StandardError.new('Bork!'))
355
+ expect { f2.get }.to raise_error('Snork!')
356
+ end
357
+ end
358
+ end
359
+
360
+ describe '#fallback' do
361
+ context 'returns a new future that' do
362
+ it 'completes with the value of the fallback future when the source future fails' do
363
+ f1 = Future.new
364
+ f2 = Future.new
365
+ f3 = f1.fallback { f2 }
366
+ f1.fail!(StandardError.new('Bork!'))
367
+ f2.complete!('foo')
368
+ f3.get.should == 'foo'
369
+ end
370
+
371
+ it 'yields the error to the block' do
372
+ f1 = Future.new
373
+ f2 = Future.new
374
+ f3 = f1.fallback do |error|
375
+ Future.completed(error.message)
376
+ end
377
+ f1.fail!(StandardError.new('Bork!'))
378
+ f3.get.should == 'Bork!'
379
+ end
380
+
381
+ it 'completes with the value of the source future when the source future succeeds' do
382
+ f1 = Future.new
383
+ f2 = Future.new
384
+ f3 = f1.fallback { f2 }
385
+ f2.complete!('bar')
386
+ f1.complete!('foo')
387
+ f3.get.should == 'foo'
388
+ end
389
+
390
+ it 'fails when the block raises an error' do
391
+ f1 = Future.new
392
+ f2 = f1.fallback { raise 'Bork!' }
393
+ f1.fail!(StandardError.new('Splork!'))
394
+ expect { f2.get }.to raise_error('Bork!')
395
+ end
396
+
397
+ it 'fails when the fallback future fails' do
398
+ f1 = Future.new
399
+ f2 = Future.new
400
+ f3 = f1.fallback { f2 }
401
+ f2.fail!(StandardError.new('Bork!'))
402
+ f1.fail!(StandardError.new('Fnork!'))
403
+ expect { f3.get }.to raise_error('Bork!')
404
+ end
405
+ end
406
+ end
407
+
274
408
  describe '.completed' do
275
409
  let :future do
276
410
  described_class.completed('hello world')
@@ -41,6 +41,13 @@ module Cql
41
41
  end
42
42
  end
43
43
 
44
+ describe '#[]/#[]=' do
45
+ it 'is thread safe storage for arbitrary data' do
46
+ protocol_handler[:host_id] = 42
47
+ protocol_handler[:host_id].should == 42
48
+ end
49
+ end
50
+
44
51
  describe '#send_request' do
45
52
  before do
46
53
  connection.stub(:write).and_yield(buffer)
@@ -10,20 +10,29 @@ class FakeIoReactor
10
10
  @default_host = nil
11
11
  @connection_listeners = []
12
12
  @started_future = Cql::Future.new
13
- @startup_delay = 0
13
+ @before_startup_handler = nil
14
+ @down_nodes = []
14
15
  end
15
16
 
16
- def startup_delay=(n)
17
- @startup_delay = n
17
+ def node_down(hostname)
18
+ @down_nodes << hostname
19
+ end
20
+
21
+ def before_startup(&handler)
22
+ @before_startup_handler = handler
18
23
  end
19
24
 
20
25
  def connect(host, port, timeout)
21
- connection = FakeConnection.new(host, port, timeout)
22
- @connections << connection
23
- @connection_listeners.each do |listener|
24
- listener.call(connection)
26
+ if @down_nodes.include?(host)
27
+ Cql::Future.failed(Cql::Io::ConnectionError.new('Node down'))
28
+ else
29
+ connection = FakeConnection.new(host, port, timeout)
30
+ @connections << connection
31
+ @connection_listeners.each do |listener|
32
+ listener.call(connection)
33
+ end
34
+ Cql::Future.completed(connection)
25
35
  end
26
- Cql::Future.completed(connection)
27
36
  end
28
37
 
29
38
  def on_connection(&listener)
@@ -32,8 +41,13 @@ class FakeIoReactor
32
41
 
33
42
  def start
34
43
  @running = true
35
- Thread.start do
36
- sleep(@startup_delay)
44
+ if @before_startup_handler
45
+ @before_startup_handler = nil
46
+ Thread.start do
47
+ @before_startup_handler.call
48
+ @started_future.complete!(self)
49
+ end
50
+ elsif !(@started_future.complete? || @started_future.failed?)
37
51
  @started_future.complete!(self)
38
52
  end
39
53
  @started_future
@@ -61,14 +75,28 @@ class FakeConnection
61
75
  @responses = []
62
76
  @closed = false
63
77
  @keyspace = nil
78
+ @data = {}
79
+ @request_handler = method(:default_request_handler)
80
+ end
81
+
82
+ def [](key)
83
+ @data[key]
84
+ end
85
+
86
+ def []=(key, value)
87
+ @data[key] = value
88
+ end
89
+
90
+ def connected?
91
+ !@closed
64
92
  end
65
93
 
66
94
  def close
67
95
  @closed = true
68
96
  end
69
97
 
70
- def queue_response(response)
71
- @responses << response
98
+ def handle_request(&handler)
99
+ @request_handler = handler
72
100
  end
73
101
 
74
102
  def send_request(request)
@@ -76,11 +104,23 @@ class FakeConnection
76
104
  Cql::Future.failed(Cql::NotConnectedError.new)
77
105
  else
78
106
  @requests << request
79
- response = @responses.shift
107
+ response = @request_handler.call(request)
80
108
  if response.is_a?(Cql::Protocol::SetKeyspaceResultResponse)
81
109
  @keyspace = response.keyspace
82
110
  end
83
111
  Cql::Future.completed(response)
84
112
  end
85
113
  end
114
+
115
+ def default_request_handler(request)
116
+ response = @responses.shift
117
+ unless response
118
+ case request
119
+ when Cql::Protocol::StartupRequest
120
+ Cql::Protocol::ReadyResponse.new
121
+ when Cql::Protocol::QueryRequest
122
+ Cql::Protocol::RowsResultResponse.new([], [])
123
+ end
124
+ end
125
+ end
86
126
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cql-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0.pre0
4
+ version: 1.1.0.pre1
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-04 00:00:00.000000000 Z
12
+ date: 2013-07-24 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A pure Ruby CQL3 driver for Cassandra
15
15
  email:
@@ -71,7 +71,6 @@ files:
71
71
  - spec/cql/byte_buffer_spec.rb
72
72
  - spec/cql/client/asynchronous_client_spec.rb
73
73
  - spec/cql/client/asynchronous_prepared_statement_spec.rb
74
- - spec/cql/client/client_shared.rb
75
74
  - spec/cql/client/column_metadata_spec.rb
76
75
  - spec/cql/client/request_runner_spec.rb
77
76
  - spec/cql/client/synchronous_client_spec.rb
@@ -133,7 +132,6 @@ test_files:
133
132
  - spec/cql/byte_buffer_spec.rb
134
133
  - spec/cql/client/asynchronous_client_spec.rb
135
134
  - spec/cql/client/asynchronous_prepared_statement_spec.rb
136
- - spec/cql/client/client_shared.rb
137
135
  - spec/cql/client/column_metadata_spec.rb
138
136
  - spec/cql/client/request_runner_spec.rb
139
137
  - spec/cql/client/synchronous_client_spec.rb
@@ -1,27 +0,0 @@
1
- # encoding: utf-8
2
-
3
- shared_context 'client setup' do
4
- let :connection_options do
5
- {:host => 'example.com', :port => 12321, :io_reactor => io_reactor}
6
- end
7
-
8
- let :io_reactor do
9
- FakeIoReactor.new
10
- end
11
-
12
- def connections
13
- io_reactor.connections
14
- end
15
-
16
- def last_connection
17
- connections.last
18
- end
19
-
20
- def requests
21
- last_connection.requests
22
- end
23
-
24
- def last_request
25
- requests.last
26
- end
27
- end