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,170 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
-
6
- module Cql
7
- module Client
8
- describe SynchronousClient do
9
- let :client do
10
- described_class.new(async_client)
11
- end
12
-
13
- let :async_client do
14
- double(:async_client)
15
- end
16
-
17
- let :future do
18
- double(:future, value: nil)
19
- end
20
-
21
- describe '#connect' do
22
- it 'calls #connect on the async client and waits for the result' do
23
- async_client.should_receive(:connect).and_return(future)
24
- future.should_receive(:value)
25
- client.connect
26
- end
27
-
28
- it 'returns self' do
29
- async_client.stub(:connect).and_return(future)
30
- client.connect.should equal(client)
31
- end
32
- end
33
-
34
- describe '#close' do
35
- it 'calls #close on the async client and waits for the result' do
36
- async_client.should_receive(:close).and_return(future)
37
- future.should_receive(:value)
38
- client.close
39
- end
40
-
41
- it 'returns self' do
42
- async_client.stub(:close).and_return(future)
43
- client.close.should equal(client)
44
- end
45
- end
46
-
47
- describe '#connected?' do
48
- it 'delegates to the async client' do
49
- async_client.stub(:connected?).and_return(true)
50
- client.connected?.should be_true
51
- async_client.stub(:connected?).and_return(false)
52
- client.connected?.should be_false
53
- end
54
- end
55
-
56
- describe '#keyspace' do
57
- it 'delegates to the async client' do
58
- async_client.stub(:keyspace).and_return('foo')
59
- client.keyspace.should == 'foo'
60
- end
61
- end
62
-
63
- describe '#use' do
64
- it 'calls #use on the async client and waits for the result' do
65
- async_client.should_receive(:use).with('foo').and_return(future)
66
- future.should_receive(:value)
67
- client.use('foo')
68
- end
69
- end
70
-
71
- describe '#execute' do
72
- it 'calls #execute on the async client and waits for, and returns the result' do
73
- result = double(:result)
74
- async_client.stub(:execute).with('SELECT * FROM something', :one).and_return(future)
75
- future.stub(:value).and_return(result)
76
- client.execute('SELECT * FROM something', :one).should equal(result)
77
- end
78
-
79
- it 'wraps AsynchronousPagedQueryResult in a synchronous wrapper' do
80
- cql = 'SELECT * FROM something'
81
- request = double(:request, cql: cql, values: [])
82
- async_result = double(:result, paging_state: 'somepagingstate')
83
- options = {:page_size => 10}
84
- async_client.stub(:execute).and_return(Future.resolved(AsynchronousQueryPagedQueryResult.new(async_client, request, async_result, options)))
85
- result1 = client.execute(cql, options)
86
- result2 = result1.next_page
87
- async_client.should have_received(:execute).with('SELECT * FROM something', page_size: 10, paging_state: 'somepagingstate')
88
- result2.should be_a(SynchronousPagedQueryResult)
89
- end
90
- end
91
-
92
- describe '#prepare' do
93
- it 'calls #prepare on the async client, waits for the result and returns a SynchronousFuture' do
94
- result = double(:result)
95
- metadata = double(:metadata)
96
- result_metadata = double(:result_metadata)
97
- async_statement = double(:async_statement, metadata: metadata, result_metadata: result_metadata)
98
- another_future = double(:another_future)
99
- async_client.stub(:prepare).with('SELECT * FROM something').and_return(future)
100
- future.stub(:value).and_return(async_statement)
101
- statement = client.prepare('SELECT * FROM something')
102
- async_statement.should_receive(:execute).and_return(another_future)
103
- another_future.stub(:value).and_return(result)
104
- statement.execute.should equal(result)
105
- statement.metadata.should equal(metadata)
106
- end
107
- end
108
-
109
- describe '#batch' do
110
- let :batch do
111
- double(:batch)
112
- end
113
-
114
- context 'when called without a block' do
115
- it 'delegates to the asynchronous client and wraps the returned object in a synchronous wrapper' do
116
- async_client.stub(:batch).with(:unlogged, trace: true).and_return(batch)
117
- batch.stub(:execute).and_return(Cql::Future.resolved(VoidResult.new))
118
- b = client.batch(:unlogged, trace: true)
119
- b.execute.should be_a(VoidResult)
120
- end
121
- end
122
-
123
- context 'when called with a block' do
124
- it 'delegates to the asynchronous client' do
125
- async_client.stub(:batch).with(:counter, trace: true).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
126
- yielded_batch = nil
127
- client.batch(:counter, trace: true) { |b| yielded_batch = b }
128
- yielded_batch.should equal(batch)
129
- end
130
-
131
- it 'waits for the operation to complete' do
132
- async_client.stub(:batch).with(:counter, {}).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
133
- result = client.batch(:counter) { |b| }
134
- result.should be_a(VoidResult)
135
- end
136
- end
137
- end
138
-
139
- describe '#async' do
140
- it 'returns an asynchronous client' do
141
- client.async.should equal(async_client)
142
- end
143
- end
144
-
145
- context 'when exceptions are raised' do
146
- it 'replaces the backtrace of the asynchronous call to make it less confusing' do
147
- error = CqlError.new('Bork')
148
- error.set_backtrace(['Hello', 'World'])
149
- future.stub(:value).and_raise(error)
150
- async_client.stub(:execute).and_return(future)
151
- begin
152
- client.execute('SELECT * FROM something')
153
- rescue CqlError => e
154
- e.backtrace.first.should match(%r{/synchronous_client.rb:\d+:in `execute'})
155
- end
156
- end
157
-
158
- it 'does not replace the backtrace of non-CqlError errors' do
159
- future.stub(:value).and_raise('Bork')
160
- async_client.stub(:execute).and_return(future)
161
- begin
162
- client.execute('SELECT * FROM something')
163
- rescue => e
164
- e.backtrace.first.should_not match(%r{/synchronous_client.rb:\d+:in `execute'})
165
- end
166
- end
167
- end
168
- end
169
- end
170
- end
@@ -1,155 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
-
6
- module Cql
7
- module Client
8
- describe SynchronousPreparedStatement do
9
- let :statement do
10
- described_class.new(async_statement)
11
- end
12
-
13
- let :async_statement do
14
- double(:async_statement, metadata: metadata, result_metadata: result_metadata)
15
- end
16
-
17
- let :metadata do
18
- double(:metadata)
19
- end
20
-
21
- let :result_metadata do
22
- double(:result_metadata)
23
- end
24
-
25
- let :promise do
26
- Promise.new
27
- end
28
-
29
- let :future do
30
- promise.future
31
- end
32
-
33
- describe '#metadata' do
34
- it 'returns the async statement\'s metadata' do
35
- statement.metadata.should equal(async_statement.metadata)
36
- end
37
- end
38
-
39
- describe '#result_metadata' do
40
- it 'returns the async statement\'s result metadata' do
41
- statement.result_metadata.should equal(async_statement.result_metadata)
42
- end
43
- end
44
-
45
- describe '#execute' do
46
- it 'it calls #execute on the async statement and waits for the result' do
47
- result = double(:result)
48
- async_statement.should_receive(:execute).with('one', 'two', :three).and_return(future)
49
- promise.fulfill(result)
50
- statement.execute('one', 'two', :three).should equal(result)
51
- end
52
-
53
- it 'wraps AsynchronousPagedQueryResult in a synchronous wrapper' do
54
- request = double(:request, values: ['one', 'two'])
55
- async_result = double(:result, paging_state: 'somepagingstate')
56
- options = {:page_size => 10}
57
- async_statement.stub(:execute).and_return(Future.resolved(AsynchronousPreparedPagedQueryResult.new(async_statement, request, async_result, options)))
58
- result1 = statement.execute('one', 'two', options)
59
- result2 = result1.next_page
60
- async_statement.should have_received(:execute).with('one', 'two', page_size: 10, paging_state: 'somepagingstate')
61
- result2.should be_a(SynchronousPagedQueryResult)
62
- end
63
- end
64
-
65
- describe '#batch' do
66
- let :batch do
67
- double(:batch)
68
- end
69
-
70
- context 'when called without a block' do
71
- it 'delegates to the asynchronous statement and wraps the returned object in a synchronous wrapper' do
72
- async_statement.stub(:batch).with(:unlogged, trace: true).and_return(batch)
73
- batch.stub(:execute).and_return(Cql::Future.resolved(VoidResult.new))
74
- b = statement.batch(:unlogged, trace: true)
75
- b.execute.should be_a(VoidResult)
76
- end
77
- end
78
-
79
- context 'when called with a block' do
80
- it 'delegates to the asynchronous statement' do
81
- async_statement.stub(:batch).with(:counter, trace: true).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
82
- yielded_batch = nil
83
- statement.batch(:counter, trace: true) { |b| yielded_batch = b }
84
- yielded_batch.should equal(batch)
85
- end
86
-
87
- it 'waits for the operation to complete' do
88
- async_statement.stub(:batch).with(:counter, anything).and_yield(batch).and_return(Cql::Future.resolved(VoidResult.new))
89
- result = statement.batch(:counter) { |b| }
90
- result.should be_a(VoidResult)
91
- end
92
- end
93
- end
94
-
95
- describe '#add_to_batch' do
96
- it 'delegates to the async statement' do
97
- batch = double(:batch)
98
- connection = double(:connection)
99
- bound_arguments = [1, 2, 3]
100
- async_statement.stub(:add_to_batch)
101
- statement.add_to_batch(batch, connection, bound_arguments)
102
- async_statement.should have_received(:add_to_batch).with(batch, connection, bound_arguments)
103
- end
104
- end
105
-
106
- describe '#pipeline' do
107
- it 'executes the statement multiple times and waits for all the results' do
108
- result1 = double(:result1)
109
- result2 = double(:result2)
110
- async_statement.stub(:execute).with('one', 'two', :three).and_return(Future.resolved(result1))
111
- async_statement.stub(:execute).with('four', 'file', :all).and_return(Future.resolved(result2))
112
- results = statement.pipeline do |p|
113
- p.execute('one', 'two', :three)
114
- p.execute('four', 'file', :all)
115
- end
116
- results.should eql([result1, result2])
117
- end
118
-
119
- it 'does nothing when statements are executed' do
120
- statement.pipeline { |p| }.should == []
121
- end
122
- end
123
-
124
- describe '#async' do
125
- it 'returns an asynchronous statement' do
126
- statement.async.should equal(async_statement)
127
- end
128
- end
129
-
130
- context 'when exceptions are raised' do
131
- it 'replaces the backtrace of the asynchronous call to make it less confusing' do
132
- error = CqlError.new('Bork')
133
- error.set_backtrace(['Hello', 'World'])
134
- future.stub(:value).and_raise(error)
135
- async_statement.stub(:execute).and_return(future)
136
- begin
137
- statement.execute('SELECT * FROM something')
138
- rescue CqlError => e
139
- e.backtrace.first.should match(%r{/synchronous_prepared_statement.rb:\d+:in `execute'})
140
- end
141
- end
142
-
143
- it 'does not replace the backtrace of non-CqlError errors' do
144
- future.stub(:value).and_raise('Bork')
145
- async_statement.stub(:execute).and_return(future)
146
- begin
147
- statement.execute('SELECT * FROM something')
148
- rescue => e
149
- e.backtrace.first.should_not match(%r{/synchronous_prepared_statement.rb:\d+:in `execute'})
150
- end
151
- end
152
- end
153
- end
154
- end
155
- end
@@ -1,737 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
-
6
- module Cql
7
- describe Promise do
8
- let :promise do
9
- described_class.new
10
- end
11
-
12
- let :future do
13
- promise.future
14
- end
15
-
16
- let :error do
17
- StandardError.new('bork')
18
- end
19
-
20
- describe '#fulfill' do
21
- it 'resolves its future' do
22
- promise.fulfill
23
- future.should be_resolved
24
- end
25
-
26
- it 'raises an error if fulfilled a second time' do
27
- promise.fulfill
28
- expect { promise.fulfill }.to raise_error(FutureError)
29
- end
30
-
31
- it 'raises an error if failed after being fulfilled' do
32
- promise.fulfill
33
- expect { promise.fail(error) }.to raise_error(FutureError)
34
- end
35
-
36
- it 'returns nil' do
37
- promise.fulfill(:foo).should be_nil
38
- end
39
- end
40
-
41
- describe '#fail' do
42
- it 'fails its future' do
43
- promise.fail(error)
44
- future.should be_failed
45
- end
46
-
47
- it 'raises an error if failed a second time' do
48
- promise.fail(error)
49
- expect { promise.fail(error) }.to raise_error(FutureError)
50
- end
51
-
52
- it 'raises an error if fulfilled after being failed' do
53
- promise.fail(error)
54
- expect { promise.fulfill }.to raise_error(FutureError)
55
- end
56
-
57
- it 'returns nil' do
58
- promise.fail(error).should be_nil
59
- end
60
- end
61
-
62
- describe '#observe' do
63
- it 'resolves its future when the specified future is resolved' do
64
- p2 = Promise.new
65
- promise.observe(p2.future)
66
- p2.fulfill
67
- promise.future.should be_resolved
68
- end
69
-
70
- it 'fails its future when the specified future fails' do
71
- p2 = Promise.new
72
- promise.observe(p2.future)
73
- p2.fail(error)
74
- promise.future.should be_failed
75
- end
76
-
77
- it 'silently ignores double fulfillment/failure' do
78
- p2 = Promise.new
79
- promise.observe(p2.future)
80
- promise.fail(error)
81
- p2.fulfill
82
- end
83
-
84
- it 'returns nil' do
85
- promise.observe(Promise.new.future).should be_nil
86
- end
87
- end
88
-
89
- describe '#try' do
90
- it 'fulfills the promise with the result of the block' do
91
- promise.try do
92
- 3 + 4
93
- end
94
- promise.future.value.should == 7
95
- end
96
-
97
- it 'fails the promise when the block raises an error' do
98
- promise.try do
99
- raise error
100
- end
101
- expect { promise.future.value }.to raise_error(/bork/)
102
- end
103
-
104
- it 'calls the block with the specified arguments' do
105
- promise.try(:foo, 3) do |a, b|
106
- a.length + b
107
- end
108
- promise.future.value.should == 6
109
- end
110
-
111
- it 'returns nil' do
112
- promise.try { }.should be_nil
113
- end
114
- end
115
- end
116
-
117
- describe Future do
118
- let :promise do
119
- Promise.new
120
- end
121
-
122
- let :future do
123
- promise.future
124
- end
125
-
126
- let :error do
127
- StandardError.new('bork')
128
- end
129
-
130
- def async(*context, &listener)
131
- Thread.start(*context, &listener)
132
- end
133
-
134
- def delayed(*context, &listener)
135
- async(*context) do |*ctx|
136
- sleep(0.1)
137
- listener.call(*context)
138
- end
139
- end
140
-
141
- describe '#completed?' do
142
- it 'is true when the promise is fulfilled' do
143
- promise.fulfill
144
- future.should be_completed
145
- end
146
-
147
- it 'is true when the promise is failed' do
148
- promise.fail(StandardError.new('bork'))
149
- future.should be_completed
150
- end
151
- end
152
-
153
- describe '#resolved?' do
154
- it 'is true when the promise is fulfilled' do
155
- promise.fulfill('foo')
156
- future.should be_resolved
157
- end
158
-
159
- it 'is true when the promise is fulfilled with something falsy' do
160
- promise.fulfill(nil)
161
- future.should be_resolved
162
- end
163
-
164
- it 'is false when the promise is failed' do
165
- promise.fail(StandardError.new('bork'))
166
- future.should_not be_resolved
167
- end
168
- end
169
-
170
- describe '#failed?' do
171
- it 'is true when the promise is failed' do
172
- promise.fail(error)
173
- future.should be_failed
174
- end
175
-
176
- it 'is false when the promise is fulfilled' do
177
- promise.fulfill
178
- future.should_not be_failed
179
- end
180
- end
181
-
182
- describe '#on_complete' do
183
- context 'registers listeners and' do
184
- it 'notifies all listeners when the promise is fulfilled' do
185
- v1, v2 = nil, nil
186
- future.on_complete { |f| v1 = f.value }
187
- future.on_complete { |f| v2 = f.value }
188
- promise.fulfill('bar')
189
- v1.should == 'bar'
190
- v2.should == 'bar'
191
- end
192
-
193
- it 'notifies all listeners when the promise fails' do
194
- e1, e2 = nil, nil
195
- future.on_complete { |f| begin; f.value; rescue => err; e1 = err; end }
196
- future.on_complete { |f| begin; f.value; rescue => err; e2 = err; end }
197
- future.fail(error)
198
- e1.message.should == error.message
199
- e2.message.should == error.message
200
- end
201
-
202
- it 'notifies all listeners when the promise is fulfilled, even when one raises an error' do
203
- value = nil
204
- future.on_complete { |f| raise 'Blurgh' }
205
- future.on_complete { |f| value = f.value }
206
- promise.fulfill('bar')
207
- value.should == 'bar'
208
- end
209
-
210
- it 'notifies all listeners when the promise fails, even when one raises an error' do
211
- err = nil
212
- future.on_complete { |f| raise 'Blurgh' }
213
- future.on_complete { |f| begin; f.value; rescue => err; e = err; end }
214
- promise.fail(error)
215
- err.message.should == 'bork'
216
- end
217
-
218
- it 'notifies listeners registered after the promise was fulfilled' do
219
- promise.fulfill('bar')
220
- expect { future.on_complete { |v| raise 'blurgh' } }.to_not raise_error
221
- end
222
-
223
- it 'notifies listeners registered after the promise failed' do
224
- promise.fail(error)
225
- expect { future.on_complete { |v| raise 'blurgh' } }.to_not raise_error
226
- end
227
-
228
- it 'returns nil' do
229
- future.on_complete { :foo }.should be_nil
230
- end
231
-
232
- it 'returns nil when the future is already resolved' do
233
- promise.fulfill
234
- future.on_complete { :foo }.should be_nil
235
- end
236
-
237
- it 'returns nil when the future already has failed' do
238
- promise.fail(error)
239
- future.on_complete { :foo }.should be_nil
240
- end
241
- end
242
- end
243
-
244
- describe '#on_value' do
245
- context 'registers listeners and' do
246
- it 'notifies all value listeners when the promise is fulfilled' do
247
- v1, v2 = nil, nil
248
- future.on_value { |v| v1 = v }
249
- future.on_value { |v| v2 = v }
250
- promise.fulfill('bar')
251
- v1.should == 'bar'
252
- v2.should == 'bar'
253
- end
254
-
255
- it 'notifies all listeners even when one raises an error' do
256
- value = nil
257
- future.on_value { |v| raise 'Blurgh' }
258
- future.on_value { |v| value = v }
259
- promise.fulfill('bar')
260
- value.should == 'bar'
261
- end
262
-
263
- it 'notifies listeners registered after the promise was resolved' do
264
- v1, v2 = nil, nil
265
- promise.fulfill('bar')
266
- future.on_value { |v| v1 = v }
267
- future.on_value { |v| v2 = v }
268
- v1.should == 'bar'
269
- v2.should == 'bar'
270
- end
271
-
272
- it 'does not raise any error when the listener raises an error when already resolved' do
273
- promise.fulfill('bar')
274
- expect { future.on_value { |v| raise 'blurgh' } }.to_not raise_error
275
- end
276
-
277
- it 'returns nil' do
278
- future.on_value { :foo }.should be_nil
279
- end
280
-
281
- it 'returns nil when the future is already resolved' do
282
- promise.fulfill
283
- future.on_failure { :foo }.should be_nil
284
- end
285
- end
286
- end
287
-
288
- describe '#on_failure' do
289
- context 'registers listeners and' do
290
- it 'notifies all failure listeners when the promise fails' do
291
- e1, e2 = nil, nil
292
- future.on_failure { |err| e1 = err }
293
- future.on_failure { |err| e2 = err }
294
- promise.fail(error)
295
- e1.message.should eql(error.message)
296
- e2.message.should eql(error.message)
297
- end
298
-
299
- it 'notifies all listeners even if one raises an error' do
300
- e = nil
301
- future.on_failure { |err| raise 'Blurgh' }
302
- future.on_failure { |err| e = err }
303
- promise.fail(error)
304
- e.message.should eql(error.message)
305
- end
306
-
307
- it 'notifies new listeners even when already failed' do
308
- e1, e2 = nil, nil
309
- promise.fail(error)
310
- future.on_failure { |e| e1 = e }
311
- future.on_failure { |e| e2 = e }
312
- e1.message.should eql(error.message)
313
- e2.message.should eql(error.message)
314
- end
315
-
316
- it 'does not raise any error when the listener raises an error when already failed' do
317
- promise.fail(error)
318
- expect { future.on_failure { |e| raise 'Blurgh' } }.to_not raise_error
319
- end
320
-
321
- it 'returns nil' do
322
- future.on_failure { :foo }.should be_nil
323
- end
324
-
325
- it 'returns nil when the future already has failed' do
326
- promise.fail(error)
327
- future.on_failure { :foo }.should be_nil
328
- end
329
- end
330
- end
331
-
332
- describe '#value' do
333
- it 'is nil by default' do
334
- promise.fulfill
335
- future.value.should be_nil
336
- end
337
-
338
- it 'is the object passed to Promise#fulfill' do
339
- obj = 'hello world'
340
- promise.fulfill(obj)
341
- future.value.should equal(obj)
342
- end
343
-
344
- it 'raises the error passed to Promise#fail' do
345
- promise.fail(StandardError.new('bork'))
346
- expect { future.value }.to raise_error(/bork/)
347
- end
348
-
349
- it 'blocks until the promise is completed' do
350
- d = delayed(promise) do |p|
351
- p.fulfill('bar')
352
- end
353
- d.value
354
- future.value.should == 'bar'
355
- end
356
-
357
- it 'blocks on #value until fulfilled, when value is nil' do
358
- d = delayed(promise) do |p|
359
- p.fulfill
360
- end
361
- d.value
362
- future.value.should be_nil
363
- end
364
-
365
- it 'blocks on #value until failed' do
366
- d = delayed(promise) do |p|
367
- p.fail(StandardError.new('bork'))
368
- end
369
- d.value
370
- expect { future.value }.to raise_error('bork')
371
- end
372
-
373
- it 'allows multiple threads to block on #value until fulfilled' do
374
- listeners = Array.new(10) do
375
- async(future) do |f|
376
- f.value
377
- end
378
- end
379
- sleep 0.1
380
- promise.fulfill(:hello)
381
- listeners.map(&:value).should == Array.new(10, :hello)
382
- end
383
- end
384
-
385
- describe '#map' do
386
- context 'returns a new future that' do
387
- it 'will be fulfilled with the result of the given block' do
388
- mapped_value = nil
389
- p = Promise.new
390
- f = p.future.map { |v| v * 2 }
391
- f.on_value { |v| mapped_value = v }
392
- p.fulfill(3)
393
- mapped_value.should == 3 * 2
394
- end
395
-
396
- it 'will be fulfilled with the specified value' do
397
- mapped_value = nil
398
- p = Promise.new
399
- f = p.future.map(7)
400
- f.on_value { |v| mapped_value = v }
401
- p.fulfill(3)
402
- mapped_value.should == 7
403
- end
404
-
405
- it 'will be fulfilled with the result of the given block, even if a value is specified' do
406
- mapped_value = nil
407
- p = Promise.new
408
- f = p.future.map(7) { |v| v * 2 }
409
- f.on_value { |v| mapped_value = v }
410
- p.fulfill(3)
411
- mapped_value.should == 3 * 2
412
- end
413
-
414
- it 'will be fulfilled with nil when neither value nor block is specified' do
415
- mapped_value = 3
416
- p = Promise.new
417
- f = p.future.map
418
- f.on_value { |v| mapped_value = v }
419
- p.fulfill(3)
420
- mapped_value.should be_nil
421
- end
422
-
423
- it 'fails when the original future fails' do
424
- failed = false
425
- p = Promise.new
426
- f = p.future.map { |v| v * 2 }
427
- f.on_failure { failed = true }
428
- p.fail(StandardError.new('Blurgh'))
429
- failed.should be_true
430
- end
431
-
432
- it 'fails when the block raises an error' do
433
- p = Promise.new
434
- f = p.future.map { |v| raise 'blurgh' }
435
- d = delayed do
436
- p.fulfill
437
- end
438
- d.value
439
- expect { f.value }.to raise_error('blurgh')
440
- end
441
- end
442
- end
443
-
444
- describe '#flat_map' do
445
- it 'works like #map, but expects that the block returns a future' do
446
- p = Promise.new
447
- f = p.future.flat_map { |v| Future.resolved(v * 2) }
448
- p.fulfill(3)
449
- f.value.should == 3 * 2
450
- end
451
-
452
- it 'fails when the block raises an error' do
453
- p = Promise.new
454
- f = p.future.flat_map { |v| raise 'Hurgh' }
455
- p.fulfill(3)
456
- expect { f.value }.to raise_error('Hurgh')
457
- end
458
- end
459
-
460
- describe '#recover' do
461
- context 'returns a new future that' do
462
- it 'becomes fulfilled with a value created by the block when the source future fails' do
463
- p = Promise.new
464
- f = p.future.recover { 'foo' }
465
- p.fail(error)
466
- f.value.should == 'foo'
467
- end
468
-
469
- it 'becomes fulfilled with a specfied value when the source future fails' do
470
- p = Promise.new
471
- f = p.future.recover('bar')
472
- p.fail(error)
473
- f.value.should == 'bar'
474
- end
475
-
476
- it 'becomes fulfilled with a value created by the block even when a value is specified when the source future fails' do
477
- p = Promise.new
478
- f = p.future.recover('bar') { 'foo' }
479
- p.fail(error)
480
- f.value.should == 'foo'
481
- end
482
-
483
- it 'becomes fulfilled with nil value when no value nor block is specified and the source future fails' do
484
- p = Promise.new
485
- f = p.future.recover
486
- p.fail(error)
487
- f.value.should be_nil
488
- end
489
-
490
- it 'yields the error to the block' do
491
- p = Promise.new
492
- f = p.future.recover { |e| e.message }
493
- p.fail(error)
494
- f.value.should == error.message
495
- end
496
-
497
- it 'becomes fulfilled with the value of the source future when the source future is fulfilled' do
498
- p = Promise.new
499
- f = p.future.recover { 'foo' }
500
- p.fulfill('bar')
501
- f.value.should == 'bar'
502
- end
503
-
504
- it 'fails with the error raised in the given block' do
505
- p = Promise.new
506
- f = p.future.recover { raise 'snork' }
507
- p.fail(StandardError.new('bork'))
508
- expect { f.value }.to raise_error('snork')
509
- end
510
- end
511
- end
512
-
513
- describe '#fallback' do
514
- context 'returns a new future that' do
515
- it 'is resolved with the value of the fallback future when the source future fails' do
516
- p1 = Promise.new
517
- p2 = Promise.new
518
- f = p1.future.fallback { p2.future }
519
- p1.fail(error)
520
- p2.fulfill('foo')
521
- f.value.should == 'foo'
522
- end
523
-
524
- it 'yields the error to the block' do
525
- p1 = Promise.new
526
- p2 = Promise.new
527
- f = p1.future.fallback do |error|
528
- Future.resolved(error.message)
529
- end
530
- p1.fail(error)
531
- f.value.should == error.message
532
- end
533
-
534
- it 'is resolved with the value of the source future when the source future fullfills' do
535
- p1 = Promise.new
536
- p2 = Promise.new
537
- f = p1.future.fallback { p2.future }
538
- p2.fulfill('bar')
539
- p1.fulfill('foo')
540
- f.value.should == 'foo'
541
- end
542
-
543
- it 'fails when the block raises an error' do
544
- p = Promise.new
545
- f = p.future.fallback { raise 'bork' }
546
- p.fail(StandardError.new('splork'))
547
- expect { f.value }.to raise_error('bork')
548
- end
549
-
550
- it 'fails when the fallback future fails' do
551
- p1 = Promise.new
552
- p2 = Promise.new
553
- f = p1.future.fallback { p2.future }
554
- p2.fail(StandardError.new('bork'))
555
- p1.fail(StandardError.new('fnork'))
556
- expect { f.value }.to raise_error('bork')
557
- end
558
- end
559
- end
560
-
561
- describe '.all' do
562
- context 'returns a new future which' do
563
- it 'is resolved when the source futures are resolved' do
564
- p1 = Promise.new
565
- p2 = Promise.new
566
- f = Future.all(p1.future, p2.future)
567
- p1.fulfill
568
- f.should_not be_resolved
569
- p2.fulfill
570
- f.should be_resolved
571
- end
572
-
573
- it 'resolves when the source futures are resolved' do
574
- sequence = []
575
- p1 = Promise.new
576
- p2 = Promise.new
577
- p3 = Promise.new
578
- f = Future.all(p1.future, p2.future, p3.future)
579
- p1.future.on_value { sequence << 1 }
580
- p2.future.on_value { sequence << 2 }
581
- p3.future.on_value { sequence << 3 }
582
- p2.fulfill
583
- p1.fulfill
584
- p3.fulfill
585
- sequence.should == [2, 1, 3]
586
- end
587
-
588
- it 'returns an array of the values of the source futures, in order ' do
589
- p1 = Promise.new
590
- p2 = Promise.new
591
- p3 = Promise.new
592
- f = Future.all(p1.future, p2.future, p3.future)
593
- p2.fulfill(2)
594
- p1.fulfill(1)
595
- p3.fulfill(3)
596
- f.value.should == [1, 2, 3]
597
- end
598
-
599
- it 'fails if any of the source futures fail' do
600
- p1 = Promise.new
601
- p2 = Promise.new
602
- p3 = Promise.new
603
- p4 = Promise.new
604
- f = Future.all(p1.future, p2.future, p3.future, p4.future)
605
- p2.fulfill
606
- p1.fail(StandardError.new('hurgh'))
607
- p3.fail(StandardError.new('murgasd'))
608
- p4.fulfill
609
- expect { f.value }.to raise_error('hurgh')
610
- f.should be_failed
611
- end
612
-
613
- it 'completes with an empty list when no futures are given' do
614
- Future.all.value.should == []
615
- end
616
- end
617
- end
618
-
619
- describe '.first' do
620
- context 'it returns a new future which' do
621
- it 'is resolved when the first of the source futures is resolved' do
622
- p1 = Promise.new
623
- p2 = Promise.new
624
- p3 = Promise.new
625
- f = Future.first(p1.future, p2.future, p3.future)
626
- p2.fulfill
627
- f.should be_resolved
628
- end
629
-
630
- it 'fullfills with the value of the first source future' do
631
- p1 = Promise.new
632
- p2 = Promise.new
633
- p3 = Promise.new
634
- f = Future.first(p1.future, p2.future, p3.future)
635
- p2.fulfill('foo')
636
- f.value.should == 'foo'
637
- end
638
-
639
- it 'is unaffected by the fullfillment of the other futures' do
640
- p1 = Promise.new
641
- p2 = Promise.new
642
- p3 = Promise.new
643
- f = Future.first(p1.future, p2.future, p3.future)
644
- p2.fulfill
645
- p1.fulfill
646
- p3.fulfill
647
- f.value
648
- end
649
-
650
- it 'is unaffected by a future failing when at least one resolves' do
651
- p1 = Promise.new
652
- p2 = Promise.new
653
- p3 = Promise.new
654
- f = Future.first(p1.future, p2.future, p3.future)
655
- p2.fail(error)
656
- p1.fail(error)
657
- p3.fulfill
658
- expect { f.value }.to_not raise_error
659
- end
660
-
661
- it 'fails if all of the source futures fail' do
662
- p1 = Promise.new
663
- p2 = Promise.new
664
- p3 = Promise.new
665
- f = Future.first(p1.future, p2.future, p3.future)
666
- p2.fail(error)
667
- p1.fail(error)
668
- p3.fail(error)
669
- f.should be_failed
670
- end
671
-
672
- it 'fails with the error of the last future to fail' do
673
- p1 = Promise.new
674
- p2 = Promise.new
675
- p3 = Promise.new
676
- f = Future.first(p1.future, p2.future, p3.future)
677
- p2.fail(StandardError.new('bork2'))
678
- p1.fail(StandardError.new('bork1'))
679
- p3.fail(StandardError.new('bork3'))
680
- expect { f.value }.to raise_error('bork3')
681
- end
682
-
683
- it 'completes with nil when no futures are given' do
684
- Future.first.value.should be_nil
685
- end
686
- end
687
- end
688
-
689
- describe '.resolved' do
690
- context 'returns a future which' do
691
- let :future do
692
- described_class.resolved('hello world')
693
- end
694
-
695
- it 'is resolved' do
696
- future.should be_resolved
697
- end
698
-
699
- it 'calls callbacks immediately' do
700
- value = nil
701
- future.on_value { |v| value = v }
702
- value.should == 'hello world'
703
- end
704
-
705
- it 'does not block on #value' do
706
- future.value.should == 'hello world'
707
- end
708
-
709
- it 'defaults to the value nil' do
710
- described_class.resolved.value.should be_nil
711
- end
712
- end
713
- end
714
-
715
- describe '.failed' do
716
- let :future do
717
- described_class.failed(error)
718
- end
719
-
720
- context 'returns a future which' do
721
- it 'is failed when created' do
722
- future.should be_failed
723
- end
724
-
725
- it 'calls callbacks immediately' do
726
- error = nil
727
- future.on_failure { |e| error = e }
728
- error.message.should == 'bork'
729
- end
730
-
731
- it 'does not block on #value' do
732
- expect { future.value }.to raise_error('bork')
733
- end
734
- end
735
- end
736
- end
737
- end