Skip to content

Commit

Permalink
Merge branch 'freakhill-slightly-better-specs' into 0.4
Browse files Browse the repository at this point in the history
Conflicts:
	spec/em-ssh_spec.rb
  • Loading branch information
gruis committed Mar 15, 2013
2 parents 09c543f + deca2ef commit 0319a81
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 120 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -76,7 +76,7 @@ EM.run do
shell.expect('~]$ ', '/sbin/ifconfig -a')
EM.stop
end
shell.errback do
shell.errback do |err|
puts "error: #{err} (#{err.class})"
EM.stop
end
Expand Down
62 changes: 62 additions & 0 deletions spec/constants.rb
@@ -0,0 +1,62 @@
module EM
class Ssh
module Test

# Hold would-be-hardcoded values used for testing, constants in regard to the actual testing.
module Constants

# Previously, values used for tests (urls, credentials, ips, etc.) were hardcoded
# and spread through the test codebase.
# For a slight improvement, this class match previously hardcoded constants to environment variables,
# use these environment variables if present, and if not rely on hardcoded values provided when
# said constants were declared (via #add_field(constant_name, default_hardcoded_value).
class EnvElseHardcoded

def initialize(header, target)
@header = header
@target = target
end

# Sets an accessor for 'name', sets its value as the one from ENV["#@header#{name}".upcase],
# but if nil, sets is value as parameter 'default7 (default: ''). &blk is called on the chosen value.
# @param[#to_s] name Name of the accessor to create. Be careful with field names that would break a ruby object
# (like :method_missing for instance).
# @param[Object] default Value to use if associed ENV value is not set
# @block Called on chosen value
# @example
# DEVICE1 = EnvElseHardcoded.new("THAT_DEVICE_")
# DEVICE1.add_field(:some_kind_of_conf, 'default_hardcoded_value') # matched to the environment variable "THAT_DEVICE_SOME_KIND_OF_CONF"
# # if the environment variable exists it will use the value it holds, else it will use 'default_hardcoded_value'
# # similarily
# DEVICE2 = EnvElseHardcoded.new("THAT_OTHER_DEVICE_")
# DEVICE2.add_field(:some_other_kind_of_integer_conf, '1', &:to_i) # in this case the block will convert the environment value to an integer
# # note, that if no environment variable is provided, the default hardcoded value will also be passed through the block.
# DEVICE2.add_field(:ahahah, '2') { |i| i.to_i } # this works_too
# # also note that the default hardcoded value defaults to ''.
def add_field(name, default='', &blk)
const_name = "#{@header}#{name}".upcase
value = ENV[const_name] || ENV["#@header#{name}".upcase] || default
class << self; self; end.instance_eval { attr_accessor name }
send("#{name}=", blk ? blk.call(value) : value)
@target.const_set(const_name, value)
end
end

### remote server 1
REMOTE1 = EnvElseHardcoded.new("REMOTE1_", self)
REMOTE1.add_field(:ip, '192.168.92.11')
REMOTE1.add_field(:username, 'caleb')
REMOTE1.add_field(:prompt)
### remote server 2
REMOTE2 = EnvElseHardcoded.new("REMOTE2_", self)
REMOTE2.add_field(:url, 'icaleb.org')
REMOTE2.add_field(:username, 'calebcrane')
REMOTE2.add_field(:prompt, ']$')
REMOTE2.add_field(:timeout, 2, &:to_i)
REMOTE2.add_field(:uname_a, "Linux icaleb 2.6.18-194.3.1.el5 #1 SMP Thu May 13 13:08:30 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux\n")

end # module Constants

end # module Test
end # module Ssh
end # module EM
93 changes: 48 additions & 45 deletions spec/em-ssh_spec.rb
@@ -1,50 +1,53 @@
#!/usr/bin/env ruby
require 'bundler/setup'
require 'em-ssh'
require 'rspec'
require_relative "spec_helper"

