net-ssh-simple 1.1.1 → 1.2.0

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/.gitignore CHANGED
@@ -5,3 +5,4 @@ pkg/*
5
5
  .yardoc
6
6
  coverage.data
7
7
  coverage
8
+ sync
data/README.rdoc CHANGED
@@ -55,7 +55,22 @@ Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.
55
55
  s.scp_ul 'example2.com', '/tmp/local_foo', '/tmp/remote_bar'
56
56
  s.scp_dl 'example3.com', '/tmp/remote_foo', '/tmp/local_bar'
57
57
  s.close
58
-
58
+
59
+ === Handling a Timeout
60
+
61
+ require 'net/ssh/simple'
62
+
63
+ # Hint: Set timeout=0 to disable, default is 60
64
+ begin
65
+ Net::SSH::Simple.sync({:timeout => 5}) do
66
+ ssh('example1.com', 'sleep 1') # I will (probably) succeed!
67
+ ssh('example2.com', 'sleep 60') # I will fail :(
68
+ end
69
+ rescue Net::SSH::Simple::Error => e
70
+ puts e.result.timed_out #=> true
71
+ end
72
+
73
+
59
74
  == Documentation
60
75
 
61
76
  See {Net::SSH::Simple}[http://rubydoc.info/gems/net-ssh-simple/Net/SSH/Simple] for more examples and full API.
data/Rakefile CHANGED
@@ -8,10 +8,16 @@ task :default => :test
8
8
  RSpec::Core::RakeTask.new("test:spec") do |t|
9
9
  t.pattern = 'spec/*.rb'
10
10
  t.rcov = false
11
- #t.rspec_opts = '-b -c -f progress'
12
- t.rspec_opts = '-b -c -f documentation'
11
+ t.rspec_opts = '-b -c -f progress --tag ~benchmark'
13
12
  end
14
13
 
14
+ RSpec::Core::RakeTask.new("test:benchmark") do |t|
15
+ t.pattern = 'spec/*.rb'
16
+ t.rcov = false
17
+ t.rspec_opts = '-b -c -f documentation --tag benchmark'
18
+ end
19
+
20
+
15
21
  namespace :test do
16
22
  task :coverage do
17
23
  require 'cover_me'
@@ -1,7 +1,7 @@
1
1
  require 'net/ssh/simple/version'
2
2
  require 'blockenspiel'
3
3
  require 'hashie'
4
+ require 'timeout'
4
5
  require 'net/ssh'
5
6
  require 'net/scp'
6
7
  require 'net/ssh/simple/core'
7
-
@@ -66,8 +66,8 @@ module Net
66
66
  # rescue Net::SSH::Simple::Error => e
67
67
  # puts "Something bad happened!"
68
68
  # puts e # Human readable error
69
- # puts e.wrapped # Original Exception from Net::SSH
70
- # puts e.context # Config that triggered the error
69
+ # puts e.wrapped # Original Exception
70
+ # puts e.result # Net::SSH::Simple::Result (partial result)
71
71
  # end
72
72
  #
73
73
  # @example
@@ -115,8 +115,8 @@ module Net
115
115
  # rescue Net::SSH::Simple::Error => e
116
116
  # puts "Something bad happened!"
117
117
  # puts e # Human readable error
118
- # puts e.wrapped # Original Exception from Net::SSH
119
- # puts e.context # Config that triggered the error
118
+ # puts e.wrapped # Original Exception
119
+ # puts e.result # Net::SSH::Simple::Result (partial result)
120
120
  # ensure
121
121
  # s.close # don't forget the clean up!
122
122
  # end
@@ -128,6 +128,27 @@ module Net
128
128
  # {:user => 'tom', :password => 'jerry', :port => 1234})
129
129
  # end
130
130
  #
131
+ # # Parameter inheritance
132
+ # Net::SSH::Simple.sync({:user => 'tom', :port => 1234}) do
133
+ # # Both commands will inherit :user and :port
134
+ # ssh('example1.com', 'echo "Hello World."', {:password => 'jerry'})
135
+ # scp_ul('example2.com', '/tmp/a', '/tmp/a', {:password => 's3cr3t'})
136
+ # end
137
+ #
138
+ # @example
139
+ # # Timeout handling
140
+ # #
141
+ # # Note: The timeout applies to each command independently.
142
+ # # Hint: Set timeout=0 to disable, default is 60
143
+ # begin
144
+ # Net::SSH::Simple.sync({:timeout => 5}) do
145
+ # ssh('example1.com', 'sleep 1') # I will (probably) succeed!
146
+ # ssh('example2.com', 'sleep 60') # I will fail :(
147
+ # end
148
+ # rescue Net::SSH::Simple::Error => e
149
+ # puts e.result.timed_out #=> true
150
+ # end
151
+ #
131
152
  # @example
132
153
  # # Using the SCP progress callback
133
154
  # Net::SSH::Simple.sync do
@@ -229,9 +250,9 @@ module Net
229
250
  # @param (see Net::SSH::Simple#ssh)
230
251
  # @raise [Net::SSH::Simple::Error]
231
252
  # @return [Net::SSH::Simple::Result] Result
232
- def self.ssh(*args)
253
+ def self.ssh(*args, &block)
233
254
  s = self.new
234
- r = s.ssh(*args)
255
+ r = s.ssh(*args, &block)
235
256
  s.close
236
257
  r
237
258
  end
@@ -297,6 +318,7 @@ module Net
297
318
  # @return [Net::SSH::Simple::Result] Result
298
319
  #
299
320
  def scp_ul(host, src, dst, opts={}, &block)
321
+ opts = @opts.merge(opts)
300
322
  scp(:upload, host, src, dst, opts, &block)
301
323
  end
302
324
 
@@ -307,12 +329,13 @@ module Net
307
329
  #
308
330
  # @param [String] host Destination hostname or ip-address
309
331
  # @param [String] cmd Shell command to execute
310
- # @param [Hash] opts Parameters for the underlying Net::SSH
332
+ # @param opts (see Net::SSH::Simple#ssh)
311
333
  # @param [Block] &block Progress callback (optional)
312
334
  # @return [Net::SSH::Simple::Result] Result
313
335
  # @see Net::SSH::Simple#scp_ul
314
336
  #
315
337
  def scp_dl(host, src, dst, opts={}, &block)
338
+ opts = @opts.merge(opts)
316
339
  scp(:download, host, src, dst, opts, &block)
317
340
  end
318
341
 
@@ -324,8 +347,8 @@ module Net
324
347
  # @return [Net::SSH::Simple::Result] Result
325
348
  # @param [String] host Destination hostname or ip-address
326
349
  # @param [String] cmd Shell command to execute
327
- # @param [Hash] opts Parameters for the underlying Net::SSH
328
350
  # @param [Block] &block Use the event-API (see example above)
351
+ # @param [Hash] opts SSH options
329
352
  # @option opts [Array] :auth_methods
330
353
  # an array of authentication methods to try
331
354
  #
@@ -399,7 +422,7 @@ module Net
399
422
  # the port to use when connecting to the remote host
400
423
  #
401
424
  # @option opts [Hash] :properties
402
- # a hash of key/value pairs to add to the new connections properties
425
+ # a hash of key/value pairs to add to the new connection's properties
403
426
  # (see Net::SSH::Connection::Session#properties)
404
427
  #
405
428
  # @option opts [String] :proxy
@@ -414,8 +437,8 @@ module Net
414
437
  # @option opts [Integer] :rekey_packet_limit
415
438
  # the max number of packets to process before rekeying
416
439
  #
417
- # @option opts [Integer] :timeout
418
- # how long to wait for the initial connection to be made
440
+ # @option opts [Integer] :timeout (60)
441
+ # connection timeout. this is enforced by Net::SSH::Simple.
419
442
  #
420
443
  # @option opts [String] :user
421
444
  # the username to log in as
@@ -434,10 +457,11 @@ module Net
434
457
  # @see http://net-ssh.github.com/ssh/v2/api/classes/Net/SSH/Config.html
435
458
  # Net::SSH documentation for the 'opts'-hash
436
459
  def ssh(host, cmd, opts={}, &block)
460
+ opts = @opts.merge(opts)
437
461
  with_session(host, opts) do |session|
438
462
  @result = Result.new(
439
- { :host => host, :cmd => cmd, :start_at => Time.new,
440
- :stdout => '' , :stderr => '' , :success => nil
463
+ { :op => :ssh, :host => host, :cmd => cmd, :start_at => Time.new,
464
+ :opts => opts, :stdout => '', :stderr => '', :success => nil
441
465
  } )
442
466
 
443
467
  channel = session.open_channel do |chan|
@@ -477,7 +501,8 @@ module Net
477
501
 
478
502
  dsl_methods false
479
503
 
480
- def initialize()
504
+ def initialize(opts={})
505
+ @opts = opts
481
506
  @sessions = {}
482
507
  @result = Result.new
483
508
  end
@@ -486,23 +511,25 @@ module Net
486
511
  # Spawn a Thread to perform a sequence of ssh/scp operations.
487
512
  #
488
513
  # @param [Block] block
514
+ # @param opts (see Net::SSH::Simple#ssh)
489
515
  # @return [Thread] Thread executing the SSH-Block.
490
516
  #
491
- def self.async(&block)
517
+ def self.async(opts={}, &block)
492
518
  Thread.new do
493
- self.sync(&block)
519
+ self.sync(opts, &block)
494
520
  end
495
521
  end
496
522
 
497
523
  #
498
524
  # Perform a sequence of ssh/scp operations.
499
525
  #
526
+ # @param opts (see Net::SSH::Simple#ssh)
500
527
  # @return [Net::SSH::Simple::Result] Result
501
528
  #
502
- def self.sync(&block)
503
- b = self.new
504
- r = Blockenspiel.invoke(block, b)
505
- b.close
529
+ def self.sync(opts={}, &block)
530
+ s = self.new(opts)
531
+ r = Blockenspiel.invoke(block, s)
532
+ s.close
506
533
  r
507
534
  end
508
535
 
@@ -519,23 +546,27 @@ module Net
519
546
  end
520
547
 
521
548
  private
522
- def with_session(host, opts, &block)
549
+ def with_session(host, opts={:timeout => 60}, &block)
523
550
  begin
524
- session = @sessions[host.hash] = @sessions[host.hash] ||\
525
- Net::SSH.start(*[host, opts[:user], opts])
526
- block.call(session)
551
+ Timeout.timeout(opts[:timeout]) do
552
+ session = @sessions[host.hash] = @sessions[host.hash] ||\
553
+ Net::SSH.start(*[host, opts[:user], opts])
554
+ block.call(session)
555
+ end
527
556
  rescue => e
528
557
  opts[:password].gsub!(/./,'*') if opts.include? :password
529
558
  @result[:exception] = e
530
- @result[:context] = [host,opts]
531
- raise Net::SSH::Simple::Error, [e, [host,opts]]
559
+ @result[:success] = false
560
+ @result[:timed_out] = true
561
+ @result[:finish_at] = Time.new
562
+ raise Net::SSH::Simple::Error, [e, [host,opts,@result]]
532
563
  end
533
564
  end
534
565
 
535
566
  def scp(mode, host, src, dst, opts={}, &block)
536
567
  @result = Result.new(
537
- { :host => host, :cmd => :scp_dl, :start_at => Time.new,
538
- :src => src , :dst => dst , :success => false
568
+ { :op => :scp, :host => host, :opts => opts, :cmd => :scp_dl,
569
+ :start_at => Time.new, :src => src, :dst => dst, :success => false
539
570
  } )
540
571
  with_session(host, opts) do |session|
541
572
  lt = 0
@@ -556,15 +587,23 @@ module Net
556
587
  # Error that occured during a Net::SSH::Simple operation.
557
588
  #
558
589
  class Error < RuntimeError
559
- # Reference to the underlying Net::SSH Exception
590
+ # Reference to the underlying Exception
560
591
  attr_reader :wrapped
561
- # The opts-hash of the operation that triggered the Error
592
+
593
+ # Context for the operation that failed, as an Array: [host, opts, result].
594
+ #
595
+ # @deprecated
596
+ # This will be removed soon, use {#result} instead!
562
597
  attr_reader :context
563
598
 
599
+ # {Net::SSH::Simple::Result} for the interrupted operation.
600
+ attr_reader :result
601
+
564
602
  def initialize(msg, e=$!)
565
603
  super(msg)
566
604
  @wrapped = e
567
605
  @context = msg[1]
606
+ @result = msg[1][2]
568
607
  end
569
608
 
570
609
  def to_s
@@ -576,9 +615,11 @@ module Net
576
615
  # Result of a Net::SSH::Simple operation.
577
616
  #
578
617
  # @attr [String] host Hostname/IP address
618
+ # @attr [Symbol] op :ssh or :scp
579
619
  # @attr [String] cmd Shell command (SSH only)
580
620
  # @attr [Time] start_at Operation start timestamp
581
621
  # @attr [Time] finish_at Operation finish timestamp
622
+ # @attr [Boolean] timed_out Set to true if the operation timed out
582
623
  # @attr [String] stdout Output to stdout (SSH only)
583
624
  # @attr [String] stderr Output to stderr (SSH only)
584
625
  # @attr [boolean] success
@@ -586,7 +627,7 @@ module Net
586
627
  # @attr [Integer] total Size of requested file (in bytes, SCP only)
587
628
  # @attr [Integer] sent Number of bytes transferred (SCP only)
588
629
  # @attr [String] exit_signal
589
- # Only present if the remote command terminates due to a signal (SSH only)
630
+ # Only present if the remote command terminated due to a signal (SSH only)
590
631
  #
591
632
  class Result < Hashie::Mash; end
592
633
  end
@@ -1,7 +1,7 @@
1
1
  module Net
2
2
  module SSH
3
3
  class Simple
4
- VERSION = "1.1.1"
4
+ VERSION = "1.2.0"
5
5
  end
6
6
  end
7
7
  end
@@ -11,14 +11,14 @@ Gem::Specification.new do |s|
11
11
  s.description = %q{Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.}
12
12
  s.summary = %q{SSH without the headache}
13
13
 
14
- s.rubyforge_project = "net-ssh-simple"
14
+ s.required_ruby_version = '>= 1.9.2'
15
15
 
16
16
  s.add_dependency "net-ssh", "~> 2.1.4"
17
17
  s.add_dependency "net-scp", "~> 1.0.4"
18
18
  s.add_dependency "blockenspiel", "~> 0.4.3"
19
19
  s.add_dependency "hashie", "~> 1.1.0"
20
20
 
21
- s.add_development_dependency "rake"
21
+ s.add_development_dependency "rake", "~> 0.9.2.2"
22
22
  s.add_development_dependency "rspec"
23
23
  s.add_development_dependency "cover_me"
24
24
 
@@ -17,14 +17,19 @@ require 'securerandom'
17
17
  # Port 22
18
18
  #
19
19
  # The test-suite will (over)write the following files on localhost:
20
- # /tmp/ssh_test_in{0,1,2,3,4}
21
- # /tmp/ssh_test_out{0,1,2,3,4}
20
+ # /tmp/ssh_test_in*
21
+ # /tmp/ssh_test_out*
22
22
  #
23
23
 
24
+ CONCURRENCY = 16
25
+
26
+ BENCHMARK_ITER = 10
27
+ BENCHMARK_CONCURRENCY = 128
28
+
24
29
  describe Net::SSH::Simple do
25
30
  describe "singleton" do
26
31
  before :each do
27
- (0..4).each do |i|
32
+ (0..CONCURRENCY).each do |i|
28
33
  begin
29
34
  File.unlink(File.join('/tmp', "ssh_test_in#{i}"))
30
35
  rescue; end
@@ -37,16 +42,32 @@ describe Net::SSH::Simple do
37
42
  end
38
43
  end
39
44
 
40
- it "fails gently" do
41
- lambda {
42
- Net::SSH::Simple.ssh('localhost', 'true', {:port => 0})
43
- }.should raise_error(Net::SSH::Simple::Error)
45
+ it "enforces timeout" do
46
+ raised = false
47
+ begin
48
+ r = Net::SSH::Simple.ssh('localhost', 'sleep 60', {:timeout => 1})
49
+ rescue => e
50
+ raised = true
51
+ e.to_s.should match /^execution expired @ .*/
52
+ e.result.op == :ssh
53
+ e.result.timed_out.should == true
54
+ end
55
+ raised.should == true
56
+ end
57
+
58
+ it "interprets timeout=0 as no timeout" do
59
+ Net::SSH::Simple.ssh('localhost', 'sleep 2', {:timeout => 0})
60
+ end
44
61
 
