blondy-dhcpd 0.0.1 → 0.0.2

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.
@@ -4,21 +4,69 @@ module Blondy
4
4
  module DHCPD
5
5
  describe 'Dispatcher' do
6
6
  subject(:dispatcher) {Dispatcher}
7
+ let(:pool) {Pool}
8
+ let(:pool_query_result) do
9
+ pr = OpenStruct.new
10
+ pr.data = OpenStruct.new
11
+ pr.data.fname = String.new
12
+ pr.data.yiaddr = '0.0.0.0'
13
+ pr.data.options = Array.new
14
+ pr.code = 200
15
+ pr
16
+ end
7
17
  let(:from_ip) {'0.0.0.0'}
8
18
  let(:from_port) {67}
9
- let(:discover) do
10
- d = DHCP::Discover.new
11
- d.xid = 123456789
12
- d
19
+ [ :discover, :request, :release, :inform ].each do |message|
20
+ let(message) do
21
+ msg_class = DHCP.const_get message.to_s.capitalize.to_sym
22
+ d = msg_class.new
23
+ d.xid = 123456789
24
+ d
25
+ end
26
+ end
27
+ let(:reply) {OpenStruct.new}
28
+
29
+ before(:each) do
30
+ allow(pool).to receive(:query).and_return(pool_query_result)
31
+ allow(pool).to receive(:query).with('ee:ee:ee:ee:ee:ee', :discover).and_return(pool_query_result)
32
+ end
33
+
34
+ shared_examples 'Dispatcher' do |message|
35
+ it 'data is correct' do
36
+ dispatcher.dispatch(eval(message.to_s).pack, from_ip, from_port).data.pack.should == reply.data.pack
37
+ end
38
+ it 'ip is correct' do
39
+ dispatcher.dispatch(eval(message.to_s).pack, from_ip, from_port).ip.should == reply.ip
40
+ end
41
+ it 'port is correct' do
42
+ dispatcher.dispatch(eval(message.to_s).pack, from_ip, from_port).port.should == reply.port
43
+ end
13
44
  end
14
45
 
15
- context 'receive dhcp message' do
16
- it 'reply xid is the same as received xid' do
17
- dispatcher.dispatch(discover.pack, from_ip, from_port).data.xid.should == discover.xid
46
+ %w{discover request release inform}.each do |message|
47
+ context "receive dhcp #{message} message" do
48
+ it "dispatch it to specific #{message}_handler private method" do
49
+ dispatcher.should_receive("#{message}_handler".to_sym)
50
+ dispatcher.dispatch(eval(message).pack, from_ip, from_port)
51
+ end
52
+ if %w{discover request inform}.include? message
53
+ it 'reply xid is the same as received xid' do
54
+ dispatcher.dispatch(eval(message).pack, from_ip, from_port).data.xid.should == eval(message).xid
55
+ end
56
+ end
18
57
  end
19
58
  end
20
59
 
21
- context 'receive discovery message' do
60
+ context 'wrong message' do
61
+ it 'false when message is unknown' do
62
+ lambda { dispatcher.dispatch("abracadabra", from_ip, from_port) }.should raise_error(IncorrectMessage)
63
+ end
64
+ it 'false when action for message unspecified' do
65
+ lambda { dispatcher.dispatch("abracadabra", from_ip, from_port) }.should raise_error(IncorrectMessage)
66
+ end
67
+ end
68
+
69
+ describe 'receive discovery message' do
22
70
  # RFC 2131 (http://www.ietf.org/rfc/rfc2131.txt)
23
71
  #
24
72
  # http://stackoverflow.com/a/10757849
@@ -34,44 +82,155 @@ module Blondy
34
82
  # then the server unicasts DHCPOFFER and DHCPACK messages to the client's hardware address
35
83
  # and 'yiaddr' address. In all cases, when 'giaddr' is zero,
36
84
  # the server broadcasts any DHCPNAK messages to 0xffffffff.
