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.
- data/CHANGELOG +6 -0
- data/Manifest +10 -0
- data/README +0 -61
- data/RUBYFORGE +40 -0
- data/Rakefile +8 -5
- data/lib/zerg_support/event_machine/connection_mocks.rb +46 -0
- data/lib/zerg_support/event_machine/frame_protocol.rb +68 -0
- data/lib/zerg_support/event_machine/object_protocol.rb +24 -0
- data/lib/zerg_support/gems.rb +33 -9
- data/lib/zerg_support/open_ssh.rb +104 -0
- data/lib/zerg_support/process.rb +65 -23
- data/lib/zerg_support/spawn.rb +65 -6
- data/lib/zerg_support.rb +10 -0
- data/test/fork_tree.rb +34 -0
- data/test/test_connection_mocks.rb +57 -0
- data/test/test_frame_protocol.rb +119 -0
- data/test/test_gems.rb +1 -1
- data/test/test_object_protocol.rb +55 -0
- data/test/test_open_ssh.rb +125 -0
- data/test/test_process.rb +19 -9
- data/test/test_spawn.rb +44 -18
- data/zerg_support.gemspec +18 -10
- metadata +44 -6
data/lib/zerg_support/spawn.rb
CHANGED
@@ -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
|
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
|
-
|
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 =>
|
15
|
-
:creation_flags =>
|
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
|
-
|
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 = '
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
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
|