describe "EM::Ssh" do
it "should be addressable through EM::P and EM::Protocols" do
EM::P.const_defined?(:Ssh).should be true
EM::Protocols.const_defined?(:Ssh).should be true
EM::P::Ssh.should == EM::Ssh
EM::Protocols::Ssh.should == EM::Ssh
end
it "should raise a ConnectionTimeout error when a connection can't be established before the given timeout" do
expect {
EM.run {
EM::Ssh.start('192.168.92.11', 'caleb', :timeout => 1) do |ssh|
ssh.callback { EM.stop }
ssh.errback{|e| raise e }
end
}
}.to raise_error(EM::Ssh::ConnectionTimeout)
end # should raise a ConnectionTimeout error when a connection can't be established before the given timeout
it "should raise a ConnectionError when the address is invalid" do
expect {

module EM::Ssh::Test
include Constants

describe "EM::Ssh" do
it "should be addressable through EM::P and EM::Protocols" do
EM::P.const_defined?(:Ssh).should be true
EM::Protocols.const_defined?(:Ssh).should be true
EM::P::Ssh.should == EM::Ssh
EM::Protocols::Ssh.should == EM::Ssh
end
it "should raise a ConnectionTimeout error when a connection can't be established before the given timeout" do
expect {
EM.run {
EM::Ssh.start(REMOTE1_IP, REMOTE1_USERNAME, :timeout => 1) do |ssh|
ssh.callback { EM.stop }
ssh.errback{|e| raise e }
end
}
}.to raise_error(EM::Ssh::ConnectionTimeout)
end # should raise a ConnectionTimeout error when a connection can't be established before the given timeout
it "should raise a ConnectionError when the address is invalid" do
expect {
EM.run {
EM::Ssh.start('0.0.0.1', 'caleb') do |ssh| # 0.0.0.1 is an invalid address
ssh.callback { EM.stop }
ssh.errback { |e| raise(e) }
end
}
}.to raise_error(EM::ConnectionError)
end # should raise a ConnectionFailed when the address is invalid

it "should run exec! succesfully" do
res = ""
EM.run {
EM::Ssh.start('0.0.0.1', 'caleb') do |ssh|
ssh.callback { EM.stop }
ssh.errback { |e| raise(e) }
EM::Ssh.start(REMOTE2_URL, REMOTE2_USERNAME) do |con|
con.errback do |err|
raise err
end
con.callback do |ssh|
res = ssh.exec!("uname -a")
ssh.close
EM.stop
end
end
}
}.to raise_error(EM::ConnectionError)
end # should raise a ConnectionFailed when the address is invalid

it "should run exec! succesfully" do
res = ""
EM.run {
EM::Ssh.start('icaleb.org', 'calebcrane') do |con|
con.errback do |err|
raise err
end
con.callback do |ssh|
res = ssh.exec!("uname -a")
ssh.close
EM.stop
end
end
}
res.should include("Linux icaleb")
end
end # EM::Ssh
res.should == REMOTE2_UNAME_A
end
end # EM::Ssh
end # module::EM::Ssh::Test
152 changes: 78 additions & 74 deletions spec/shell_spec.rb
@@ -1,92 +1,96 @@
#!/usr/bin/env ruby
require 'bundler/setup'
require 'em-ssh/shell'
require 'rspec'
require_relative "spec_helper"

describe "Ssh::Shell" do
it "should return a shell" do
EM.run {
Fiber.new {
timer = EM::Timer.new(2) { raise "failed #{$0}" }
shell = EM::Ssh::Shell.new('icaleb.org', 'calebcrane', "")
shell.callback do
shell.should be_a(EventMachine::Ssh::Shell)
shell.wait_for(Regexp.escape(']$'))
shell.send_and_wait('uname -a', Regexp.escape(']$')).should include("GNU/Linux")
timer.cancel
EM.stop
end
shell.errback { EM.stop }
}.resume
}
end # should return a shell

it "should yield a shell" do
EM.run {
timer = EM::Timer.new(4) { raise "failed #{$0}" }
EM::Ssh::Shell.new('icaleb.org', 'calebcrane', "") do |shell|
shell.callback do
shell.should be_a(EventMachine::Ssh::Shell)
shell.wait_for(Regexp.escape(']$'))
shell.send_and_wait('uname -a', Regexp.escape(']$')).should include("GNU/Linux")
shell.send_and_wait('/sbin/ifconfig -a', Regexp.escape(']$')).should include("eth0")
timer.cancel
EM.stop
end
end
}
end # should yield a shell
module EM::Ssh::Test
include Constants

describe "Ssh::Shell" do

it "should yield a shell even when in a fiber" do
EM.run {
Fiber.new{
timer = EM::Timer.new(4) { raise "failed #{$0}" }
EM::Ssh::Shell.new('icaleb.org', 'calebcrane', "") do |shell|
it "should return a shell" do
EM.run {
Fiber.new {
timer = EM::Timer.new(REMOTE2_TIMEOUT) { raise "failed #{$0}" }
shell = EM::Ssh::Shell.new(REMOTE2_URL, REMOTE2_USERNAME, "")
shell.callback do
shell.should be_a(EventMachine::Ssh::Shell)
shell.wait_for(Regexp.escape(']$'))
shell.send_and_wait('uname -a', Regexp.escape(']$')).should include("GNU/Linux")
shell.wait_for(Regexp.escape(REMOTE2_PROMPT))
shell.send_and_wait('uname -a', Regexp.escape(REMOTE2_PROMPT)).should include("GNU/Linux")
timer.cancel
EM.stop
end
end
}.resume
}
end # should yield a shell
shell.errback { EM.stop }
}.resume
}
end # should return a shell