37
- let(:reply) do
38
- reply = OpenStruct.new
85
+
86
+ before(:each) do
87
+ discover.chaddr = [238, 238, 238, 238, 238, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
88
+ discover.hlen = 6
89
+ pool_query_result.data.fname = 'test.txt'.unpack('C128').map {|x| x ? x : 0}
90
+ pool_query_result.data.yiaddr = IPAddr.new('192.168.5.150').to_i
91
+ pool_query_result.data.options = [
92
+ DHCP::MessageTypeOption.new({payload: [$DHCP_MSG_OFFER]}),
93
+ DHCP::ServerIdentifierOption.new({payload: [192, 168, 1, 1]}),
94
+ DHCP::DomainNameOption.new({payload: 'example.com'.unpack('C*')}),
95
+ DHCP::DomainNameServerOption.new({payload: [8,8,8,8]}),
96
+ DHCP::IPAddressLeaseTimeOption.new({payload: [7200].pack('N').unpack('C*')}),
97
+ DHCP::SubnetMaskOption.new({payload: [255, 255, 255, 255]}),
98
+ DHCP::RouterOption.new({payload: [192, 168, 1, 1]})
99
+ ]
39
100
  reply.data = DHCP::Offer.new
40
- reply
101
+ reply.data.xid = discover.xid
102
+ reply.data.options = pool_query_result.data.options
103
+ reply.data.yiaddr = pool_query_result.data.yiaddr
104
+ reply.data.fname = pool_query_result.data.fname
105
+ reply.data.siaddr = IPAddr.new(Blondy::DHCPD::CONFIG['server_ip']).to_i
106
+ end
107
+
108
+ it 'reply with offer' do
109
+ dispatcher.dispatch(discover.pack, from_ip, from_port).data.class == DHCP::Offer
41
110
  end
42
111
 
43
112
  context 'giaddr != 0' do
44
- it 'send offer message to bootp relay' do
45
- pending
46
- data.giaddr = IPAddr.new('192.168.3.3').to_i
47
- server.should_receive(:send_datagram).with(reply.data.pack, '192.168.3.3', 67)
48
- server.receive_data(data.pack)
113
+ #reply with offer message to bootp relay
114
+ before(:each) do
115
+ giaddr = '192.168.3.3'
116
+ discover.giaddr = IPAddr.new(giaddr).to_i
117
+ reply.ip = giaddr
118
+ reply.port = 67
49
119
  end
120
+ it_should_behave_like 'Dispatcher', :discover
50
121
  end
51
122
  context 'giaddr = 0 and ciaddr != 0' do
52
- it 'send offer message to client by unicast' do
53
- pending
54
- data.ciaddr = IPAddr.new('192.168.3.3').to_i
55
- server.should_receive(:send_data).with(reply.data.pack, '192.168.3.3', 68)
56
- server.receive_data(data.pack)
123
+ #send offer message to client
124
+ before(:each) do
125
+ ciaddr = '192.168.3.4'
126
+ discover.ciaddr = IPAddr.new(ciaddr).to_i
127
+ reply.ip = ciaddr
128
+ reply.port = 68
57
129
  end
130
+ it_should_behave_like 'Dispatcher', :discover
58
131
  end
59
- context 'giaddr = 0 and ciaddr = 0 and flags = 1' do
60
- it 'send offer message to client by broadcast to 255.255.255.255' do
61
- pending
62
- data.flags = 1
63
- server.should_receive(:send_data).with(reply.data.pack, '', 68)
64
- server.receive_data(data.pack)
132
+ context 'giaddr = 0 and ciaddr = 0' do
133
+ #send offer message to client by broadcast to 255.255.255.255
134
+ before(:each) do
135
+ discover.flags = 1
136
+ reply.ip = '255.255.255.255'
137
+ reply.port = 68
65
138
  end
139
+ it_should_behave_like 'Dispatcher', :discover
66
140
  end
67
- context 'giaddr = 0 and ciaddr = 0 and flags = 0' do
68
- it 'send offer message to client by unicast it to client hwaddr and yiaddr' do
69
- pending
70
- data.yiaddr = IPAddr.new('192.168.3.200').to_i
71
- data.chaddr = [80, 229, 73, 35, 15, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
72
- reply.data.chaddr.should eq(data.chaddr)
73
- server.should_receive(:send_data).with(reply.data.pack, '192.168.3.200', 68)
74
- server.receive_data(data.pack)
141
+
142
+ context 'ask pool for configuration' do
143
+ context 'query already found in cache' do
144
+ it 'not reply for message' do
145
+ pool.should_receive(:query).with('ee:ee:ee:ee:ee:ee', :discover).and_return(false)
146
+ dispatcher.dispatch(discover.pack, from_ip, from_port).should be_false
147
+ end
148
+ end
149
+ context 'query not found in cache' do
150
+ it 'set reply fields according to pool query result' do
151
+ dispatcher.dispatch(discover.pack, from_ip, from_port).data.fname.should == pool_query_result.data.fname
152
+ dispatcher.dispatch(discover.pack, from_ip, from_port).data.yiaddr.should == pool_query_result.data.yiaddr
153
+ dispatcher.dispatch(discover.pack, from_ip, from_port).data.options.should == pool_query_result.data.options
154
+ end
155
+ it 'set siaddr to server ip address' do
156
+ dispatcher.dispatch(discover.pack, from_ip, from_port).data.siaddr.should == IPAddr.new(Blondy::DHCPD::CONFIG['server_ip']).to_i
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ describe 'receive request message' do
163
+ before(:each) do
164
+ request.chaddr = [238, 238, 238, 238, 238, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
165
+ request.hlen = 6
166
+ pool_query_result.data.fname = 'test.txt'.unpack('C128').map {|x| x ? x : 0}
167
+ pool_query_result.data.yiaddr = IPAddr.new('192.168.5.150').to_i
168
+ pool_query_result.data.options = [
169
+ DHCP::MessageTypeOption.new({payload: [$DHCP_MSG_ACK]}),
170
+ DHCP::ServerIdentifierOption.new({payload: [192, 168, 1, 1]}),
171
+ DHCP::DomainNameOption.new({payload: 'example.com'.unpack('C*')}),
172
+ DHCP::DomainNameServerOption.new({payload: [8,8,8,8]}),
173
+ DHCP::IPAddressLeaseTimeOption.new({payload: [7200].pack('N').unpack('C*')}),
174
+ DHCP::SubnetMaskOption.new({payload: [255, 255, 255, 255]}),
175
+ DHCP::RouterOption.new({payload: [192, 168, 1, 1]})
176
+ ]
177
+ reply.data = DHCP::ACK.new
178
+ reply.data.xid = request.xid
179
+ reply.data.options = pool_query_result.data.options
180
+ reply.data.yiaddr = pool_query_result.data.yiaddr
181
+ reply.data.fname = pool_query_result.data.fname
182
+ reply.data.siaddr = IPAddr.new(Blondy::DHCPD::CONFIG['server_ip']).to_i
183
+ message = request
184
+ end
185
+ it 'reply with ack' do
186
+ dispatcher.dispatch(discover.pack, from_ip, from_port).data.class == DHCP::ACK
187
+ end
188
+ context 'giaddr != 0' do
189
+ #reply with ack message to bootp relay
190
+ before(:each) do
191
+ giaddr = '192.168.3.3'
192
+ request.giaddr = IPAddr.new(giaddr).to_i
193
+ reply.ip = giaddr
194
+ reply.port = 67
195
+ end
196
+ it_should_behave_like 'Dispatcher', :request
197
+ end
198
+ context 'giaddr = 0 and ciaddr != 0' do
199
+ #send ack message to client
200
+ before(:each) do
201
+ ciaddr = '192.168.3.4'
202
+ request.ciaddr = IPAddr.new(ciaddr).to_i
203
+ reply.ip = ciaddr
204
+ reply.port = 68
205
+ end
206
+ it_should_behave_like 'Dispatcher', :request
207
+ end
208
+ context 'giaddr = 0 and ciaddr = 0' do
209
+ #send ack message to client by broadcast to 255.255.255.255
210
+ before(:each) do
211
+ request.flags = 1
212
+ reply.ip = '255.255.255.255'
213
+ reply.port = 68
214
+ end
215
+ it_should_behave_like 'Dispatcher', :request
216
+ end
217
+
218
+ context 'ask pool for configuration' do
219
+ context 'query already found in cache' do
220
+ it 'not reply for message' do
221
+ pool.should_receive(:query).with('ee:ee:ee:ee:ee:ee', :request).and_return(false)
222
+ dispatcher.dispatch(request.pack, from_ip, from_port).should be_false
223
+ end
224
+ end
225
+ context 'query not found in cache' do
226
+ it 'set reply fields according to pool query result' do
227
+ dispatcher.dispatch(request.pack, from_ip, from_port).data.fname.should == pool_query_result.data.fname
228
+ dispatcher.dispatch(request.pack, from_ip, from_port).data.yiaddr.should == pool_query_result.data.yiaddr
229
+ dispatcher.dispatch(request.pack, from_ip, from_port).data.options.should == pool_query_result.data.options
230
+ end
231
+ it 'set siaddr to server ip address' do
232
+ dispatcher.dispatch(request.pack, from_ip, from_port).data.siaddr.should == IPAddr.new(Blondy::DHCPD::CONFIG['server_ip']).to_i
233
+ end
75
234
  end
76
235
  end
77
236
  end
data/spec/pool_spec.rb ADDED
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+
3
+ module Blondy
4
+ module DHCPD
5
+
6
+ describe 'Pool' do
7
+ subject(:pool) {Pool}
8
+ let(:cache) {Cache}
9
+ let(:logger) {Logger}
10
+ let(:remote_json) { {'fname' => 'test.txt',
11
+ 'yiaddr' => '192.168.5.150',
12
+ 'domain' => 'example.com',
13
+ 'dns' => '8.8.8.8',
14
+ 'gw' => '192.168.1.3',
15
+ 'netmask' => '255.255.255.255' }.to_json }
16
+ let(:remote_invalid_json) { { 'netaddr' => 'invalid', 'yomask' => '' }.to_json }
17
+ let(:reply_data) do
18
+ pool_query_result = OpenStruct.new
19
+ pool_query_result.data = OpenStruct.new
20
+ pool_query_result.data.fname = 'test.txt'.unpack('C128').map {|x| x ? x : 0}
21
+ pool_query_result.data.yiaddr = IPAddr.new('192.168.5.150').to_i
22
+ pool_query_result.data.options = [
23
+ DHCP::MessageTypeOption.new({payload: [$DHCP_MSG_OFFER]}),
24
+ DHCP::ServerIdentifierOption.new({payload: Blondy::DHCPD::CONFIG['server_ip'].split('.').map {|octet| octet.to_i}}),
25
+ DHCP::DomainNameOption.new({payload: 'example.com'.unpack('C*')}),
26
+ DHCP::DomainNameServerOption.new({payload: [8,8,8,8]}),
27
+ DHCP::IPAddressLeaseTimeOption.new({payload: [7200].pack('N').unpack('C*')}),
28
+ DHCP::SubnetMaskOption.new({payload: [255, 255, 255, 255]}),
29
+ DHCP::RouterOption.new({payload: [192, 168, 1, 3]})
30
+ ]
31
+ pool_query_result
32
+ end
33
+
34
+ describe 'receive query' do
35
+
36
+ before(:each) do
37
+ cache.flush
38
+ stub_request(:get, "https://127.0.0.1/blondy/dhcpd?hwaddr=11:11:11:11:11:11&type=discover").
39
+ with(:headers => {'X-Blondy-Key'=>'abcd'}).
40
+ to_return(:status => 200, :body => remote_json, :headers => {})
41
+ end
42
+
43
+ it 'check for reply in cache' do
44
+ cache.should_receive(:query).with('11:11:11:11:11:11', :discover)
45
+ pool.query('11:11:11:11:11:11', :discover)
46
+ end
47
+
48
+ context 'not found in cache' do
49
+ before(:each) do
50
+ allow(cache).to receive(:query).with('11:11:11:11:11:11', :discover).and_return(false)
51
+ end
52
+ it 'initiate query to remote server' do
53
+ pool.query('11:11:11:11:11:11', :discover)
54
+ WebMock.should have_requested(:get, "https://127.0.0.1/blondy/dhcpd?hwaddr=11:11:11:11:11:11&type=discover")
55
+ end
56
+ it 'reply with false' do
57
+ pool.query('11:11:11:11:11:11', :discover).should == false
58
+ end
59
+ it 'set received data to cache', :no_em do
60
+ cache.stub(:query) { cache.unstub(:query); false }
61
+ EM.run_block { pool.query('11:11:11:11:11:11', :discover) }
62
+ cache.query('11:11:11:11:11:11', :discover)[:data].should == reply_data
63
+ end
64
+ end
65
+
66
+ context 'found in cache' do
67
+ before(:each) do
68
+ allow(cache).to receive(:query).with('11:11:11:11:11:11', :discover).and_return({data:reply_data, time: Time.now})
69
+ end
70
+
71
+ it 'return reply data' do
72
+ pool.query('11:11:11:11:11:11', :discover).should == reply_data
73
+ end
74
+ end
75
+
76
+ context 'remote pool unavailable' do
77
+ before(:each) do
78
+ stub_request(:get, "https://127.0.0.1/blondy/dhcpd?hwaddr=11:11:11:11:11:11&type=discover").
79
+ with(:headers => {'X-Blondy-Key'=>'abcd'}).
80
+ to_timeout
81
+ end
82
+ it 'log that pool unavailable', :no_em do
83
+ logger.should_receive(:error).with('Remote pool server is unavailable.')
84
+ EM.run_block { pool.query('11:11:11:11:11:11', :discover) }
85
+ end
86
+ it 'not set values to cache' do
87
+ cache.should_not_receive(:add)
88
+ pool.query('11:11:11:11:11:11', :discover)
89
+ end
90
+ end
91
+
92
+ context 'remote pool send incorrect data' do
93
+ before(:each) do
94
+ stub_request(:get, "https://127.0.0.1/blondy/dhcpd?hwaddr=11:11:11:11:11:11&type=discover").
95
+ with(:headers => {'X-Blondy-Key'=>'abcd'}).
96
+ to_return(:status => 200, :body => remote_invalid_json, :headers => {})
97
+ end
98
+ it 'return false' do
99
+ pool.query('11:11:11:11:11:11', :discover).should be_false
100
+ end
101
+ end
102
+
103
+ context 'remote pool reply with error' do
104
+ before(:each) do
105
+ stub_request(:get, "https://127.0.0.1/blondy/dhcpd?hwaddr=11:11:11:11:11:11&type=discover").
106
+ with(:headers => {'X-Blondy-Key'=>'abcd'}).
107
+ to_return(:status => 500, :body => "", :headers => {})
108
+ end
109
+ it 'log error code', :no_em do
110
+ logger.should_receive(:error).with('Remote server reply with 500 error code.')
111
+ EM.run_block { pool.query('11:11:11:11:11:11', :discover) }
112
+ end
113
+ it 'not set values to cache' do
114
+ cache.should_not_receive(:add)
115
+ pool.query('11:11:11:11:11:11', :discover)
116
+ end
117
+ end
118
+
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module Blondy
4
+ module DHCPD
5
+ describe 'Reply' do
6
+
7
+ end
8
+ end
9
+ end
data/spec/server_spec.rb CHANGED
@@ -17,26 +17,87 @@ module Blondy
17
17
  d.xid = 123456789
18
18
  d
19
19
  end
20
+ let(:logger) {Logger}
20
21
 
21
22
  before(:each) do
22
23
  allow(EM).to receive(:open_udp_socket).and_return 0
23
24
  allow(Socket).to receive(:unpack_sockaddr_in).and_return ['0.0.0.0', '68']
25
+ allow(Logger).to receive(:info)
26
+ allow(Logger).to receive(:warn)
27
+ allow(Logger).to receive(:error)
28
+ allow(Pool).to receive(:query)
24
29
  end
25
30
 
26
- context 'receive dhcp message' do
31
+ it 'has defined buffer' do
32
+ server.instance_variable_defined?('@buffer').should be_true
33
+ end
34
+
35
+ describe 'receive message' do
27
36
  before(:each) do
28
37
  @ip, @port = Socket.unpack_sockaddr_in(server.get_peername)
29
38
  end
30
- it 'run dispatcher' do
31
- dispatcher.should_receive(:dispatch).with(discover.pack, @ip, @port)
32
- server.receive_data(discover.pack)
39
+
40
+ it 'add received data in buffer' do
41
+ server.receive_data('test data')
42
+ server.instance_variable_get('@buffer').include?('test data').should be_true
33
43
  end
34
- it 'send reply' do
35
- server.should_receive(:send_datagram)
36
- server.receive_data(discover.pack)
44
+ context 'buffer include DHCP magic number' do
45
+ it 'run dispatcher' do
46
+ dispatcher.should_receive(:dispatch).with(discover.pack, @ip, @port)
47
+ server.receive_data(discover.pack)
48
+ end
49
+ it 'clear buffer' do
50
+ server.receive_data(discover.pack)
51
+ server.instance_variable_get('@buffer').size.should eq(0)
52
+ end
53
+ end
54
+ context 'buffer not include DHCP magic' do
55
+ # Maximum dhcp message size is 576 bytes (but client can increase it)
56
+ # So we will try with 1000 bytes buffer
57
+ context 'data size in buffer is greater than 1000 bytes' do
58
+ it 'clear buffer' do
59
+ dummy_data = String.new
60
+ 1000.times { dummy_data += rand(9).to_s }
61
+ server.instance_variable_set('@buffer', dummy_data)
62
+ server.receive_data(discover.pack.byteslice(0,15))
63
+ server.instance_variable_get('@buffer').size.should eq(15)
64
+ end
65
+ end
66
+ it 'shoul not clear buffer' do
67
+ server.receive_data(discover.pack.byteslice(0,10))
68
+ server.instance_variable_get('@buffer').size.should eq(10)
69
+ end
37
70
  end
38
- end
39
71
 
72
+ context 'receive dhcp message' do
73
+ it 'send reply' do
74
+ reply = OpenStruct.new
75
+ reply.data = DHCP::Offer.new
76
+ allow(dispatcher).to receive(:dispatch).and_return(reply)
77
+ server.should_receive(:send_datagram)
78
+ server.receive_data(discover.pack)
79
+ end
80
+ context 'wrong data' do
81
+ it 'not send reply' do
82
+ server.should_not_receive(:send_datagram)
83
+ server.receive_data('abracadabra')
84
+ end
85
+ context 'can not convert received data to Message object' do
86
+ it 'should log error' do
87
+ logger.should_receive(:warn).with('Incorrect message received. Ignore.')
88
+ discover.options.shift
89
+ server.receive_data(discover.pack)
90
+ end
91
+ end
92
+ context 'no handler for message' do
93
+ it 'should log error' do
94
+ logger.should_receive(:warn).with('No handler for message found. Ignore.')
95
+ server.receive_data(DHCP::Offer.new.pack)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
40
101
  end
41
102
  end
42
103
  end
data/spec/spec_helper.rb CHANGED
@@ -4,16 +4,31 @@
4
4
  # loaded once.
5
5
  #
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require 'simplecov'
8
+ SimpleCov.start
7
9
 
8
10
  require 'net-dhcp'
9
11
  require 'eventmachine'
12
+ require 'em-http'
10
13
  require 'ostruct'
11
14
  require 'ipaddr'
12
15
  require 'rspec'
16
+ require 'webmock/rspec'
17
+ require 'json'
18
+ require 'fiber'
19
+ require 'log4r'
20
+
13
21
 
14
22
  spec_root = File.dirname(File.absolute_path(__FILE__))
15
- Dir.glob(spec_root + '/../lib/blondy/dhcpd/*') {|file| require file}
23
+ exclude = %w{config.rb logger.rb}
24
+ Dir.glob(spec_root + '/../lib/blondy/dhcpd/*') {|file| require file unless exclude.include?(file.gsub(/^.*\//,''))}
16
25
 
26
+ # Set config for test
27
+ Blondy::DHCPD::CONFIG = Hash.new
28
+ Blondy::DHCPD::CONFIG['server_ip'] = '192.168.5.1'
29
+ Blondy::DHCPD::CONFIG['master'] = 'https://127.0.0.1/blondy/dhcpd'
30
+ Blondy::DHCPD::CONFIG['client_key'] = 'abcd'
31
+ Logger = Log4r::Logger.new 'ruby-dhcpd'
17
32
 
18
33
  RSpec.configure do |config|
19
34
  config.treat_symbols_as_metadata_keys_with_true_values = true
@@ -30,17 +45,46 @@ end
30
45
  # Wrap for running examples inside eventmachine reactor
31
46
  RSpec::Core::Example.class_eval do
32
47
  alias ignorant_run run
48
+ class << self
49
+ attr_accessor :examples_fibers
50
+ end
51
+ self.examples_fibers = Array.new
33
52
 
34
53
  def run(example_group_instance, reporter)
35
- Fiber.new do
54
+ if @options[:no_em]
55
+ fibers_alive = [true]
56
+ while fibers_alive.include?(true)
57
+ fibers_alive = []
58
+ self.class.examples_fibers.each do |f|
59
+ f.resume if f.alive?
60
+ fibers_alive << f.alive?
61
+ end
62
+ end
63
+ while EM.reactor_running?
64
+ EM.stop
65
+ sleep 0.5
66
+ end
67
+ ignorant_run example_group_instance, reporter
68
+ elsif @options[:no_fiber]
36
69
  EM.run do
37
70
  df = EM::DefaultDeferrable.new
38
71
  result = nil
39
- df.callback { |x| EM.stop_event_loop; Fiber.yield result }
72
+ df.callback { |x| EM.stop_event_loop; result }
40
73
  result = ignorant_run example_group_instance, reporter
41
74
  df.succeed
42
75
  end
43
- end.resume
76
+ else
77
+ f = Fiber.new do
78
+ EM.run do
79
+ df = EM::DefaultDeferrable.new
80
+ result = nil
81
+ df.callback { |x| EM.stop_event_loop; Fiber.yield result }
82
+ result = ignorant_run example_group_instance, reporter
83
+ df.succeed
84
+ end
85
+ end
86
+ self.class.examples_fibers << f
87
+ f.resume
88
+ end
44
89
  end
45
90
  end
46
-