cql-rb 2.0.0.pre0 → 2.0.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.
- checksums.yaml +4 -4
- data/README.md +14 -2
- data/lib/cql.rb +8 -3
- data/lib/cql/client.rb +21 -356
- data/lib/cql/client/authenticators.rb +70 -0
- data/lib/cql/client/batch.rb +54 -0
- data/lib/cql/client/{asynchronous_client.rb → client.rb} +241 -6
- data/lib/cql/client/connector.rb +3 -2
- data/lib/cql/client/{asynchronous_prepared_statement.rb → prepared_statement.rb} +103 -0
- data/lib/cql/protocol.rb +1 -2
- data/lib/cql/protocol/cql_byte_buffer.rb +285 -0
- data/lib/cql/protocol/cql_protocol_handler.rb +3 -3
- data/lib/cql/protocol/frame_decoder.rb +3 -3
- data/lib/cql/protocol/frame_encoder.rb +2 -2
- data/lib/cql/protocol/request.rb +0 -2
- data/lib/cql/protocol/requests/auth_response_request.rb +2 -2
- data/lib/cql/protocol/requests/batch_request.rb +10 -10
- data/lib/cql/protocol/requests/credentials_request.rb +2 -2
- data/lib/cql/protocol/requests/execute_request.rb +13 -13
- data/lib/cql/protocol/requests/options_request.rb +2 -2
- data/lib/cql/protocol/requests/prepare_request.rb +2 -2
- data/lib/cql/protocol/requests/query_request.rb +13 -13
- data/lib/cql/protocol/requests/register_request.rb +2 -2
- data/lib/cql/protocol/requests/startup_request.rb +2 -2
- data/lib/cql/protocol/response.rb +2 -4
- data/lib/cql/protocol/responses/auth_challenge_response.rb +2 -2
- data/lib/cql/protocol/responses/auth_success_response.rb +2 -2
- data/lib/cql/protocol/responses/authenticate_response.rb +2 -2
- data/lib/cql/protocol/responses/detailed_error_response.rb +15 -15
- data/lib/cql/protocol/responses/error_response.rb +4 -4
- data/lib/cql/protocol/responses/event_response.rb +3 -3
- data/lib/cql/protocol/responses/prepared_result_response.rb +4 -4
- data/lib/cql/protocol/responses/raw_rows_result_response.rb +1 -1
- data/lib/cql/protocol/responses/ready_response.rb +1 -1
- data/lib/cql/protocol/responses/result_response.rb +3 -3
- data/lib/cql/protocol/responses/rows_result_response.rb +22 -22
- data/lib/cql/protocol/responses/schema_change_event_response.rb +2 -2
- data/lib/cql/protocol/responses/schema_change_result_response.rb +2 -2
- data/lib/cql/protocol/responses/set_keyspace_result_response.rb +2 -2
- data/lib/cql/protocol/responses/status_change_event_response.rb +2 -2
- data/lib/cql/protocol/responses/supported_response.rb +2 -2
- data/lib/cql/protocol/responses/void_result_response.rb +1 -1
- data/lib/cql/protocol/type_converter.rb +78 -81
- data/lib/cql/time_uuid.rb +6 -0
- data/lib/cql/uuid.rb +2 -1
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/batch_spec.rb +8 -8
- data/spec/cql/client/{asynchronous_client_spec.rb → client_spec.rb} +162 -0
- data/spec/cql/client/connector_spec.rb +13 -3
- data/spec/cql/client/{asynchronous_prepared_statement_spec.rb → prepared_statement_spec.rb} +148 -1
- data/spec/cql/client/request_runner_spec.rb +2 -2
- data/spec/cql/protocol/cql_byte_buffer_spec.rb +895 -0
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +1 -1
- data/spec/cql/protocol/frame_decoder_spec.rb +14 -14
- data/spec/cql/protocol/frame_encoder_spec.rb +7 -7
- data/spec/cql/protocol/requests/auth_response_request_spec.rb +4 -4
- data/spec/cql/protocol/requests/batch_request_spec.rb +21 -21
- data/spec/cql/protocol/requests/credentials_request_spec.rb +2 -2
- data/spec/cql/protocol/requests/execute_request_spec.rb +13 -13
- data/spec/cql/protocol/requests/options_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/prepare_request_spec.rb +2 -2
- data/spec/cql/protocol/requests/query_request_spec.rb +13 -13
- data/spec/cql/protocol/requests/register_request_spec.rb +2 -2
- data/spec/cql/protocol/requests/startup_request_spec.rb +4 -4
- data/spec/cql/protocol/responses/auth_challenge_response_spec.rb +5 -5
- data/spec/cql/protocol/responses/auth_success_response_spec.rb +5 -5
- data/spec/cql/protocol/responses/authenticate_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/detailed_error_response_spec.rb +15 -15
- data/spec/cql/protocol/responses/error_response_spec.rb +5 -5
- data/spec/cql/protocol/responses/event_response_spec.rb +8 -8
- data/spec/cql/protocol/responses/prepared_result_response_spec.rb +7 -7
- data/spec/cql/protocol/responses/raw_rows_result_response_spec.rb +1 -1
- data/spec/cql/protocol/responses/ready_response_spec.rb +2 -2
- data/spec/cql/protocol/responses/result_response_spec.rb +16 -16
- data/spec/cql/protocol/responses/rows_result_response_spec.rb +21 -21
- data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +2 -2
- data/spec/cql/protocol/responses/status_change_event_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/supported_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/void_result_response_spec.rb +2 -2
- data/spec/cql/protocol/type_converter_spec.rb +25 -13
- data/spec/cql/time_uuid_spec.rb +17 -4
- data/spec/cql/uuid_spec.rb +5 -1
- data/spec/integration/protocol_spec.rb +48 -42
- data/spec/spec_helper.rb +0 -1
- metadata +27 -39
- data/lib/cql/byte_buffer.rb +0 -177
- data/lib/cql/client/synchronous_client.rb +0 -79
- data/lib/cql/client/synchronous_prepared_statement.rb +0 -63
- data/lib/cql/future.rb +0 -515
- data/lib/cql/io.rb +0 -15
- data/lib/cql/io/connection.rb +0 -220
- data/lib/cql/io/io_reactor.rb +0 -349
- data/lib/cql/protocol/decoding.rb +0 -187
- data/lib/cql/protocol/encoding.rb +0 -114
- data/spec/cql/byte_buffer_spec.rb +0 -337
- data/spec/cql/client/synchronous_client_spec.rb +0 -170
- data/spec/cql/client/synchronous_prepared_statement_spec.rb +0 -155
- data/spec/cql/future_spec.rb +0 -737
- data/spec/cql/io/connection_spec.rb +0 -484
- data/spec/cql/io/io_reactor_spec.rb +0 -402
- data/spec/cql/protocol/decoding_spec.rb +0 -547
- data/spec/cql/protocol/encoding_spec.rb +0 -386
- data/spec/integration/io_spec.rb +0 -283
- 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
|
data/spec/cql/future_spec.rb
DELETED
@@ -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
|