raktr 0.0.1

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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE.md +29 -0
  4. data/README.md +77 -0
  5. data/Rakefile +53 -0
  6. data/lib/raktr/connection/callbacks.rb +71 -0
  7. data/lib/raktr/connection/error.rb +120 -0
  8. data/lib/raktr/connection/peer_info.rb +90 -0
  9. data/lib/raktr/connection/tls.rb +164 -0
  10. data/lib/raktr/connection.rb +339 -0
  11. data/lib/raktr/global.rb +24 -0
  12. data/lib/raktr/iterator.rb +249 -0
  13. data/lib/raktr/queue.rb +89 -0
  14. data/lib/raktr/tasks/base.rb +57 -0
  15. data/lib/raktr/tasks/delayed.rb +33 -0
  16. data/lib/raktr/tasks/one_off.rb +30 -0
  17. data/lib/raktr/tasks/periodic.rb +58 -0
  18. data/lib/raktr/tasks/persistent.rb +29 -0
  19. data/lib/raktr/tasks.rb +105 -0
  20. data/lib/raktr/version.rb +13 -0
  21. data/lib/raktr.rb +707 -0
  22. data/spec/raktr/connection/tls_spec.rb +348 -0
  23. data/spec/raktr/connection_spec.rb +74 -0
  24. data/spec/raktr/iterator_spec.rb +203 -0
  25. data/spec/raktr/queue_spec.rb +91 -0
  26. data/spec/raktr/tasks/base.rb +8 -0
  27. data/spec/raktr/tasks/delayed_spec.rb +71 -0
  28. data/spec/raktr/tasks/one_off_spec.rb +66 -0
  29. data/spec/raktr/tasks/periodic_spec.rb +57 -0
  30. data/spec/raktr/tasks/persistent_spec.rb +54 -0
  31. data/spec/raktr/tasks_spec.rb +155 -0
  32. data/spec/raktr_spec.rb +20 -0
  33. data/spec/raktr_tls_spec.rb +20 -0
  34. data/spec/spec_helper.rb +17 -0
  35. data/spec/support/fixtures/handlers/echo_client.rb +34 -0
  36. data/spec/support/fixtures/handlers/echo_client_tls.rb +10 -0
  37. data/spec/support/fixtures/handlers/echo_server.rb +12 -0
  38. data/spec/support/fixtures/handlers/echo_server_tls.rb +8 -0
  39. data/spec/support/fixtures/pems/cacert.pem +37 -0
  40. data/spec/support/fixtures/pems/client/cert.pem +37 -0
  41. data/spec/support/fixtures/pems/client/foo-cert.pem +39 -0
  42. data/spec/support/fixtures/pems/client/foo-key.pem +51 -0
  43. data/spec/support/fixtures/pems/client/key.pem +51 -0
  44. data/spec/support/fixtures/pems/server/cert.pem +37 -0
  45. data/spec/support/fixtures/pems/server/key.pem +51 -0
  46. data/spec/support/helpers/paths.rb +23 -0
  47. data/spec/support/helpers/utilities.rb +135 -0
  48. data/spec/support/lib/server_option_parser.rb +29 -0
  49. data/spec/support/lib/servers/runner.rb +13 -0
  50. data/spec/support/lib/servers.rb +133 -0
  51. data/spec/support/servers/echo.rb +14 -0
  52. data/spec/support/servers/echo_tls.rb +22 -0
  53. data/spec/support/servers/echo_unix.rb +14 -0
  54. data/spec/support/servers/echo_unix_tls.rb +22 -0
  55. data/spec/support/shared/connection.rb +696 -0
  56. data/spec/support/shared/raktr.rb +834 -0
  57. data/spec/support/shared/task.rb +21 -0
  58. metadata +140 -0
