zerg_support 0.0.5 → 0.0.8

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,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