62
+ it "fails gently" do
63
+ raised = false
45
64
  begin
46
65
  Net::SSH::Simple.ssh('localhost', 'true', {:port => 0})
47
66
  rescue => e
48
- e.to_s.should == 'Connection refused - connect(2) @ ["localhost", {:port=>0}]'
67
+ raised = true
68
+ e.to_s.should match /^Connection refused - connect\(2\).*/
49
69
  end
70
+ raised.should == true
50
71
  end
51
72
 
52
73
  it "returns a result" do
@@ -95,7 +116,7 @@ describe Net::SSH::Simple do
95
116
  before :each do
96
117
  @s = Net::SSH::Simple.new
97
118
 
98
- (0..4).each do |i|
119
+ (0..CONCURRENCY).each do |i|
99
120
  begin
100
121
  File.unlink(File.join('/tmp', "ssh_test_in#{i}"))
101
122
  rescue; end
@@ -140,6 +161,7 @@ describe Net::SSH::Simple do
140
161
  mockback.ping
141
162
  end
142
163
  r.success.should == true
164
+ r.op.should == :scp
143
165
  Digest::MD5.file('/tmp/ssh_test_in0').should == Digest::MD5.file('/tmp/ssh_test_out0')
144
166
  end
145
167
 
@@ -150,6 +172,7 @@ describe Net::SSH::Simple do
150
172
  mockback.ping
