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.
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