it "should raise a proper error with good backtrace on timeout" do
EM.run {
Fiber.new {
timer = EM::Timer.new(4) { raise TimeoutError.new("failed to finish test") }
EM::Ssh::Shell.new('icaleb.org', 'calebcrane', "") do |shell|
it "should yield a shell" do
EM.run {
timer = EM::Timer.new(REMOTE2_TIMEOUT*2) { raise "failed #{$0}" }
EM::Ssh::Shell.new(REMOTE2_URL, REMOTE2_USERNAME, "") do |shell|
shell.callback do
shell.should be_a(EventMachine::Ssh::Shell)
shell.wait_for(Regexp.escape(']$'), :timeout => 1)
e = shell.send_and_wait('uname -a', Regexp.escape(']%'), :timeout => 2) rescue $!
e.should be_a(EM::Ssh::TimeoutError)
e.backtrace.join.should include("#{__FILE__}:#{__LINE__ - 2}:in `block")
shell.wait_for(Regexp.escape(REMOTE2_PROMPT))
shell.send_and_wait('uname -a', Regexp.escape(REMOTE2_PROMPT)).should include("GNU/Linux")
shell.send_and_wait('/sbin/ifconfig -a', Regexp.escape(REMOTE2_PROMPT)).should include("eth0")
timer.cancel
EM.stop
end
end
}.resume
}
end # should raise a proper error with good backtrace on timeout
}
end # should yield a shell

specify "#wait_for should raise TimeoutError on timeout" do
EM.run {
Fiber.new {
timer = EM::Timer.new(4) { raise TimeoutError.new("failed to finish test") }
EM::Ssh::Shell.new('icaleb.org', 'calebcrane', "") do |shell|
shell.callback do
expect {
shell.wait_for(Regexp.escape(']%'), :timeout => 1)
}.to raise_error(EM::Ssh::TimeoutError)
timer.cancel
EM.stop
it "should yield a shell even when in a fiber" do
EM.run {
Fiber.new{
timer = EM::Timer.new(REMOTE2_TIMEOUT*2) { raise "failed #{$0}" }
EM::Ssh::Shell.new(REMOTE2_URL, REMOTE2_USERNAME, "") do |shell|
shell.callback do
shell.should be_a(EventMachine::Ssh::Shell)
shell.wait_for(Regexp.escape(REMOTE2_PROMPT))
shell.send_and_wait('uname -a', Regexp.escape(REMOTE2_PROMPT)).should include("GNU/Linux")
timer.cancel
EM.stop
end
end
end
}.resume
}
end
end # Ssh::Shell
}.resume
}
end # should yield a shell

it "should raise a proper error with good backtrace on timeout" do
EM.run {
Fiber.new {
timer = EM::Timer.new(REMOTE2_TIMEOUT*2) { raise TimeoutError.new("failed to finish test") }
EM::Ssh::Shell.new(REMOTE2_URL, REMOTE2_USERNAME, "") do |shell|
shell.callback do
shell.should be_a(EventMachine::Ssh::Shell)
shell.wait_for(Regexp.escape(REMOTE2_PROMPT), :timeout => 1)
e = shell.send_and_wait('uname -a', Regexp.escape(']%'), :timeout => 2) rescue $!
e.should be_a(EM::Ssh::TimeoutError)
e.backtrace.join.should include("#{__FILE__}:#{__LINE__ - 2}:in `block")
timer.cancel
EM.stop
end
end
}.resume
}
end # should raise a proper error with good backtrace on timeout

specify "#wait_for should raise TimeoutError on timeout" do
EM.run {
Fiber.new {
timer = EM::Timer.new(REMOTE2_TIMEOUT*2) { raise TimeoutError.new("failed to finish test") }
EM::Ssh::Shell.new(REMOTE2_URL, REMOTE2_USERNAME, "") do |shell|
shell.callback do
expect {
shell.wait_for(Regexp.escape(']%'), :timeout => 1)
}.to raise_error(EM::Ssh::TimeoutError)
timer.cancel
EM.stop
end
end
}.resume
}
end
end # Ssh::Shell
end # module::EM::Ssh::Test
7 changes: 7 additions & 0 deletions spec/spec_helper.rb
@@ -0,0 +1,7 @@
require 'bundler/setup'
require 'rspec'
require_relative 'constants'

RSpec.configure do |config|
config.include EM::Ssh::Test
end

0 comments on commit 0319a81

Please sign in to comment.