151
173
  end
152
174
  r.success.should == true
175
+ r.op.should == :scp
153
176
  Digest::MD5.file('/tmp/ssh_test_in0').should == Digest::MD5.file('/tmp/ssh_test_out0')
154
177
  end
155
178
  end
@@ -211,7 +234,7 @@ describe Net::SSH::Simple do
211
234
 
212
235
  describe "asynchronous block syntax" do
213
236
  before :each do
214
- (0..4).each do |i|
237
+ (0..CONCURRENCY).each do |i|
215
238
  begin
216
239
  File.unlink(File.join('/tmp', "ssh_test_in#{i}"))
217
240
  rescue; end
@@ -226,7 +249,7 @@ describe Net::SSH::Simple do
226
249
 
227
250
  it "copes with a little concurrency" do
228
251
  t = []
229
- (0..4).each do |i|
252
+ (0..CONCURRENCY).each do |i|
230
253
  t[i] = Net::SSH::Simple.async do
231
254
  mockback = mock(:progress_callback)
232
255
  mockback.should_receive(:ping).at_least(:once)
@@ -245,13 +268,47 @@ describe Net::SSH::Simple do
245
268
  end
246
269
  end
247
270
 
248
- (0..4).each do |i|
271
+ (0..CONCURRENCY).each do |i|
249
272
  r = t[i].value
