net-ssh-multi 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,152 @@
1
+ require 'common'
2
+ require 'net/ssh/multi/channel'
3
+
4
+ class ChannelTest < Test::Unit::TestCase
5
+ def test_each_should_iterate_over_each_component_channel
6
+ channels = [c1 = mock('channel'), c2 = mock('channel'), c3 = mock('channel')]
7
+ channel = Net::SSH::Multi::Channel.new(mock('session'), channels)
8
+ result = []
9
+ channel.each { |c| result << c }
10
+ assert_equal channels, result
11
+ end
12
+
13
+ def test_property_accessors
14
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [])
15
+ channel[:foo] = "hello"
16
+ assert_equal "hello", channel[:foo]
17
+ channel['bar'] = "goodbye"
18
+ assert_equal "goodbye", channel['bar']
19
+ assert_nil channel[:bar]
20
+ assert_nil channel['foo']
21
+ end
22
+
23
+ def test_exec_should_delegate_to_component_channels
24
+ c1, c2, results = mock('channel'), mock('channel'), []
25
+ c1.expects(:exec).with('ls -l').yields(c1)
26
+ c2.expects(:exec).with('ls -l').yields(c2)
27
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
28
+ assert_equal channel, channel.exec('ls -l') { |c| results << c }
29
+ assert_equal [c1, c2], results
30
+ end
31
+
32
+ def test_request_pty_should_delegate_to_component_channels
33
+ c1, c2, results = mock('channel'), mock('channel'), []
34
+ c1.expects(:request_pty).with(:foo => 5).yields(c1)
35
+ c2.expects(:request_pty).with(:foo => 5).yields(c2)
36
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
37
+ assert_equal channel, channel.request_pty(:foo => 5) { |c| results << c }
38
+ assert_equal [c1, c2], results
39
+ end
40
+
41
+ def test_send_data_should_delegate_to_component_channels
42
+ c1, c2 = mock('channel'), mock('channel')
43
+ c1.expects(:send_data).with("hello\n")
44
+ c2.expects(:send_data).with("hello\n")
45
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
46
+ assert_equal channel, channel.send_data("hello\n")
47
+ end
48
+
49
+ def test_active_should_be_true_if_all_component_channels_are_active
50
+ c1, c2, c3 = stub('channel', :active? => true), stub('channel', :active? => true), stub('channel', :active? => true)
51
+ channel = Net::SSH::Multi::Channel.new(stub('session'), [c1, c2, c3])
52
+ assert channel.active?
53
+ end
54
+
55
+ def test_active_should_be_true_if_any_component_channels_are_active
56
+ c1, c2, c3 = stub('channel', :active? => true), stub('channel', :active? => false), stub('channel', :active? => false)
57
+ channel = Net::SSH::Multi::Channel.new(stub('session'), [c1, c2, c3])
58
+ assert channel.active?
59
+ end
60
+
61
+ def test_active_should_be_false_if_no_component_channels_are_active
62
+ c1, c2, c3 = stub('channel', :active? => false), stub('channel', :active? => false), stub('channel', :active? => false)
63
+ channel = Net::SSH::Multi::Channel.new(stub('session'), [c1, c2, c3])
64
+ assert !channel.active?
65
+ end
66
+
67
+ def test_wait_should_block_until_active_is_false
68
+ channel = Net::SSH::Multi::Channel.new(MockSession.new, [])
69
+ channel.expects(:active?).times(4).returns(true,true,true,false)
70
+ assert_equal channel, channel.wait
71
+ end
72
+
73
+ def test_close_should_delegate_to_component_channels
74
+ c1, c2 = mock('channel'), mock('channel')
75
+ c1.expects(:close)
76
+ c2.expects(:close)
77
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
78
+ assert_equal channel, channel.close
79
+ end
80
+
81
+ def test_eof_bang_should_delegate_to_component_channels
82
+ c1, c2 = mock('channel'), mock('channel')
83
+ c1.expects(:eof!)
84
+ c2.expects(:eof!)
85
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
86
+ assert_equal channel, channel.eof!
87
+ end
88
+
89
+ def test_on_data_should_delegate_to_component_channels
90
+ c1, c2, results = mock('channel'), mock('channel'), []
91
+ c1.expects(:on_data).yields(c1)
92
+ c2.expects(:on_data).yields(c2)
93
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
94
+ assert_equal channel, channel.on_data { |c| results << c }
95
+ assert_equal [c1, c2], results
96
+ end
97
+
98
+ def test_on_extended_data_should_delegate_to_component_channels
99
+ c1, c2, results = mock('channel'), mock('channel'), []
100
+ c1.expects(:on_extended_data).yields(c1)
101
+ c2.expects(:on_extended_data).yields(c2)
102
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
103
+ assert_equal channel, channel.on_extended_data { |c| results << c }
104
+ assert_equal [c1, c2], results
105
+ end
106
+
107
+ def test_on_process_should_delegate_to_component_channels
108
+ c1, c2, results = mock('channel'), mock('channel'), []
109
+ c1.expects(:on_process).yields(c1)
110
+ c2.expects(:on_process).yields(c2)
111
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
112
+ assert_equal channel, channel.on_process { |c| results << c }
113
+ assert_equal [c1, c2], results
114
+ end
115
+
116
+ def test_on_close_should_delegate_to_component_channels
117
+ c1, c2, results = mock('channel'), mock('channel'), []
118
+ c1.expects(:on_close).yields(c1)
119
+ c2.expects(:on_close).yields(c2)
120
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
121
+ assert_equal channel, channel.on_close { |c| results << c }
122
+ assert_equal [c1, c2], results
123
+ end
124
+
125
+ def test_on_eof_should_delegate_to_component_channels
126
+ c1, c2, results = mock('channel'), mock('channel'), []
127
+ c1.expects(:on_eof).yields(c1)
128
+ c2.expects(:on_eof).yields(c2)
129
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
130
+ assert_equal channel, channel.on_eof { |c| results << c }
131
+ assert_equal [c1, c2], results
132
+ end
133
+
134
+ def test_on_request_should_delegate_to_component_channels
135
+ c1, c2, results = mock('channel'), mock('channel'), []
136
+ c1.expects(:on_request).with("exit-status").yields(c1)
137
+ c2.expects(:on_request).with("exit-status").yields(c2)
138
+ channel = Net::SSH::Multi::Channel.new(mock('session'), [c1, c2])
139
+ assert_equal channel, channel.on_request("exit-status") { |c| results << c }
140
+ assert_equal [c1, c2], results
141
+ end
142
+
143
+ private
144
+
145
+ class MockSession
146
+ def loop
147
+ while true do
148
+ return if !yield(self)
149
+ end
150
+ end
151
+ end
152
+ end
data/test/common.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require 'mocha'
@@ -0,0 +1,20 @@
1
+ require 'common'
2
+ require 'net/ssh/multi'
3
+
4
+ class MultiTest < Test::Unit::TestCase
5
+ def test_start_with_block_should_yield_session_and_then_close
6
+ Net::SSH::Multi::Session.any_instance.expects(:loop)
7
+ Net::SSH::Multi::Session.any_instance.expects(:close)
8
+ yielded = false
9
+ Net::SSH::Multi.start do |session|
10
+ yielded = true
11
+ assert_instance_of Net::SSH::Multi::Session, session
12
+ end
13
+ end
14
+
15
+ def test_start_without_block_should_return_open_session
16
+ Net::SSH::Multi::Session.any_instance.expects(:loop).never
17
+ Net::SSH::Multi::Session.any_instance.expects(:close).never
18
+ assert_instance_of Net::SSH::Multi::Session, Net::SSH::Multi.start
19
+ end
20
+ end
@@ -0,0 +1,256 @@
1
+ require 'common'
2
+ require 'net/ssh/multi/server'
3
+
4
+ class ServerTest < Test::Unit::TestCase
5
+ def setup
6
+ @master = stub('multi-session', :default_user => "bob")
7
+ end
8
+
9
+ def test_accessor_without_properties_should_access_empty_hash
10
+ assert_nil server('host')[:foo]
11
+ end
12
+
13
+ def test_accessor_with_properties_should_access_properties
14
+ assert_equal "hello", server('host', :properties => { :foo => "hello" })[:foo]
15
+ end
16
+
17
+ def test_port_should_return_22_by_default
18
+ assert_equal 22, server('host').port
19
+ end
20
+
21
+ def test_port_should_return_given_port_when_present
22
+ assert_equal 1234, server('host', :port => 1234).port
23
+ end
24
+
25
+ def test_port_should_return_parsed_port_when_present
26
+ assert_equal 1234, server('host:1234', :port => 1235).port
27
+ end
28
+
29
+ def test_user_should_return_default_user_by_default
30
+ assert_equal "bob", server('host').user
31
+ end
32
+
33
+ def test_user_should_return_given_user_when_present
34
+ assert_equal "jim", server('host', :user => "jim").user
35
+ end
36
+
37
+ def test_user_should_return_parsed_user_when_present
38
+ assert_equal "jim", server('jim@host', :user => "john").user
39
+ end
40
+
41
+ def test_equivalence_when_host_and_user_and_port_match
42
+ s1 = server('user@host:1234')
43
+ s2 = server('user@host:1234')
44
+ assert s1.eql?(s2)
45
+ assert_equal s1.hash, s2.hash
46
+ assert s1 == s2
47
+ end
48
+
49
+ def test_equivalence_when_host_mismatch
50
+ s1 = server('user@host1:1234')
51
+ s2 = server('user@host2:1234')
52
+ assert !s1.eql?(s2)
53
+ assert_not_equal s1.hash, s2.hash
54
+ assert s1 != s2
55
+ end
56
+
57
+ def test_equivalence_when_port_mismatch
58
+ s1 = server('user@host:1234')
59
+ s2 = server('user@host:1235')
60
+ assert !s1.eql?(s2)
61
+ assert_not_equal s1.hash, s2.hash
62
+ assert s1 != s2
63
+ end
64
+
65
+ def test_equivalence_when_user_mismatch
66
+ s1 = server('user1@host:1234')
67
+ s2 = server('user2@host:1234')
68
+ assert !s1.eql?(s2)
69
+ assert_not_equal s1.hash, s2.hash
70
+ assert s1 != s2
71
+ end
72
+
73
+ def test_to_s_should_include_user_and_host
74
+ assert_equal "user@host", server('user@host').to_s
75
+ end
76
+
77
+ def test_to_s_should_include_user_and_host_and_port_when_port_is_given
78
+ assert_equal "user@host:1234", server('user@host:1234').to_s
79
+ end
80
+
81
+ def test_gateway_should_be_nil_by_default
82
+ assert_nil server('host').gateway
83
+ end
84
+
85
+ def test_gateway_should_be_set_with_the_via_value
86
+ gateway = mock('gateway')
87
+ assert_equal gateway, server('host', :via => gateway).gateway
88
+ end
89
+
90
+ def test_session_with_default_argument_should_not_instantiate_session
91
+ assert_nil server('host').session
92
+ end
93
+
94
+ def test_session_with_true_argument_should_instantiate_and_cache_session
95
+ srv = server('host')
96
+ session = expect_connection_to(srv)
97
+ assert_equal session, srv.session(true)
98
+ assert_equal session, srv.session(true)
99
+ assert_equal session, srv.session
100
+ end
101
+
102
+ def test_session_that_cannot_authenticate_adds_host_to_exception_message
103
+ srv = server('host')
104
+ Net::SSH.expects(:start).with('host', 'bob', {}).raises(Net::SSH::AuthenticationFailed.new('bob'))
105
+
106
+ begin
107
+ srv.new_session
108
+ flunk
109
+ rescue Net::SSH::AuthenticationFailed => e
110
+ assert_equal "bob@host", e.message
111
+ end
112
+ end
113
+
114
+ def test_close_channels_when_session_is_not_open_should_not_do_anything
115
+ assert_nothing_raised { server('host').close_channels }
116
+ end
117
+
118
+ def test_close_channels_when_session_is_open_should_iterate_over_open_channels_and_close_them
119
+ srv = server('host')
120
+ session = expect_connection_to(srv)
121
+ c1 = mock('channel', :close => nil)
122
+ c2 = mock('channel', :close => nil)
123
+ c3 = mock('channel', :close => nil)
124
+ session.expects(:channels).returns(1 => c1, 2 => c2, 3 => c3)
125
+ assert_equal session, srv.session(true)
126
+ srv.close_channels
127
+ end
128
+
129
+ def test_close_when_session_is_not_open_should_not_do_anything
130
+ assert_nothing_raised { server('host').close }
131
+ end
132
+
133
+ def test_close_when_session_is_open_should_close_session
134
+ srv = server('host')
135
+ session = expect_connection_to(srv)
136
+ session.expects(:close)
137
+ @master.expects(:server_closed).with(srv)
138
+ assert_equal session, srv.session(true)
139
+ srv.close
140
+ end
141
+
142
+ def test_busy_should_be_false_when_session_is_not_open
143
+ assert !server('host').busy?
144
+ end
145
+
146
+ def test_busy_should_be_false_when_session_is_not_busy
147
+ srv = server('host')
148
+ session = expect_connection_to(srv)
149
+ session.expects(:busy?).returns(false)
150
+ srv.session(true)
151
+ assert !srv.busy?
152
+ end
153
+
154
+ def test_busy_should_be_true_when_session_is_busy
155
+ srv = server('host')
156
+ session = expect_connection_to(srv)
157
+ session.expects(:busy?).returns(true)
158
+ srv.session(true)
159
+ assert srv.busy?
160
+ end
161
+
162
+ def test_preprocess_should_be_nil_when_session_is_not_open
163
+ assert_nil server('host').preprocess
164
+ end
165
+
166
+ def test_preprocess_should_return_result_of_session_preprocess
167
+ srv = server('host')
168
+ session = expect_connection_to(srv)
169
+ session.expects(:preprocess).returns(:result)
170
+ srv.session(true)
171
+ assert_equal :result, srv.preprocess
172
+ end
173
+
174
+ def test_readers_should_return_empty_array_when_session_is_not_open
175
+ assert_equal [], server('host').readers
176
+ end
177
+
178
+ def test_readers_should_return_all_listeners_when_session_is_open
179
+ srv = server('host')
180
+ session = expect_connection_to(srv)
181
+ io1, io2, io3, io4 = Reader.new, Reader.new, Reader.new, Reader.new
182
+ session.expects(:listeners).returns(io1 => 2, io2 => 4, io3 => 6, io4 => 8)
183
+ srv.session(true)
184
+ assert_equal [io1, io2, io3, io4], srv.readers.sort
185
+ end
186
+
187
+ def test_writers_should_return_empty_array_when_session_is_not_open
188
+ assert_equal [], server('host').writers
189
+ end
190
+
191
+ def test_writers_should_return_all_listeners_that_are_pending_writes_when_session_is_open
192
+ srv = server('host')
193
+ session = expect_connection_to(srv)
194
+ listeners = { Reader.new(true) => 1, MockIO.new => 2,
195
+ MockIO.new => 3, Reader.new => 4, Reader.new(true) => 5 }
196
+ session.expects(:listeners).returns(listeners)
197
+ srv.session(true)
198
+ assert_equal 2, srv.writers.length
199
+ end
200
+
201
+ def test_postprocess_should_return_true_when_session_is_not_open
202
+ assert_equal true, server('host').postprocess([], [])
203
+ end
204
+
205
+ def test_postprocess_should_call_session_postprocess_with_ios_belonging_to_session
206
+ srv = server('host')
207
+ session = expect_connection_to(srv)
208
+ session.expects(:listeners).returns(1 => 2, 3 => 4, 5 => 6, 7 => 8)
209
+ session.expects(:postprocess).with([1,3], [7]).returns(:result)
210
+ srv.session(true)
211
+ assert_equal :result, srv.postprocess([1,11,3], [18,14,7,12])
212
+ end
213
+
214
+ private
215
+
216
+ class MockIO
217
+ include Comparable
218
+
219
+ @@identifier = 0
220
+
221
+ attr_reader :id
222
+
223
+ def initialize
224
+ @id = (@@identifier += 1)
225
+ end
226
+
227
+ def <=>(io)
228
+ @id <=> io.id
229
+ end
230
+
231
+ def closed?
232
+ false
233
+ end
234
+ end
235
+
236
+ class Reader < MockIO
237
+ def initialize(ready=false)
238
+ super()
239
+ @ready = ready
240
+ end
241
+
242
+ def pending_write?
243
+ @ready
244
+ end
245
+ end
246
+
247
+ def server(host, options={})
248
+ Net::SSH::Multi::Server.new(@master, host, options)
249
+ end
250
+
251
+ def expect_connection_to(server)
252
+ session = {}
253
+ @master.expects(:next_session).with(server).returns(session)
254
+ return session
255
+ end
256
+ end
@@ -0,0 +1,128 @@
1
+ require 'common'
2
+ require 'net/ssh/multi/server'
3
+ require 'net/ssh/multi/session_actions'
4
+
5
+ class SessionActionsTest < Test::Unit::TestCase
6
+ class SessionActionsContainer
7
+ include Net::SSH::Multi::SessionActions
8
+
9
+ attr_reader :servers
10
+
11
+ def initialize
12
+ @servers = []
13
+ end
14
+
15
+ def default_user
16
+ "user"
17
+ end
18
+
19
+ def use(h, o={})
20
+ server = Net::SSH::Multi::Server.new(self, h, o)
21
+ servers << server
22
+ server
23
+ end
24
+ end
25
+
26
+ def setup
27
+ @session = SessionActionsContainer.new
28
+ end
29
+
30
+ def test_busy_should_be_true_if_any_server_is_busy
31
+ srv1, srv2, srv3 = @session.use('h1'), @session.use('h2'), @session.use('h3')
32
+ srv1.stubs(:busy?).returns(false)
33
+ srv2.stubs(:busy?).returns(false)
34
+ srv3.stubs(:busy?).returns(true)
35
+ assert @session.busy?
36
+ end
37
+
38
+ def test_busy_should_be_false_if_all_servers_are_not_busy
39
+ srv1, srv2, srv3 = @session.use('h1'), @session.use('h2'), @session.use('h3')
40
+ srv1.stubs(:busy?).returns(false)
41
+ srv2.stubs(:busy?).returns(false)
42
+ srv3.stubs(:busy?).returns(false)
43
+ assert !@session.busy?
44
+ end
45
+
46
+ def test_send_global_request_should_delegate_to_sessions
47
+ s1 = mock('ssh')
48
+ s2 = mock('ssh')
49
+ s1.expects(:send_global_request).with("a", "b", "c").yields
50
+ s2.expects(:send_global_request).with("a", "b", "c").yields
51
+ @session.expects(:sessions).returns([s1, s2])
52
+ calls = 0
53
+ @session.send_global_request("a", "b", "c") { calls += 1 }
54
+ assert_equal 2, calls
55
+ end
56
+
57
+ def test_open_channel_should_delegate_to_sessions_and_set_accessors_on_each_channel_and_return_multi_channel
58
+ srv1 = @session.use('h1')
59
+ srv2 = @session.use('h2')
60
+ s1 = { :server => srv1 }
61
+ s2 = { :server => srv2 }
62
+ c1 = { :stub => :value }
63
+ c2 = {}
64
+ c1.stubs(:connection).returns(s1)
65
+ c2.stubs(:connection).returns(s2)
66
+ @session.expects(:sessions).returns([s1, s2])
67
+ s1.expects(:open_channel).with("session").yields(c1).returns(c1)
68
+ s2.expects(:open_channel).with("session").yields(c2).returns(c2)
69
+ results = []
70
+ channel = @session.open_channel do |c|
71
+ results << c
72
+ end
73
+ assert_equal [c1, c2], results
74
+ assert_equal "h1", c1[:host]
75
+ assert_equal "h2", c2[:host]
76
+ assert_equal srv1, c1[:server]
77
+ assert_equal srv2, c2[:server]
78
+ assert_instance_of Net::SSH::Multi::Channel, channel
79
+ assert_equal [c1, c2], channel.channels
80
+ end
81
+
82
+ def test_exec_should_raise_exception_if_channel_cannot_exec_command
83
+ c = { :host => "host" }
84
+ @session.expects(:open_channel).yields(c).returns(c)
85
+ c.expects(:exec).with('something').yields(c, false)
86
+ assert_raises(RuntimeError) { @session.exec("something") }
87
+ end
88
+
89
+ def test_exec_with_block_should_pass_data_and_extended_data_to_block
90
+ c = { :host => "host" }
91
+ @session.expects(:open_channel).yields(c).returns(c)
92
+ c.expects(:exec).with('something').yields(c, true)
93
+ c.expects(:on_data).yields(c, "stdout")
94
+ c.expects(:on_extended_data).yields(c, 1, "stderr")
95
+ c.expects(:on_request)
96
+ results = {}
97
+ @session.exec("something") do |c, stream, data|
98
+ results[stream] = data
99
+ end
100
+ assert_equal({:stdout => "stdout", :stderr => "stderr"}, results)
101
+ end
102
+
103
+ def test_exec_without_block_should_write_data_and_extended_data_lines_to_stdout_and_stderr
104
+ c = { :host => "host" }
105
+ @session.expects(:open_channel).yields(c).returns(c)
106
+ c.expects(:exec).with('something').yields(c, true)
107
+ c.expects(:on_data).yields(c, "stdout 1\nstdout 2\n")
108
+ c.expects(:on_extended_data).yields(c, 1, "stderr 1\nstderr 2\n")
109
+ c.expects(:on_request)
110
+ $stdout.expects(:puts).with("[host] stdout 1\n")
111
+ $stdout.expects(:puts).with("[host] stdout 2")
112
+ $stderr.expects(:puts).with("[host] stderr 1\n")
113
+ $stderr.expects(:puts).with("[host] stderr 2")
114
+ @session.exec("something")
115
+ end
116
+
117
+ def test_exec_should_capture_exit_status_of_process
118
+ c = { :host => "host" }
119
+ @session.expects(:open_channel).yields(c).returns(c)
120
+ c.expects(:exec).with('something').yields(c, true)
121
+ c.expects(:on_data)
122
+ c.expects(:on_extended_data)
123
+ c.expects(:on_request).with("exit-status").yields(c, Net::SSH::Buffer.from(:long, 127))
124
+ @session.exec("something")
125
+ assert_equal 127, c[:exit_status]
126
+ end
127
+
128
+ end