raktr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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