250
273
  r.stdout.should == "hello #{i}\n"
251
274
  Digest::MD5.file("/tmp/ssh_test_in#{i}").should == Digest::MD5.file("/tmp/ssh_test_out#{i}")
252
275
  end
253
276
  end
254
277
 
278
+ it "doesn't break under high concurrency", :benchmark => true do
279
+ iter = 0
280
+ (0..BENCHMARK_ITER).each do
281
+ iter += 1
282
+ t = []
283
+ (0..BENCHMARK_CONCURRENCY).each do |i|
284
+ #t[i] = Net::SSH::Simple.async(:verbose=>Logger::DEBUG) do
285
+ t[i] = Net::SSH::Simple.async do
286
+ mockback = mock(:progress_callback)
287
+ mockback.should_receive(:ping).at_least(:once)
288
+ r = nil
289
+ if 0 == i % 2
290
+ r = scp_dl('localhost', "/tmp/ssh_test_in#{i}", "/tmp/ssh_test_out#{i}") do |sent,total|
291
+ mockback.ping
292
+ end
293
+ else
294
+ r = scp_ul('localhost', "/tmp/ssh_test_in#{i}", "/tmp/ssh_test_out#{i}") do |sent,total|
295
+ mockback.ping
296
+ end
297
+ end
298
+ r.success.should == true
299
+ ssh('localhost', "echo hello #{i}")
300
+ end
301
+ end
302
+
303
+ (0..BENCHMARK_CONCURRENCY).each do |i|
304
+ r = t[i].value
305
+ r.stdout.should == "hello #{i}\n"
306
+ Digest::MD5.file("/tmp/ssh_test_in#{i}").should == Digest::MD5.file("/tmp/ssh_test_out#{i}")
307
+ end
308
+ puts "#{iter}/#{BENCHMARK_ITER}"
309
+ end
310
+ end
311
+
255
312
  it "handles signals" do
