arachni-reactor 0.1.0.beta1

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 +15 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.md +29 -0
  4. data/README.md +79 -0
  5. data/Rakefile +53 -0
  6. data/lib/arachni/reactor.rb +679 -0
  7. data/lib/arachni/reactor/connection.rb +302 -0
  8. data/lib/arachni/reactor/connection/callbacks.rb +73 -0
  9. data/lib/arachni/reactor/connection/error.rb +114 -0
  10. data/lib/arachni/reactor/connection/peer_info.rb +92 -0
  11. data/lib/arachni/reactor/connection/tls.rb +107 -0
  12. data/lib/arachni/reactor/global.rb +26 -0
  13. data/lib/arachni/reactor/iterator.rb +251 -0
  14. data/lib/arachni/reactor/queue.rb +91 -0
  15. data/lib/arachni/reactor/tasks.rb +107 -0
  16. data/lib/arachni/reactor/tasks/base.rb +59 -0
  17. data/lib/arachni/reactor/tasks/delayed.rb +35 -0
  18. data/lib/arachni/reactor/tasks/one_off.rb +30 -0
  19. data/lib/arachni/reactor/tasks/periodic.rb +60 -0
  20. data/lib/arachni/reactor/tasks/persistent.rb +31 -0
  21. data/lib/arachni/reactor/version.rb +15 -0
  22. data/spec/arachni/reactor/connection/tls_spec.rb +332 -0
  23. data/spec/arachni/reactor/connection_spec.rb +58 -0
  24. data/spec/arachni/reactor/iterator_spec.rb +203 -0
  25. data/spec/arachni/reactor/queue_spec.rb +91 -0
  26. data/spec/arachni/reactor/tasks/base.rb +8 -0
  27. data/spec/arachni/reactor/tasks/delayed_spec.rb +54 -0
  28. data/spec/arachni/reactor/tasks/one_off_spec.rb +51 -0
  29. data/spec/arachni/reactor/tasks/periodic_spec.rb +40 -0
  30. data/spec/arachni/reactor/tasks/persistent_spec.rb +39 -0
  31. data/spec/arachni/reactor/tasks_spec.rb +136 -0
  32. data/spec/arachni/reactor_spec.rb +20 -0
  33. data/spec/arachni/reactor_tls_spec.rb +20 -0
  34. data/spec/spec_helper.rb +16 -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 +117 -0
  48. data/spec/support/lib/server_option_parser.rb +29 -0
  49. data/spec/support/lib/servers.rb +133 -0
  50. data/spec/support/lib/servers/runner.rb +13 -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 +778 -0
  56. data/spec/support/shared/reactor.rb +785 -0
  57. data/spec/support/shared/task.rb +21 -0
  58. metadata +141 -0
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ require 'spec_helper'
4
+
5
+ class Handler < Arachni::Reactor::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
+ @reactor.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 Arachni::Reactor::Connection do
33
+ before :all do
34
+ @host, @port = Servers.start( :echo )
35
+
36
+ if Arachni::Reactor.supports_unix_sockets?
37
+ _, port = Servers.start( :echo_unix )
38
+ @unix_socket = port_to_socket( port )
39
+ end
40
+ end
41
+
42
+ let(:unix_socket) { unix_connect( @unix_socket ) }
43
+ let(:unix_server_socket) { unix_server( port_to_socket( Servers.available_port ) ) }
44
+
45
+ let(:echo_client) { tcp_connect( @host, @port ) }
46
+ let(:echo_client_handler) { EchoClient.new }
47
+
48
+ let(:peer_client_socket) { tcp_connect( host, port ) }
49
+ let(:peer_server_socket) { tcp_server( host, port ) }
50
+
51
+ let(:client_socket) { tcp_connect( host, port ) }
52
+ let(:server_socket) { tcp_server( host, port ) }
53
+
54
+ let(:connection) { Handler.new }
55
+ let(:server_handler) { proc { Handler.new } }
56
+
57
+ it_should_behave_like 'Arachni::Reactor::Connection'
58
+ end
@@ -0,0 +1,203 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Reactor::Iterator do
4
+
5
+ def get_iterator
6
+ described_class.new reactor, list, concurrency
7
+ end
8
+
9
+ def get_reactor
10
+ Arachni::Reactor.new
11
+ end
12
+
13
+ let(:reactor) { get_reactor }
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 '#reactor' do
47
+ it 'returns the associated Reactor' do
48
+ subject.reactor.should == reactor
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_reactor, list, concurrency )
66
+ iter.concurrency = concurrency
67
+
68
+ iter.reactor.run do
69
+ iter.each do |item, iterator|
70
+ start ||= Time.now
71
+
72
+ iter.reactor.delay 1 do
73
+ if item == list.last
74
+ finish = Time.now
75
+ iter.reactor.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
+ reactor.run do
105
+ subject.each do |item, iterator|
106
+ iterated << item
107
+
108
+ reactor.delay 1 do
109
+ reactor.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
+ reactor.run do
125
+ subject.each do |item, iterator|
126
+ iterated << item
127
+
128
+ reactor.stop if item == list.last
129
+ reactor.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
+ reactor.run do
143
+ subject.each(
144
+ proc do |item, iterator|
145
+ iterated << item
146
+ reactor.delay 1 do
147
+ iterator.next
148
+ end
149
+ end,
150
+ proc do
151
+ reactor.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
+ reactor.run do
166
+ subject.map(
167
+ proc do |string, iterator|
168
+ reactor.delay 1 do
169
+ iterator.return( string.size )
170
+ end
171
+ end,
172
+ proc do |res|
173
+ results = res
174
+ reactor.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
+ reactor.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
+ reactor.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 Arachni::Reactor::Queue do
4
+ let(:reactor) { Arachni::Reactor.new }
5
+ subject { described_class.new reactor }
6
+
7
+ describe '#initialize' do
8
+ it 'sets the associated reactor' do
9
+ subject.reactor.should == reactor
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
+ reactor.run do
19
+ subject << :my_item
20
+ subject.pop do |item|
21
+ passed_item = item
22
+ reactor.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
+ reactor.run do
35
+ subject.pop do |item|
36
+ passed_item = item
37
+ reactor.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
+ reactor.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
+ reactor.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
+ reactor.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
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Reactor::Tasks::Base do
4
+ it_should_behave_like 'Arachni::Reactor::Tasks::Base'
5
+
6
+ subject { described_class.new{} }
7
+ end
8
+
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Reactor::Tasks::Delayed do
4
+ it_should_behave_like 'Arachni::Reactor::Tasks::Base'
5
+
6
+ let(:list) { Arachni::Reactor::Tasks.new }
7
+ let(:interval) { 0.25 }
8
+ subject { described_class.new( interval ){} }
9
+
10
+ describe '#initialize' do
11
+ context 'when the interval is <= 0' do
12
+ it "raises #{ArgumentError}" do
13
+ expect { described_class.new( 0 ){} }.to raise_error ArgumentError
14
+ expect { described_class.new( -1 ){} }.to raise_error ArgumentError
15
+ end
16
+ end
17
+ end
18
+
19
+ describe '#interval' do
20
+ it 'returns the configured interval' do
21
+ subject.interval.should == interval
22
+ end
23
+ end
24
+
25
+ describe '#call' do
26
+ context 'at the next interval' do
27
+ it 'calls the task' do
28
+ called = 0
29
+ task = described_class.new( interval ) do
30
+ called += 1
31
+ end
32
+
33
+ list << task
34
+
35
+ time = Time.now
36
+ task.call while called < 1
37
+
38
+ (Time.now - time).round(2).should == 0.25
39
+ end
40
+
41
+ it 'calls #done' do
42
+ called = 0
43
+ task = described_class.new( interval ) do
44
+ called += 1
45
+ end
46
+
47
+ list << task
48
+
49
+ task.should receive(:done)
50
+ task.call while called < 1
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arachni::Reactor::Tasks::OneOff do
4
+ it_should_behave_like 'Arachni::Reactor::Tasks::Base'
5
+
6
+ let(:list) { Arachni::Reactor::Tasks.new }
7
+ subject { described_class.new{} }
8
+
9
+ describe '#initialize' do
10
+ context 'when no task have been given' do
11
+ it "raises #{ArgumentError}" do
12
+ expect { described_class.new }.to raise_error ArgumentError
13
+ end
14
+ end
15
+ end
16
+
17
+ describe '#call' do
18
+ it 'calls the given task' do
19
+ callable = proc {}
20
+ callable.should receive(:call)
21
+
22
+ task = described_class.new(&callable)
23
+ list << task
24
+
25
+ task.call
26
+ end
27
+
28
+ it 'passes the task to it' do
29
+ callable = proc {}
30
+ task = described_class.new(&callable)
31
+
32
+ callable.should receive(:call).with(task)
33
+
34
+ list << task
35
+
36
+ task.call
37
+ end
38
+
39
+ it 'calls #done' do
40
+ callable = proc {}
41
+ task = described_class.new(&callable)
42
+
43
+ callable.should receive(:call).with(task)
44
+
45
+ list << task
46
+
47
+ task.should receive(:done)
48
+ task.call
49
+ end
50
+ end
51
+ end