spec/support/helpers.rb in engineyard-1.3.13 vs spec/support/helpers.rb in engineyard-1.3.14

- old
+ new

@@ -1,8 +1,11 @@ +require 'engineyard/cli' + require 'realweb' -require "rest_client" +require 'rest_client' require 'open4' +require 'stringio' module Spec module Helpers class UnexpectedExit < StandardError def initialize(stdout, stderr) @@ -14,10 +17,60 @@ end end NonzeroExitStatus = Class.new(UnexpectedExit) ZeroExitStatus = Class.new(UnexpectedExit) + def fast_ey(args) + err, out = StringIO.new, StringIO.new + capture_stderr_into(err) do + capture_stdout_into(out) do + with_env('DEBUG' => 'true') do + EY::CLI.start(args) + end + end + end + ensure + @err, @out = err.string, out.string + @raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out) + end + + def fast_failing_ey(*args) + begin + fast_ey(*args) + raise ZeroExitStatus + rescue SystemExit => exit_status + # SystemExit typically indicates a bogus command, which we + # here in expected-to-fail land are entirely happy with. + nil + rescue EY::Error => e + more_err, more_out = StringIO.new, StringIO.new + + capture_stderr_into(more_err) do + capture_stdout_into(more_out) do + EY.ui.print_exception(e) + end + end + + @err << more_err.string + @out << more_out.string + end + end + + def capture_stderr_into(stream) + $stderr = stream + yield + ensure + $stderr = STDERR + end + + def capture_stdout_into(stream) + $stdout = stream + yield + ensure + $stdout = STDOUT + end + def ey(cmd = nil, options = {}, &block) hide_err = options.has_key?(:hide_err) ? options[:hide_err] : options[:expect_failure] path_prepends = options[:prepend_to_path] ey_env = {'DEBUG' => 'true'} @@ -52,29 +105,40 @@ elsif exit_status.success? && options[:expect_failure] raise ZeroExitStatus.new(@out, @err) end end - @raw_ssh_commands = @out.split(/\n/).find_all do |line| - line =~ /^ssh/ + @raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out) + + puts @err unless @err.empty? || hide_err + @out + end + + def extract_ssh_commands(output) + raw_ssh_commands = @out.split(/\n/).find_all do |line| + line =~ /^bash -lc/ || line =~ /^ssh/ end - @ssh_commands = @raw_ssh_commands.map do |cmd| + ssh_commands = raw_ssh_commands.map do |cmd| # Strip off everything up to and including user@host, leaving # just the command that the remote system would run - ssh_prefix_removed = cmd.gsub(/^.*?\w+@\S*\s*/, '') + # + # XXX: this is a really icky icky. + # engineyard gem was written as if shelling out to run serverside + # and running an ssh command will always be the same. This is a nasty + # hack to get it working with Net::SSH for now so we can repair 1.9.2. + ssh_prefix_removed = cmd.gsub(/^bash -lc /, '').gsub(/^ssh .*?\w+@\S*\s*/, '') # Its arguments have been double-escaped: one layer is to get # them through our local shell and into ssh, and the other # layer is to get them through the remote system's shell. # # Strip off one layer by running it through the shell. just_the_remote_command = ssh_prefix_removed.gsub(/>\s*\/dev\/null.*$/, '') `echo #{just_the_remote_command}`.strip end - puts @err unless @err.empty? || hide_err - @out + [raw_ssh_commands, ssh_commands] end def api_scenario(scenario, remote = "user@git.host:path/to/repo.git") response = ::RestClient.put(EY.fake_awsm + '/scenario', {"scenario" => scenario, "remote" => remote}, {}) raise "Setting scenario failed: #{response.inspect}" unless response.code == 200