256
313
  victim = Net::SSH::Simple.async do
257
314
  begin
@@ -269,11 +326,151 @@ describe Net::SSH::Simple do
269
326
  k.success.should == true
270
327
 
271
328
  v = victim.value
272
- v.to_s.should == 'Killed by SIGTERM @ ["localhost", {}]'
329
+ v.to_s.should match /Killed by SIGTERM @ .*/
330
+ end
331
+ end
332
+
333
+ describe "parameter inheritance" do
334
+ it "works with instance syntax" do
335
+ s = Net::SSH::Simple.new({:timeout => 7})
336
+ r = s.ssh('localhost', 'date', {:rekey_packet_limit => 42})
337
+ r.op.should == :ssh
338
+ r.opts[:timeout].should == 7
339
+ r.opts[:rekey_packet_limit].should == 42
340
+
341
+ r = s.scp_dl('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
342
+ {:rekey_packet_limit => 42})
343
+ r.op.should == :scp
344
+ r.opts[:timeout].should == 7
345
+ r.opts[:rekey_packet_limit].should == 42
346
+
347
+ r = s.scp_ul('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
348
+ {:rekey_packet_limit => 42})
349
+ r.op.should == :scp
350
+ r.opts[:timeout].should == 7
351
+ r.opts[:rekey_packet_limit].should == 42
352
+
353
+ s.close
354
+ end
355
+
356
+ it "works with synchronous block syntax" do
357
+ r = Net::SSH::Simple.sync({:timeout => 7}) do
358
+ r = ssh('localhost', 'date', {:rekey_packet_limit => 42})
359
+ r.opts[:timeout].should == 7
360
+ r.opts[:rekey_packet_limit].should == 42
361
+
362
+ r = scp_ul('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
363
+ {:rekey_packet_limit => 42})
364
+ r.opts[:timeout].should == 7
365
+ r.opts[:rekey_packet_limit].should == 42
366
+
367
+ r = scp_dl('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
368
+ {:rekey_packet_limit => 42})
369
+ r.opts[:timeout].should == 7
370
+ r.opts[:rekey_packet_limit].should == 42
371
+ end
372
+ end
373
+
374
+ it "works with asynchronous block syntax" do
375
+ t = Net::SSH::Simple.async({:timeout => 7}) do
376
+ r = ssh('localhost', 'date', {:rekey_packet_limit => 42})
377
+ r.opts[:timeout].should == 7
378
+ r.opts[:rekey_packet_limit].should == 42
379
+
380
+ r = scp_ul('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
381
+ {:rekey_packet_limit => 42})
382
+ r.opts[:timeout].should == 7
383
+ r.opts[:rekey_packet_limit].should == 42
384
+
385
+ r = scp_dl('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
386
+ {:rekey_packet_limit => 42})
387
+ r.opts[:timeout].should == 7
388
+ r.opts[:rekey_packet_limit].should == 42
389
+ :happy
390
+ end
391
+ t.value.should == :happy
273
392
  end
274
393
  end
275
394
 
276
395
  describe "event api" do
396
+ it "works with singleton syntax" do
397
+ mockie = mock(:callbacks)
398
+ mockie.should_receive(:start).once.ordered
399
+ mockie.should_receive(:finish).once.ordered
400
+ r = Net::SSH::Simple.ssh('localhost', '/bin/sh') do |e,c,d|
401
+ case e
402
+ when :start
403
+ mockie.start()
404
+ c.send_data("echo 'hello stdout'\n")
405
+ c.eof!
406
+ when :finish
407
+ mockie.finish()
408
+ end
409
+ end
410
+ r.stdout.should == "hello stdout\n"
411
+ r.stderr.should == ''
412
+ end
413
+
414
+ it "works with instance syntax" do
415
+ mockie = mock(:callbacks)
416
+ mockie.should_receive(:start).once.ordered
417
+ mockie.should_receive(:finish).once.ordered
418
+ s = Net::SSH::Simple.new
419
+ r = s.ssh('localhost', '/bin/sh') do |e,c,d|
420
+ case e
421
+ when :start
422
+ mockie.start()
423
+ c.send_data("echo 'hello stdout'\n")
424
+ c.eof!
425
+ when :finish
426
+ mockie.finish()
427
+ end
428
+ end
429
+ r.stdout.should == "hello stdout\n"
430
+ r.stderr.should == ''
431
+ end
432
+
433
+ it "works with synchronous block syntax" do
434
+ mockie = mock(:callbacks)
435
+ mockie.should_receive(:start).once.ordered
436
+ mockie.should_receive(:finish).once.ordered
437
+ r = Net::SSH::Simple.sync do
438
+ ssh('localhost', '/bin/sh') do |e,c,d|
439
+ case e
440
+ when :start
441
+ mockie.start()
442
+ c.send_data("echo 'hello stdout'\n")
443
+ c.eof!
444
+ when :finish
445
+ mockie.finish()
446
+ end
447
+ end
448
+ end
449
+ r.stdout.should == "hello stdout\n"
450
+ r.stderr.should == ''
451
+ end
452
+
453
+ it "works with asynchronous block syntax" do
454
+ t = Net::SSH::Simple.async do
455
+ mockie = mock(:callbacks)
456
+ mockie.should_receive(:start).once.ordered
457
+ mockie.should_receive(:finish).once.ordered
458
+ ssh('localhost', '/bin/sh') do |e,c,d|
459
+ case e
460
+ when :start
461
+ mockie.start()
462
+ c.send_data("echo 'hello stdout'\n")
463
+ c.eof!
464
+ when :finish
465
+ mockie.finish()
466
+ end
467
+ end
468
+ end
469
+ r = t.value
470
+ r.stdout.should == "hello stdout\n"
471
+ r.stderr.should == ''
472
+ end
473
+
277
474
  it "handles long stdin->stdout pipe" do