@@ -0,0 +1,348 @@
1
+ require 'spec_helper'
2
+
3
+ class TLSHandler < Raktr::Connection
4
+ include TLS
5
+
6
+ attr_reader :received_data
7
+ attr_reader :error
8
+
9
+ def initialize( options = {} )
10
+ @options = options
11
+ end
12
+
13
+ def on_close( error )
14
+ @error = error
15
+
16
+ if @options[:on_error]
17
+ @options[:on_error].call error
18
+ end
19
+
20
+ @raktr.stop
21
+ end
22
+
23
+ def on_read( data )
24
+ (@received_data ||= '' ) << data
25
+
26
+ return if !@options[:on_read]
27
+ @options[:on_read].call data
28
+ end
29
+
30
+ def on_connect
31
+ start_tls @options
32
+ end
33
+
34
+ end
35
+
36
+ describe Raktr::Connection::TLS do
37
+ before :all do
38
+ @host, @port = Servers.start( :echo_tls )
39
+
40
+ if Raktr.supports_unix_sockets?
41
+ _, port = Servers.start( :echo_unix_tls )
42
+ @unix_socket = port_to_socket( port )
43
+ end
44
+ end
45
+
46
+ before :each do
47
+ @accept_q = Queue.new
48
+ @accepted = nil
49
+ end
50
+
51
+ let(:unix_socket) { unix_connect( @unix_socket ) }
52
+ let(:unix_server_socket) { unix_server( port_to_socket( Servers.available_port ) ) }
53
+
54
+ let(:echo_client) { tcp_socket }
55
+ let(:echo_client_handler) { EchoClientTLS.new }
56
+
57
+ let(:peer_client_socket) { tcp_ssl_connect( host, port ) }
58
+ let(:peer_server_socket) do
59
+ s = tcp_ssl_server( host, port )
60
+ Thread.new do
61
+ begin
62
+ @accept_q << s.accept
63
+ rescue => e
64
+ p e
65
+ end
66
+ end
67
+ s
68
+ end
69
+ let(:accepted) { @accepted ||= @accept_q.pop }
70
+
71
+ let(:client_socket) { tcp_socket }
72
+ let(:server_socket) { tcp_server( host, port ) }
73
+
74
+ let(:connection) { TLSHandler.new }
75
+ let(:server_handler) { proc { TLSHandler.new } }
76
+ let(:raktr) { Raktr.new }
77
+
78
+ let(:client_valid_ssl_options) do
79
+ {
80
+ ca: pems_path + '/cacert.pem',
81
+ private_key: pems_path + '/client/key.pem',
82
+ certificate: pems_path + '/client/cert.pem'
83
+ }
84
+ end
85
+ let(:client_invalid_ssl_options) do
86
+ {
87
+ ca: pems_path + '/cacert.pem',
88
+ private_key: pems_path + '/client/foo-key.pem',
89
+ certificate: pems_path + '/client/foo-cert.pem'
90
+ }
91
+ end
92
+
93
+ let(:server_valid_ssl_options) do
94
+ {
95
+ ca: pems_path + '/cacert.pem',
96
+ private_key: pems_path + '/server/key.pem',
97
+ certificate: pems_path + '/server/cert.pem'
98
+ }
99
+ end
100
+
101
+ it_should_behave_like 'Raktr::Connection'
102
+
103
+ context '#start_tls' do
104
+ let(:host) { '127.0.0.1' }
105
+ let(:port) { Servers.available_port }
106
+ let(:data) { "stuff\n" }
107
+
108
+ context 'when listening for a client' do
109
+ let(:client) do
110
+ tcp_ssl_connect( host, port, client_ssl_options )
111
+ end
112
+
113
+ context 'without requiring SSL authentication' do
114
+ let(:server_ssl_options) { {} }
115
+
116
+ context 'and no options have been provided' do
117
+ let(:client_ssl_options) { {} }
118
+
119
+ it 'connects successfully' do
120
+ received_data = nil
121
+ options = server_ssl_options.merge(
122
+ on_read: proc do |received|
123
+ received_data = received
124
+ end
125
+ )
126
+
127
+ raktr.run_in_thread
128
+
129
+ raktr.listen( host, port, TLSHandler, options )
130
+
131
+ client.write data
132
+ sleep 1
133
+
134
+ raktr.stop
135
+ raktr.wait rescue Raktr::Error::NotRunning
136
+
137
+ expect(received_data).to eq data
138
+ end
139
+ end
140
+
141
+ context 'and options have been provided' do
142
+ let(:client_ssl_options) { client_valid_ssl_options }
143
+
144
+ it "passes #{Raktr::Connection::Error::SSL} to #on_error" do
145
+ error = nil
146
+
147
+ options = server_ssl_options.merge(
148
+ on_error: proc do |e|
149
+ error ||= e
150
+ end
151
+ )
152
+
153
+ raktr.run_in_thread
154
+
155
+ raktr.listen( host, port, TLSHandler, options )
156
+
157
+ client_error = nil
158
+ begin
159
+ client
160
+ rescue => e
161
+ client_error = e
162
+ end
163
+
164
+ [OpenSSL::SSL::SSLError, Errno::ECONNRESET].should include client_error.class
165
+
166
+ raktr.wait rescue Raktr::Error::NotRunning
167
+
168
+ error.should be_kind_of Raktr::Connection::Error::SSL
169
+ end
170
+ end
171
+ end
172
+
173
+ context 'while requiring SSL authentication' do
174
+ let(:server_ssl_options) { server_valid_ssl_options }
175
+
176
+ context 'and options have been provided' do
177
+ context 'and are valid' do
178
+ let(:client_ssl_options) { client_valid_ssl_options }
179
+
180
+ it 'connects successfully' do
181
+ received_data = nil
182
+ options = server_ssl_options.merge(
183
+ on_read: proc do |received|
184
+ received_data = received
185
+ end
186
+ )
187
+
188
+ raktr.run_in_thread
189
+
190
+ raktr.listen( host, port, TLSHandler, options )
191
+
192
+ client.write data
193
+
194
+ sleep 0.1 while !received_data
195
+ received_data.should == data
196
+ end
197
+ end
198
+
199
+ context 'and are invalid' do
200
+ let(:client_ssl_options) { client_invalid_ssl_options }
201
+
202
+ it "passes #{Raktr::Connection::Error::SSL} to #on_error" do
203
+ error = nil
204
+
205
+ options = server_ssl_options.merge(
206
+ on_error: proc do |e|
207
+ error ||= e
208
+ end
209
+ )
210
+
211
+ raktr.run_in_thread
212
+ raktr.listen( host, port, TLSHandler, options )
213
+
214
+ client_error = nil
215
+ begin
216
+ client
217
+ rescue => e
218
+ client_error = e
219
+ end
220
+
221
+ [OpenSSL::SSL::SSLError, Errno::ECONNRESET].should include client_error.class
222
+
223
+ raktr.wait rescue Raktr::Error::NotRunning
224
+
225
+ error.should be_kind_of Raktr::Connection::Error::SSL
226
+ end
227
+ end
228
+ end
229
+
230
+ context 'and no options have been provided' do
231
+ let(:client_ssl_options) { {} }
232
+
233
+ it "passes #{Raktr::Connection::Error::SSL} to #on_error" do
234
+ error = nil
235
+
236
+ options = server_ssl_options.merge(
237
+ on_error: proc do |e|
238
+ error ||= e
239
+ end
240
+ )
241
+
242
+ raktr.run_in_thread
243
+
244
+ raktr.listen( host, port, TLSHandler, options )
245
+
246
+ client_error = nil
247
+ begin
248
+ client
249
+ rescue => e
250
+ client_error = e
251
+ end
252
+
253
+ [OpenSSL::SSL::SSLError, Errno::ECONNRESET].should include client_error.class
254
+
255
+ raktr.wait rescue Raktr::Error::NotRunning
256
+
257
+ error.should be_kind_of Raktr::Connection::Error::SSL
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ context 'when connecting to a server' do
264
+ let(:server) do
265
+ s = tcp_ssl_server( host, port, server_ssl_options )
266
+ Thread.new do
267
+ begin
268
+ @accept_q << s.accept
269
+ rescue => e
270
+ # ap e
271
+ end
272
+ end
273
+ s
274
+ end
275
+
276
+ before :each do
277
+ server
278
+ end
279
+
280
+ context 'that does not require SSL authentication' do
281
+ let(:server_ssl_options) { {} }
282
+
283
+ context 'and no options have been provided' do
284
+ it 'connects successfully' do
285
+ received = nil
286
+ Thread.new do
287
+ received = accepted.gets
288
+ raktr.stop
289
+ end
290
+
291
+ raktr.run do
292
+ connection = raktr.connect( host, port, TLSHandler )
293
+ connection.write data
294
+ end
295
+
296
+ received.should == data
297
+ end
298
+ end
299
+ end
300
+
301
+ context 'that requires SSL authentication' do
302
+ let(:server_ssl_options) { server_valid_ssl_options }
303
+
304
+ context 'and no options have been provided' do
305
+ it "passes #{Raktr::Connection::Error} to #on_error" do
306
+ connection = nil
307
+ raktr.run do
308
+ connection = raktr.connect( host, port, TLSHandler )
309
+ end
310
+
311
+ connection.error.should be_kind_of Raktr::Connection::Error
312
+ end
313
+ end
314
+
315
+ context 'and options have been provided' do
316
+ context 'and are valid' do
317
+ it 'connects successfully' do
318
+ received = nil
319
+ t = Thread.new do
320
+ received = accepted.gets
321
+ raktr.stop
322
+ end
323
+
324
+ raktr.run do
325
+ connection = raktr.connect( host, port, TLSHandler, client_valid_ssl_options )
326
+ connection.write data
327
+ end
328
+
329
+ sleep 1
330
+ expect(received).to eq data
331
+ end
332
+ end
333
+
334
+ context 'and are invalid' do
335
+ it "passes #{Raktr::Connection::Error} to #on_error" do
336
+ connection = nil
337
+ raktr.run do
338
+ connection = raktr.connect( host, port, TLSHandler, client_invalid_ssl_options )
339
+ end
340
+
341
+ connection.error.should be_kind_of Raktr::Connection::Error
342
+ end
343
+ end
344
+ end
345
+ end
346
+ end
347
+ end
348
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ require 'spec_helper'
4
+
5
+ class Handler < Raktr::Connection
6
+ attr_reader :received_data
7
+ attr_reader :error
8
+
9
+ def initialize( options = {} )
10
+ @options = options
11
+ end
12
+
13
+ def on_close( error )
14
+ @error = error
15
+
16
+ if @options[:on_error]
17
+ @options[:on_error].call error
18
+ end
19
+
20
+ @raktr.stop
21
+ end
22
+
23
+ def on_read( data )
24
+ (@received_data ||= '' ) << data
25
+
26
+ return if !@options[:on_read]
27
+ @options[:on_read].call data
28
+ end
29
+
30
+ end
31
+
32
+ describe Raktr::Connection do
33
+ before :all do
34
+ @host, @port = Servers.start( :echo )
35
+
36
+ if Raktr.supports_unix_sockets?
37
+ _, port = Servers.start( :echo_unix )
38
+ @unix_socket = port_to_socket( port )
39
+ end
40
+ end
41
+
42
+ before :each do
43
+ @accept_q = Queue.new
44
+ @accepted = nil
45
+ end
46
+
47
+ let(:unix_socket) { unix_connect( @unix_socket ) }
48
+ let(:unix_server_socket) { unix_server( port_to_socket( Servers.available_port ) ) }
49
+
50
+ let(:echo_client) { tcp_socket }
51
+ let(:echo_client_handler) { EchoClient.new }
52
+
53
+ let(:peer_client_socket) { tcp_connect( host, port ) }
54
+ let(:peer_server_socket) do
55
+ s = tcp_server( host, port )
56
+ Thread.new do
57
+ begin
58
+ @accept_q << s.accept
59
+ rescue => e
60
+ ap e
61
+ end
62
+ end
63
+ s
64
+ end
65
+ let(:accepted) { @accepted ||= @accept_q.pop }
66
+
67
+ let(:client_socket) { tcp_socket }
68
+ let(:server_socket) { tcp_server( host, port ) }
69
+
70
+ let(:connection) { Handler.new }
71
+ let(:server_handler) { proc { Handler.new } }
72
+
73
+ it_should_behave_like 'Raktr::Connection'
74
+ end
@@ -0,0 +1,203 @@
1
+ require 'spec_helper'
2
+
3
+ describe Raktr::Iterator do
4
+
5
+ def get_iterator
6
+ described_class.new raktr, list, concurrency
7
+ end
8
+
9
+ def get_raktr
10
+ Raktr.new
11
+ end
12
+
13
+ let(:raktr) { get_raktr }
14
+ let(:list) { %w(one two three four) }
15
+ let(:concurrency) { list.size }
16
+ subject { get_iterator }
17
+
18
+ describe '#initialize' do
19
+ context 'when the list does not respond to #to_a' do
20
+ let(:list) { 'stuff' }
21
+
22
+ it "raises #{ArgumentError}" do
23
+ expect { subject }.to raise_error ArgumentError
24
+ end
25
+ end
26
+
27
+ context 'when the concurrency is' do
28
+ context '0' do
29
+ let(:concurrency) { 0 }
30
+
31
+ it "raises #{ArgumentError}" do
32
+ expect { subject }.to raise_error ArgumentError
33
+ end
34
+ end
35
+
36
+ context 'less than 0' do
37
+ let(:concurrency) { -1 }
38
+
39
+ it "raises #{ArgumentError}" do
40
+ expect { subject }.to raise_error ArgumentError
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ describe '#raktr' do
47
+ it 'returns the associated Reactor' do
48
+ subject.raktr.should == raktr
49
+ end
50
+ end
51
+
52
+ describe '#concurrency' do
53
+ let(:concurrency){ 3 }
54
+ it 'returns the configured Reactor' do
55
+ subject.concurrency.should == concurrency
56
+ end
57
+ end
58
+
59
+ describe '#concurrency=' do
60
+ it 'sets the iterator concurrency' do
61
+ runner = proc do |concurrency|
62
+ start = nil
63
+ finish = nil
64
+
65
+ iter = described_class.new( get_raktr, list, concurrency )
66
+ iter.concurrency = concurrency
67
+
68
+ iter.raktr.run do
69
+ iter.each do |item, iterator|
70
+ start ||= Time.now
71
+
72
+ iter.raktr.delay 1 do
73
+ if item == list.last
74
+ finish = Time.now
75
+ iter.raktr.stop
76
+ end
77
+
78
+ iterator.next
79
+ end
80
+ end
81
+ end
82
+
83
+ finish - start
84
+ end
85
+
86
+ high_concurrency = list.size
87
+ low_concurrency = 1
88
+
89
+ high_concurrency_time, low_concurrency_time =
90
+ runner.call( high_concurrency ), runner.call( low_concurrency )
91
+
92
+ low_concurrency_time.should > high_concurrency_time
93
+
94
+ (low_concurrency_time - high_concurrency_time).to_i.should ==
95
+ high_concurrency - low_concurrency
96
+ end
97
+
98
+ context 'when it is larger than the list size' do
99
+ let(:concurrency){ 30 }
100
+
101
+ it 'does stuff' do
102
+ iterated = []
103
+
104
+ raktr.run do
105
+ subject.each do |item, iterator|
106
+ iterated << item
107
+
108
+ raktr.delay 1 do
109
+ raktr.stop if item == list.last
110
+ iterator.next
111
+ end
112
+ end
113
+ end
114
+
115
+ list.should == iterated
116
+ end
117
+ end
118
+ end
119
+
120
+ describe '#each' do
121
+ it 'iterates over the list' do
122
+ iterated = []
123
+
124
+ raktr.run do
125
+ subject.each do |item, iterator|
126
+ iterated << item
127
+
128
+ raktr.stop if item == list.last
129
+ raktr.delay 1 do
130
+ iterator.next
131
+ end
132
+ end
133
+ end
134
+
135
+ list.should == iterated
136
+ end
137
+
138
+ context 'when an \'after\' proc has been provided' do
139
+ it 'is called when the iteration is complete' do
140
+ iterated = []
141
+
142
+ raktr.run do
143
+ subject.each(
144
+ proc do |item, iterator|
145
+ iterated << item
146
+ raktr.delay 1 do
147
+ iterator.next
148
+ end
149
+ end,
150
+ proc do
151
+ raktr.stop
152
+ end
153
+ )
154
+ end
155
+
156
+ list.should == iterated
157
+ end
158
+ end
159
+ end
160
+
161
+ describe '#map' do
162
+ it 'collects the results of each iteration' do
163
+ results = nil
164
+
165
+ raktr.run do
166
+ subject.map(
167
+ proc do |string, iterator|
168
+ raktr.delay 1 do
169
+ iterator.return( string.size )
170
+ end
171
+ end,
172
+ proc do |res|
173
+ results = res
174
+ raktr.stop
175
+ end
176
+ )
177
+ end
178
+
179
+ results.should == list.map(&:size)
180
+ end
181
+ end
182
+
183
+ describe '#inject' do
184
+ it 'injects the results of the iteration into the given object' do
185
+ results = nil
186
+
187
+ raktr.run do
188
+ subject.inject( {},
189
+ proc do |hash, string, iterator|
190
+ hash.merge!( string => string.size )
191
+ iterator.return( hash )
192
+ end,
193
+ proc do |res|
194
+ results = res
195
+ raktr.stop
196
+ end
197
+ )
198
+ end
199
+
200
+ results.should == list.inject({}) { |h, string| h.merge( string => string.size ) }
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe Raktr::Queue do
4
+ let(:raktr) { Raktr.new }
5
+ subject { described_class.new raktr }
6
+
7
+ describe '#initialize' do
8
+ it 'sets the associated raktr' do
9
+ subject.raktr.should == raktr
10
+ end
11
+ end
12
+
13
+ describe '#pop' do
14
+ context 'when the queue is not empty' do
15
+ it 'passes the next item to the block' do
16
+ passed_item = nil
17
+
18
+ raktr.run do
19
+ subject << :my_item
20
+ subject.pop do |item|
21
+ passed_item = item
22
+ raktr.stop
23
+ end
24
+ end
25
+
26
+ passed_item.should == :my_item
27
+ end
28
+ end
29
+
30
+ context 'when the queue is empty' do
31
+ it 'assigns a block to handle new items' do
32
+ passed_item = nil
33
+
34
+ raktr.run do
35
+ subject.pop do |item|
36
+ passed_item = item
37
+ raktr.stop
38
+ end
39
+
40
+ subject << :my_item
41
+ end
42
+
43
+ passed_item.should == :my_item
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '#empty?' do
49
+ context 'when the queue is empty' do
50
+ it 'returns true' do
51
+ subject.should be_empty
52
+ end
53
+ end
54
+
55
+ context 'when the queue is not empty' do
56
+ it 'returns false' do
57
+ raktr.run_block do
58
+ subject << nil
59
+ subject.should_not be_empty
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ describe '#size' do
66
+ it 'returns the queue size' do
67
+ raktr.run_block do
68
+ 2.times { |i| subject << i }
69
+ subject.size.should == 2
70
+ end
71
+ end
72
+ end
73
+
74
+ describe '#num_waiting' do
75
+ context 'when no jobs are available to handle new items' do
76
+ it 'returns 0' do
77
+ subject.num_waiting.should == 0
78
+ end
79
+ end
80
+
81
+ context 'when there are jobs waiting to handle new items' do
82
+ it 'returns a count' do
83
+ raktr.run_block do
84
+ 3.times { subject.pop{} }
85
+ subject.num_waiting.should == 3
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ end