zerg_support 0.0.5 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,15 +4,68 @@ module Zerg::Support::Process
4
4
  end
5
5
 
6
6
  if RUBY_PLATFORM =~ /win/ and RUBY_PLATFORM !~ /darwin/
7
- require 'win32-process'
7
+ require 'win32/process'
8
8
 
9
9
  #:nodoc: all
10
10
  module Zerg::Support::Process
11
11
  def self.spawn(binary, args = [], options = {})
12
- info = Process.create :app_name => binary,
12
+ # command line processing
13
+ command_line = '"' + binary + '" "' +
14
+ args.map { |a| a.gsub '"', '""' }.join('" "') + '"'
15
+
16
+ # environment processing
17
+ environment_string = nil
18
+ if options[:env]
19
+ if options[:unsetenv_others]
20
+ environment = options[:env]
21
+ else
22
+ environment = Hash.new.merge(ENV).merge(options[:env])
23
+ end
24
+ environment_string = environment.keys.sort.
25
+ map { |k| "#{k}=#{environment[k]}" }.join "\0"
26
+ environment_string << "\0"
27
+ end
28
+
29
+ # redirection processing
30
+ startup_info = {}
31
+ files = {}
32
+ stream_files = {}
33
+ deferred_opens = []
34
+ [[STDIN, :stdin], [STDOUT, :stdout], [STDERR, :stderr]].each do |pair|
35
+ next unless options[pair.first]
36
+ if options[pair.first].kind_of? String
37
+ filename = options[pair.first]
38
+ files[filename] ||= File.open(filename,
39
+ (pair.last == :stdin) ? 'r' : 'w+')
40
+ startup_info[pair.last] = files[filename]
41
+ stream_files[pair.first] = files[filename]
42
+ else
43
+ deferred_opens << Kernel.proc do
44
+ io = stream_files[options[pair.first]] || pair.first
45
+ startup_info[pair.last] = stream_files[pair.first] = io
46
+ end
47
+ end
48
+ end
49
+ deferred_opens.each { |d| d.call }
50
+
51
+ # process leader
52
+ creation_flags = 0
53
+ if options[:pgroup]
54
+ creation_flags |= Process::DETACHED_PROCESS
55
+ if options[:pgroup].kind_of? Numeric and options[:pgroup] > 0
56
+ # TODO: what now?
57
+ else
58
+ creation_flags |= Process::CREATE_NEW_PROCESS_GROUP
59
+ end
60
+ end
61
+
62
+ info = Process.create :command_line => command_line,
13
63
  :cwd => options[:chdir] || Dir.pwd,
14
- :environment => options[:env],
15
- :creation_flags => 0
64
+ :environment => environment_string,
65
+ :creation_flags => creation_flags,
66
+ :startup_info => startup_info
67
+ files.each { |name, io| io.close }
68
+
16
69
  return info[:process_id]
17
70
  end
18
71
  end
@@ -109,12 +162,18 @@ module Zerg::Support::Process::Helpers
109
162
  # Performs IO redirections according to the given options. The options
110
163
  # follow the convention of Kernel.spawn in ruby1.9
111
164
  def self.do_redirects(options)
165
+ redirected_files = {}
112
166
  file_redirects = []
113
167
  fd_redirects = []
114
168
  options.each do |key, value|
115
169
  next unless key.kind_of? IO
116
170
  if value.kind_of? String
117
- file_redirects << [key, value]
171
+ if redirected_files[value]
172
+ fd_redirects << [key, redirected_files[value]]
173
+ else
174
+ file_redirects << [key, value]
175
+ redirected_files[value] = key
176
+ end
118
177
  else
119
178
  fd_redirects << [key, value]
120
179
  end
@@ -123,4 +182,4 @@ module Zerg::Support::Process::Helpers
123
182
  r.first.reopen r.last
124
183
  end
125
184
  end
126
- end
185
+ end
data/lib/zerg_support.rb CHANGED
@@ -6,6 +6,16 @@ end
6
6
  module Zerg::Support
7
7
  end
8
8
 
9
+ require 'rubygems'
9
10
  require 'zerg_support/gems.rb'
10
11
  require 'zerg_support/process.rb'
12
+ require 'zerg_support/open_ssh.rb'
11
13
  require 'zerg_support/spawn.rb'
14
+
15
+ # TODO(victor): document this
16
+ module Zerg::Support::EventMachine
17
+ end
18
+
19
+ require 'zerg_support/event_machine/connection_mocks.rb'
20
+ require 'zerg_support/event_machine/frame_protocol.rb'
21
+ require 'zerg_support/event_machine/object_protocol.rb'
data/test/fork_tree.rb ADDED
@@ -0,0 +1,34 @@
1
+ # Used in test_process.rb to produce a tree of children.
2
+ # Usage:
3
+ # ruby test/fork_tree.rb level interval cookie
4
+ # Arguments:
5
+ # level - the fork level; 0 means don't fork, otherwise fork two children
6
+ # with fork level-1
7
+ # interval - the time to sleep (in seconds)
8
+ # cookie - an argument that's preserved to help track down the process
9
+ # also, the PID will be written to cookie.pid unless the file already
10
+ # exists (this means that only the fork tree's root writes it)
11
+
12
+ require 'English'
13
+
14
+ # extract arguments
15
+ level = ARGV[1].to_i
16
+ interval = ARGV[2].to_f
17
+ cookie = ARGV[3]
18
+
19
+ # write PID file
20
+ pid_file = cookie + ".pid"
21
+ unless File.exist? pid_file
22
+ File.open(pid_file, "w") { |f| f.write $PID.to_s }
23
+ end
24
+
25
+ # spawn children
26
+ unless level == 0
27
+ 2.times do
28
+ Thread.new do
29
+ system "ruby test/fork_tree.rb -- #{level - 1} #{interval} #{cookie}"
30
+ end
31
+ end
32
+ end
33
+
34
+ sleep interval
@@ -0,0 +1,57 @@
1
+ require 'test/unit'
2
+
3
+ require 'zerg_support'
4
+
5
+ require 'rubygems'
6
+ require 'flexmock/test_unit'
7
+
8
+ class HollowReceiveMock < Zerg::Support::EventMachine::ReceiveMock
9
+ end
10
+
11
+ # Collects groups of 3 letters, stores them into idenity hashes.
12
+ class ReceiveFooMock < Zerg::Support::EventMachine::ReceiveMock
13
+ object_name :foo
14
+
15
+ def receive_data(data)
16
+ @s ||= ''
17
+ data.each_byte do |c|
18
+ @s << c
19
+ if @s.length == 3
20
+ receive_foo @s => @s
21
+ @s = ''
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ class ConnectionMocksTest < Test::Unit::TestCase
28
+ def test_send_mock
29
+ send_mock = Zerg::Support::EventMachine::SendMock.new
30
+ assert_equal send_mock.string, ''
31
+
32
+ send_mock.send_data('a')
33
+ assert_equal send_mock.string, 'a'
34
+
35
+ send_mock.send_data('bcd')
36
+ assert_equal send_mock.string, 'abcd'
37
+
38
+ send_mock.send_data('em')
39
+ assert_equal send_mock.string, 'abcdem'
40
+ end
41
+
42
+ def test_receive_mock_calls_recieve_data
43
+ recv_mock = HollowReceiveMock.new ['a', 'bcd', 'em']
44
+ flexmock(recv_mock).should_receive(:receive_data).with('a').once
45
+ flexmock(recv_mock).should_receive(:receive_data).with('bcd').once
46
+ flexmock(recv_mock).should_receive(:receive_data).with('em').once
47
+ recv_mock.replay
48
+ end
49
+
50
+ def test_receive_mock_collects_objects
51
+ foos = ReceiveFooMock.new(['a', 'bcd', 'emx']).replay.foos
52
+ assert_equal [{'abc' => 'abc'}, {'dem' => 'dem'}], foos
53
+
54
+ foos = ReceiveFooMock.new('ab').replay.foos
55
+ assert_equal [], foos
56
+ end
57
+ end
@@ -0,0 +1,119 @@
1
+ require 'zerg_support'
2
+
3
+ require 'test/unit'
4
+
5
+ class TestFrameProtocol < Test::Unit::TestCase
6
+ FP = Zerg::Support::EventMachine::FrameProtocol
7
+
8
+ # Send mock for frames.
9
+ class SendFramesMock < Zerg::Support::EventMachine::SendMock
10
+ include FP
11
+ end
12
+
13
+ # Receive mock for frames.
14
+ class ReceiveFramesMock < Zerg::Support::EventMachine::ReceiveMock
15
+ include FP
16
+ object_name :frame
17
+ end
18
+
19
+ def setup
20
+ super
21
+ @send_mock = SendFramesMock.new
22
+ end
23
+
24
+ def teardown
25
+ super
26
+ end
27
+
28
+ def continuous_data_test(frames)
29
+ truncated_data_test frames, []
30
+ end
31
+
32
+ def truncated_data_test(frames, sub_lengths)
33
+ frames.each { |frame| @send_mock.send_frame frame }
34
+ in_string = @send_mock.string
35
+ in_strings, i = [], 0
36
+ sub_lengths.each do |sublen|
37
+ in_strings << in_string[i, sublen]
38
+ i += sublen
39
+ end
40
+ in_strings << in_string[i..-1] if i < in_string.length
41
+ out_frames = ReceiveFramesMock.new(@send_mock.string).replay.frames
42
+ assert_equal frames, out_frames
43
+ end
44
+
45
+ def test_empty_frame
46
+ continuous_data_test ['']
47
+ end
48
+
49
+ def test_byte_frame
50
+ continuous_data_test ['F']
51
+ end
52
+
53
+ def test_string_frame
54
+ continuous_data_test [(32...128).to_a.pack('C*')]
55
+ end
56
+
57
+ def test_multiple_frames
58
+ continuous_data_test [(32...128).to_a.pack('C*'), '', 'F', '', '1234567890']
59
+ end
60
+
61
+ def test_truncated_border
62
+ truncated_data_test ['A', 'A'], [1, 0, 2, 0]
63
+ end
64
+
65
+ def test_truncated_border_and_joined_data_size
66
+ truncated_data_test ['A', 'A'], [1, 1, 1, 1]
67
+ end
68
+
69
+ def test_truncated_size
70
+ long_frame = (32...128).to_a.pack('C*') * 5
71
+ truncated_data_test [long_frame], [1]
72
+ end
73
+
74
+ def test_truncated_size_and_data
75
+ long_frame = (32...128).to_a.pack('C*') * 5
76
+ truncated_data_test [long_frame], [1, 16]
77
+ end
78
+
79
+ def test_badass
80
+ # TODO(not_me): this test takes 4 seconds; replace with more targeted tests
81
+
82
+ # build the badass string
83
+ s2_frame = 'qwertyuiopasdfgh' * 8 * 128 # 16384 characters, size is 3 bytes
84
+ @send_mock.send_frame s2_frame
85
+ s2_string = @send_mock.string
86
+ s2_count = 3
87
+ send_string = s2_string * s2_count
88
+ ex_frames = [s2_frame] * s2_count
89
+
90
+ # build cut points in a string
91
+ s2_points = [0, 1, 2, 3, 4, 5, 127, 128, 8190, 16381, 16382, 16383]
92
+ cut_points = []
93
+ 0.upto(s2_count - 1) do |i|
94
+ cut_points += s2_points.map { |p| p + i * s2_string.length }
95
+ end
96
+
97
+ # try all combinations of cutting up the string in 4 pieces
98
+ 0.upto(cut_points.length - 1) do |i|
99
+ (i + 1).upto(cut_points.length - 1) do |j|
100
+ (j + 1).upto(cut_points.length - 1) do |k|
101
+ packets = [0...cut_points[i], cut_points[i]...cut_points[j],
102
+ cut_points[j]...cut_points[k], cut_points[k]..-1].
103
+ map { |r| send_string[r] }
104
+ assert_equal ex_frames, ReceiveFramesMock.new(packets).replay.frames
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def test_natural_encoding
111
+ table = [[0, "\0"], [1, "\x01"], [127, "\x7f"], [128, "\x80\x01"],
112
+ [65535, "\xff\xff\x03"], [0xf0f0f0, "\xf0\xe1\xc3\x07"],
113
+ [0xaa55aa55aa55, "\xd5\xd4\xd6\xd2\xda\xca\x2a"]]
114
+ table.each do |entry|
115
+ assert_equal entry.last, FP.encode_natural(entry.first)
116
+ assert_equal entry.first, FP.decode_natural(entry.last)
117
+ end
118
+ end
119
+ end
data/test/test_gems.rb CHANGED
@@ -11,7 +11,7 @@ class TestGems < Test::Unit::TestCase
11
11
  end
12
12
 
13
13
  def test_source_is_manually_tested
14
- golden_hash = '7fca02be12fb30415a492544d91f977e8de0e440'
14
+ golden_hash = '21ba9ca1e8fa3aa205b468a884746eb37697df9b'
15
15
  source_hash = hash_gems_file
16
16
 
17
17
  assert_equal golden_hash, source_hash, <<END_MESSAGE
@@ -0,0 +1,55 @@
1
+ require 'test/unit'
2
+
3
+ require 'zerg_support'
4
+
5
+ class ObjectProtocolTest < Test::Unit::TestCase
6
+ OP = Zerg::Support::EventMachine::ObjectProtocol
7
+
8
+ class SendObjectMock < Zerg::Support::EventMachine::SendMock
9
+ include OP
10
+ end
11
+ class ReceiveObjectMock < Zerg::Support::EventMachine::ReceiveMock
12
+ include OP
13
+ object_name :object
14
+ end
15
+
16
+ def one_test(*objects)
17
+ send_mock = SendObjectMock.new
18
+ objects.each { |o| send_mock.send_object o }
19
+ assert_equal objects, ReceiveObjectMock.new(send_mock.string).replay.objects
20
+ end
21
+
22
+ def test_border_cases
23
+ one_test({})
24
+ one_test(nil)
25
+ one_test('')
26
+ one_test(false)
27
+ one_test(0)
28
+ one_test([])
29
+ end
30
+
31
+ def test_literals
32
+ one_test(1)
33
+ one_test(true)
34
+ one_test('A')
35
+ one_test("A\nB\nC\tD")
36
+ end
37
+
38
+ def test_arrays
39
+ one_test(['A'])
40
+ one_test(['B', 'C'])
41
+ one_test([0, 'C', [9, 'e'], true])
42
+ end
43
+
44
+ def test_hashes
45
+ one_test({:command => 'run', :binary => '/bin/sh', :quick => false})
46
+ one_test({:command => 'run', :args => { :key => 'v3', :log => true}})
47
+ end
48
+
49
+ def test_multiple_nested
50
+ one_test({:command => 'init', :user => "m\0e", :key => false },
51
+ {:command => 'package', :map => {'dir' => 1, 'NA' => true} },
52
+ "1234567890",
53
+ {:command => 'run', :sequence => [1, nil, 2, true, "Q\n"]})
54
+ end
55
+ end
@@ -0,0 +1,125 @@
1
+ require 'zerg_support'
2
+
3
+ require 'test/unit'
4
+
5
+ module OpenSSHData; end
6
+
7
+ class OpenSshTest < Test::Unit::TestCase
8
+ include OpenSSHData
9
+ OpenSSH = Zerg::Support::OpenSSH
10
+
11
+ def setup
12
+ @rsa_key = OpenSSH.load_key StringIO.new(obsidian_rsa_privkey)
13
+ @dsa_key = OpenSSH.load_key StringIO.new(obsidian_dsa_privkey)
14
+ end
15
+
16
+ @@mpi_test_table = [[0, "\0"], [0x80, "\0\x80"], [0x1234, "\x12\x34"],
17
+ [0xAA55, "\0\xAA\x55"]]
18
+ def test_encode_mpi
19
+ @@mpi_test_table.each {|e| assert_equal e.last, OpenSSH.encode_mpi(e.first) }
20
+ end
21
+
22
+ def test_decode_mpi
23
+ @@mpi_test_table.each {|e| assert_equal e.first, OpenSSH.decode_mpi(e.last) }
24
+ end
25
+
26
+ @@pubkey_pack_table = [[[], ''], [[''], "\0\0\0\0"],
27
+ [['A'], "\0\0\0\1A"],
28
+ [['A', 'BC'], "\0\0\0\1A\0\0\0\2BC"]]
29
+
30
+ def test_pack_pubkey_components
31
+ @@pubkey_pack_table.each do |e|
32
+ assert_equal e.last, OpenSSH.pack_pubkey_components(e.first)
33
+ end
34
+ end
35
+
36
+ def test_unpack_pubkey_components
37
+ @@pubkey_pack_table.each do |e|
38
+ assert_equal e.first, OpenSSH.unpack_pubkey_components(e.last)
39
+ end
40
+ end
41
+
42
+ def test_load_key
43
+ assert_equal obsidian_rsa_privkey, @rsa_key.to_pem
44
+ assert_equal obsidian_dsa_privkey, @dsa_key.to_pem
45
+ end
46
+
47
+ def test_encode_pubkey
48
+ assert_equal obsidian_rsa_pubkey, OpenSSH.encode_pubkey(@rsa_key)
49
+ assert_equal obsidian_dsa_pubkey, OpenSSH.encode_pubkey(@dsa_key)
50
+ end
51
+
52
+ def test_decode_pubkey
53
+ assert_equal @rsa_key.public_key.to_pem,
54
+ OpenSSH.decode_pubkey(obsidian_rsa_pubkey).to_pem
55
+ assert_equal @dsa_key.public_key.to_pem,
56
+ OpenSSH.decode_pubkey(obsidian_dsa_pubkey).to_pem
57
+ end
58
+ end
59
+
60
+ module OpenSSHData
61
+ def known_hosts_file
62
+ <<END_KH
63
+ github.com,65.74.177.129 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
64
+ obsidian.local ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq7VciLo2wB+/2ThHXejC/kgkN205zlyS5cvN40Mqi3qvRVS75X1RawDoLot8eJ9KCYqZFr2Dr73d/EQNltN7dKJoPIj1IKxoraWkyNFbhhzpYuOltg9oO5UBSTNLupqla7zcdj4IwCCkBYk4+TS0dwmi20buOJ0FPY5PgbzmMnUiV9ipBqeJSdZB+TePH1gqlt7AP/6ti/0gxb2K7F69dZl/BSxMEzRCfBlTFC3f/4n8IdCuSJvNxxY+TtRnLL5CKUhj9QaIBan6JCkdRvVOBY7wmsNT8nGDzfDFSDD3KKn93g4LRkyMeaYlSDLxKy8PnNhjWgBNH1YNYyicsGfBKQ==
65
+ rubyforge.org,205.234.109.19 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3tPhdPUFGAYyrT1quRSOevLbAdKAJ6Ovwqw0m99R0QkqUwMUh09pgedWZeij7HtAHtoWPrNFev8FrwcwnL14NgA/gwNnXxbqd4twC1HyFShUf7POry8bz3Qk+84STHeMY8++hhn8LgNyfuVQswHoW661aqieLM6pF8q8xIUtkXA7daNpJAL4nTN1TxgUoCDpCa0EbUPkGpwFPNtGPuokRXNOCR9g8T6LmPQbzGUTc4CzFfQ9rrHaimqkEmRWJbBOaik1bdQNqOh6MUDDuUSpkJV7fwu3bl4fF5/1kw2HCREEjJmESOYnZhOS+MCp1qAUcuXqpMqXD8ATNsuXqrIhTQ==
66
+ END_KH
67
+ end
68
+
69
+ def obsidian_rsa_pubkey
70
+ 'AAAAB3NzaC1yc2EAAAABIwAAAQEAq7VciLo2wB+/2ThHXejC/kgkN205zlyS5cvN40Mqi3qvRVS75X1RawDoLot8eJ9KCYqZFr2Dr73d/EQNltN7dKJoPIj1IKxoraWkyNFbhhzpYuOltg9oO5UBSTNLupqla7zcdj4IwCCkBYk4+TS0dwmi20buOJ0FPY5PgbzmMnUiV9ipBqeJSdZB+TePH1gqlt7AP/6ti/0gxb2K7F69dZl/BSxMEzRCfBlTFC3f/4n8IdCuSJvNxxY+TtRnLL5CKUhj9QaIBan6JCkdRvVOBY7wmsNT8nGDzfDFSDD3KKn93g4LRkyMeaYlSDLxKy8PnNhjWgBNH1YNYyicsGfBKQ=='
71
+ end
72
+
73
+ def obsidian_dsa_pubkey
74
+ 'AAAAB3NzaC1kc3MAAACBAPdWp4HhWUoNawosyEBvrhPSbjhCJiKnVWiUS6bo0BCGzTHhugrkv2HgtlKhWo8nqTw5E4YxzFVyZ0YQt4m7NYDLTZVjrqbIpL/3F5qNXco127O/im0cG27AKC8Jf7knmUTjd8EBhtK65tNDmxPtzKQtemlNTVPX1VccOn6eLtn1AAAAFQDtQC21TJrf/p5WNsU9UIJzO9/hIwAAAIEAgwTrIfleQMEAK9N3xeMVZpAGfSAoX6owLtk3z+iQ3rM9FRvM/CgezOgezLowJghkw/bcQDmMuudBUuijrM3zZWdr6eqoNbFTR/KKiUx3cYf0LAHNPbXfVz+P7BXqjcEj75qnwuHQMp7vNMg+dmV40UA2TiC5/8QlaZVwkOSPN6gAAACAPMGJEFkoR0ayfkd0S/tnY9ilO17T6rdoDuF25ATtNUd6Zji6tslxBkQFWtTeinO3rGkqJRPndq0wp3E33AOHhJE/FOIlWl4Tf6aeU95Y4enYujKQDiImSTXmdiw5wq/LFdc3a2waOUvuI+647wxgHhqTmD7xI2biGZLYN9Oasy0='
75
+ end
76
+
77
+ def obsidian_rsa_privkey
78
+ <<END_RSAK
79
+ -----BEGIN RSA PRIVATE KEY-----
80
+ MIIEoQIBAAKCAQEAq7VciLo2wB+/2ThHXejC/kgkN205zlyS5cvN40Mqi3qvRVS7
81
+ 5X1RawDoLot8eJ9KCYqZFr2Dr73d/EQNltN7dKJoPIj1IKxoraWkyNFbhhzpYuOl
82
+ tg9oO5UBSTNLupqla7zcdj4IwCCkBYk4+TS0dwmi20buOJ0FPY5PgbzmMnUiV9ip
83
+ BqeJSdZB+TePH1gqlt7AP/6ti/0gxb2K7F69dZl/BSxMEzRCfBlTFC3f/4n8IdCu
84
+ SJvNxxY+TtRnLL5CKUhj9QaIBan6JCkdRvVOBY7wmsNT8nGDzfDFSDD3KKn93g4L
85
+ RkyMeaYlSDLxKy8PnNhjWgBNH1YNYyicsGfBKQIBIwKCAQA/xwUc13Nr7okWKtit
86
+ 2hyKVU9HyXve7y8/aPSzf1jx+l5blIBN7LfXSXrPdaNCvtJbULyEygxXN+S8yNHY
87
+ 73b/b4XNV3D9gd281x/y0WsjL09fPpyitUP435LDatL8Ks+6TXZ1D7obedaFtqAi
88
+ DEMHpH5Rch33xUsW3RY3gK1F8GHzYh+zMd0llH8w6IVBv0hrWttyp+4By1dhXA3L
89
+ alYYOlGbu5cNuJfz50v4T/uB9F63JqHtAxEjqD7SvjCUbogGPxEH1k4Or+3xGuvR
90
+ yTPaiuR9kehBstjbqc91rTLnGOr5a1VUIq6++0tCVOXQa+x5J5zCu/baGTdfkgRU
91
+ loILAoGBAOHQcGIEgD1xHwFX9AafarF+1j4pPkM1p2u+9DNTIl1f2Rk6yOHlHZGF
92
+ mfozMyh6l4HpvPTT7nflM4YR0JWJNbQIpCY8CdYKMXBVWcH4PXuqwyGKJBZMXWkn
93
+ hKvelJ0UZUwx5+n8fTmSxLcIIlz5uKEE5k23/3cKkP7P6+Z6YuIZAoGBAMKpYBkM
94
+ A4JMJ3QJ5TVsdFOoO0b1wThRgQTZR6ic9rNeXnZiL0mmr44DX2T1rTnEm6KZv2f2
95
+ kWLQp5jx8BPFI+TUv16j4xrnnuHPhuBordCYQizSPcxXqL8b8a/KU+S5xofRjwB6
96
+ +8szd/JmGFDY8WgWrtIL32TdRhcIFg0Dg1mRAoGAE1sCUYtbcvsRSUINmirr41QD
97
+ vC9rvJ4y6/pss/Eu1M2zhdHWtEbWphLEDiGlTJzLKGR96Rl61xOlVKJw9t/gCB3/
98
+ cP3U9RbRCaDqb7YxJ9tvz6zBQ71nF6RNM02XtbFKgt+0yunBlzh3QuNwqOI0ZZK0
99
+ p5Ntqx4pr3DoVZV2MKMCgYBprGdeDdYE54MhvDqZWCHkRWIB8x+/fLPAzbkvpap+
100
+ oPFzdyD8GKhxqg82zoKbs991hqm8GCMJwboRMuFp0WtBtVHxjCrUF1ZAEZJckJje
101
+ 85GjTY9DCwPVdZHUdSY6VjiS33mD6v23c7YkgJDbbnRrtIrJy+5MsqJkRjfbLcr2
102
+ GwKBgQCWDKVM8mZJcmM3KJwzBWh+b5T7tIbOBFaCvOBq4G0UUZGytWVUaddSbdh5
103
+ YJ+1CoLDB+Wp3U95B1USQuSYwwr0wOYy42HBII7HnkaphT9HgDIhgvttFhX162oC
104
+ bRizr31NgiGtgJbHJ9QPhaLvn3mZtZAFfRaEEdZslUzqRSACww==
105
+ -----END RSA PRIVATE KEY-----
106
+ END_RSAK
107
+ end
108
+
109
+ def obsidian_dsa_privkey
110
+ <<END_DSAK
111
+ -----BEGIN DSA PRIVATE KEY-----
112
+ MIIBvAIBAAKBgQD3VqeB4VlKDWsKLMhAb64T0m44QiYip1VolEum6NAQhs0x4boK
113
+ 5L9h4LZSoVqPJ6k8OROGMcxVcmdGELeJuzWAy02VY66myKS/9xeajV3KNduzv4pt
114
+ HBtuwCgvCX+5J5lE43fBAYbSuubTQ5sT7cykLXppTU1T19VXHDp+ni7Z9QIVAO1A
115
+ LbVMmt/+nlY2xT1QgnM73+EjAoGBAIME6yH5XkDBACvTd8XjFWaQBn0gKF+qMC7Z
116
+ N8/okN6zPRUbzPwoHszoHsy6MCYIZMP23EA5jLrnQVLoo6zN82Vna+nqqDWxU0fy
117
+ iolMd3GH9CwBzT2131c/j+wV6o3BI++ap8Lh0DKe7zTIPnZleNFANk4guf/EJWmV
118
+ cJDkjzeoAoGAPMGJEFkoR0ayfkd0S/tnY9ilO17T6rdoDuF25ATtNUd6Zji6tslx
119
+ BkQFWtTeinO3rGkqJRPndq0wp3E33AOHhJE/FOIlWl4Tf6aeU95Y4enYujKQDiIm
120
+ STXmdiw5wq/LFdc3a2waOUvuI+647wxgHhqTmD7xI2biGZLYN9Oasy0CFQDL/9Z1
121
+ fSLn88m1sUeWAZ4Ys2IIxw==
122
+ -----END DSA PRIVATE KEY-----
123
+ END_DSAK
124
+ end
125
+ end
data/test/test_process.rb CHANGED
@@ -4,6 +4,11 @@ require 'test/unit'
4
4
  require 'zerg_support'
5
5
 
6
6
  class TestProcess < Test::Unit::TestCase
7
+ def teardown
8
+ @pid_files.each { |f| File.delete f rescue nil } if @pid_files
9
+ super
10
+ end
11
+
7
12
  def test_process_info
8
13
  info = Zerg::Support::Process.process_info($PID)
9
14
  assert info, 'Failed to find current process'
@@ -20,18 +25,21 @@ class TestProcess < Test::Unit::TestCase
20
25
  assert list[$PID], 'Process list does not contain current process'
21
26
  end
22
27
 
23
- # spawn 2^exp children, and their command lines will contain "cookie"
28
+ # spawn 2^(exp+1)-1 children, and their command lines will contain "cookie"
24
29
  def spawn_sleepers(exp, cookie)
25
- unless child_pid = fork
26
- exp.times { fork }
27
- exec 'ruby', '-e', 'sleep 100', '--', cookie
28
- end
29
- sleep 0.5
30
- return child_pid
30
+ Thread.new { system "ruby test/fork_tree.rb -- #{exp} 100 #{cookie}" }
31
+ on_windows = RUBY_PLATFORM =~ /win/ && RUBY_PLATFORM !~ /darwin/
32
+ sleep on_windows ? 0.5 : 0.1
33
+ pid_file = "#{cookie}.pid"
34
+ @pid_files ||= []
35
+ @pid_files << pid_file
36
+ pid = File.read(pid_file).to_i
37
+ sleep on_windows ? 0.4 : 0.5
38
+ return pid
31
39
  end
32
40
 
33
41
  def now_cookie
34
- "zerg_test_#{Time.now.to_f}"
42
+ "zerg_test_#{Time.now.to_f}s"
35
43
  end
36
44
 
37
45
  def test_process_tree
@@ -39,9 +47,11 @@ class TestProcess < Test::Unit::TestCase
39
47
  root_pid = spawn_sleepers 3, cookie
40
48
 
41
49
  tree_processes = Zerg::Support::Process.process_tree root_pid
42
- assert_equal 8, tree_processes.length, 'Missed some processes'
50
+ assert_equal 15, tree_processes.length, 'Missed some processes'
43
51
  assert tree_processes.all? { |info| info[:command_line].index cookie },
44
52
  'Got the wrong processes'
53
+
54
+ Zerg::Support::Process.kill_tree root_pid
45
55
  end
46
56
 
47
57
  def test_kill