278
475
  mockie = mock(:callbacks)
279
476
  mockie.should_receive(:start).once.ordered
@@ -414,7 +611,7 @@ describe Net::SSH::Simple do
414
611
  k.success.should == true
415
612
 
416
613
  v = victim.value
417
- v.to_s.should == 'Killed by SIGTERM @ ["localhost", {}]'
614
+ v.to_s.should match /Killed by SIGTERM @ .*/
418
615
  end
419
616
 
420
617
  it "handles signals (:no_raise)" do
metadata CHANGED
@@ -1,131 +1,100 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: net-ssh-simple
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 1
7
- - 1
8
- - 1
9
- version: 1.1.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Moe
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2011-10-25 00:00:00 +02:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2011-10-25 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: net-ssh
22
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &7024800 !ruby/object:Gem::Requirement
23
17
  none: false
24
- requirements:
18
+ requirements:
25
19
  - - ~>
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 2
29
- - 1
30
- - 4
20
+ - !ruby/object:Gem::Version
31
21
  version: 2.1.4
32
22
  type: :runtime
33
23
  prerelease: false
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
24
+ version_requirements: *7024800
25
+ - !ruby/object:Gem::Dependency
36
26
  name: net-scp
37
- requirement: &id002 !ruby/object:Gem::Requirement
27
+ requirement: &7024140 !ruby/object:Gem::Requirement
38
28
  none: false
39
- requirements:
29
+ requirements:
40
30
  - - ~>
41
- - !ruby/object:Gem::Version
42
- segments:
43
- - 1
44
- - 0
45
- - 4
31
+ - !ruby/object:Gem::Version
46
32
  version: 1.0.4
47
33
  type: :runtime
48
34
  prerelease: false
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
35
+ version_requirements: *7024140
36
+ - !ruby/object:Gem::Dependency
51
37
  name: blockenspiel
52
- requirement: &id003 !ruby/object:Gem::Requirement
38
+ requirement: &7023480 !ruby/object:Gem::Requirement
53
39
  none: false
54
- requirements:
40
+ requirements:
55
41
  - - ~>
56
- - !ruby/object:Gem::Version
57
- segments:
58
- - 0
59
- - 4
60
- - 3
42
+ - !ruby/object:Gem::Version
61
43
  version: 0.4.3
62
44
  type: :runtime
63
45
  prerelease: false
64
- version_requirements: *id003
65
- - !ruby/object:Gem::Dependency
46
+ version_requirements: *7023480
47
+ - !ruby/object:Gem::Dependency
66
48
  name: hashie
67
- requirement: &id004 !ruby/object:Gem::Requirement
49
+ requirement: &7022900 !ruby/object:Gem::Requirement
68
50
  none: false
69
- requirements:
51
+ requirements:
70
52
  - - ~>
71
- - !ruby/object:Gem::Version
72
- segments:
73
- - 1
74
- - 1
75
- - 0
53
+ - !ruby/object:Gem::Version
76
54
  version: 1.1.0
77
55
  type: :runtime
78
56
  prerelease: false
79
- version_requirements: *id004
80
- - !ruby/object:Gem::Dependency
57
+ version_requirements: *7022900
58
+ - !ruby/object:Gem::Dependency
81
59
  name: rake
82
- requirement: &id005 !ruby/object:Gem::Requirement
60
+ requirement: &7022240 !ruby/object:Gem::Requirement
83
61
  none: false
84
- requirements:
85
- - - ">="
86
- - !ruby/object:Gem::Version
87
- segments:
88
- - 0
89
- version: "0"
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 0.9.2.2
90
66
  type: :development
91
67
  prerelease: false
92
- version_requirements: *id005
93
- - !ruby/object:Gem::Dependency
68
+ version_requirements: *7022240
69
+ - !ruby/object:Gem::Dependency
94
70
  name: rspec
95
- requirement: &id006 !ruby/object:Gem::Requirement
71
+ requirement: &7021660 !ruby/object:Gem::Requirement
96
72
  none: false
97
- requirements:
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- segments:
101
- - 0
102
- version: "0"
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
103
77
  type: :development
104
78
  prerelease: false
105
- version_requirements: *id006
106
- - !ruby/object:Gem::Dependency
79
+ version_requirements: *7021660
80
+ - !ruby/object:Gem::Dependency
107
81
  name: cover_me
108
- requirement: &id007 !ruby/object:Gem::Requirement
82
+ requirement: &7020960 !ruby/object:Gem::Requirement
109
83
  none: false
110
- requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- segments:
114
- - 0
115
- version: "0"
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
116
88
  type: :development
117
89
  prerelease: false
118
- version_requirements: *id007
90
+ version_requirements: *7020960
119
91
  description: Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.
120
- email:
92
+ email:
121
93
  - moe@busyloop.net
122
94
  executables: []
123
-
124
95
  extensions: []
125
-
126
96
  extra_rdoc_files: []
127
-
128
- files:
97
+ files:
129
98
  - .gitignore
130
99
  - Gemfile
131
100
  - README.rdoc
@@ -135,39 +104,31 @@ files:
135
104
  - lib/net/ssh/simple/version.rb
136
105
  - net-ssh-simple.gemspec
137
106
  - spec/net-ssh-simple.rb
138
- has_rdoc: true
139
107
  homepage: https://github.com/busyloop/net-ssh-simple
140
108
  licenses: []
141
-
142
109
  post_install_message:
143
110
  rdoc_options: []
144
-
145
- require_paths:
111
+ require_paths:
146
112
  - lib
147
- required_ruby_version: !ruby/object:Gem::Requirement
113
+ required_ruby_version: !ruby/object:Gem::Requirement
148
114
  none: false
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- hash: 4391388084429679989
153
- segments:
154
- - 0
155
- version: "0"
156
- required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: 1.9.2
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
120
  none: false
158
- requirements:
159
- - - ">="
160
- - !ruby/object:Gem::Version
161
- hash: 4391388084429679989
162
- segments:
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ segments:
163
126
  - 0
164
- version: "0"
127
+ hash: 2238180045890726956
165
128
  requirements: []
166
-
167
- rubyforge_project: net-ssh-simple
168
- rubygems_version: 1.3.7
129
+ rubyforge_project:
130
+ rubygems_version: 1.8.10
169
131
  signing_key:
170
132
  specification_version: 3
171
133
  summary: SSH without the headache
172
134
  test_files: []
173
-