From 421a1fb3419a3b7a9a683227bb9ac918d876a406 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 6 Nov 2011 13:30:49 -0800 Subject: [PATCH] First "up" based acceptance test. Multiple fixes to test harness. * First test that uses "vagrant up" * Allow interaction with processes executed during `execute` so that we can enter input into STDIN and receive data from STDOUT in real time. * Fix some issue with `waitpid2`, which actually speeds up all tests quite a bit. --- test/acceptance/base.rb | 13 +++++- .../helpers/isolated_environment.rb | 43 +++++++++++++++---- test/acceptance/helpers/output.rb | 6 +++ test/acceptance/up/basic_test.rb | 31 +++++++++++++ 4 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 test/acceptance/up/basic_test.rb diff --git a/test/acceptance/base.rb b/test/acceptance/base.rb index 23f704258..16645256f 100644 --- a/test/acceptance/base.rb +++ b/test/acceptance/base.rb @@ -36,8 +36,8 @@ class AcceptanceTest < Test::Unit::TestCase # is just a shortcut to IsolatedEnvironment#execute. # # @return [Object] - def execute(*args) - @environment.execute(*args) + def execute(*args, &block) + @environment.execute(*args, &block) end # This is a shortcut method to instantiate an Output matcher. @@ -47,6 +47,15 @@ class AcceptanceTest < Test::Unit::TestCase Acceptance::Output.new(text) end + # This method is an assertion helper for asserting that a process + # succeeds. It is a wrapper around `execute` that asserts that the + # exit status was successful. + def assert_execute(*args, &block) + result = execute(*args, &block) + assert(result.success?, "expected '#{args.join(" ")}' to succeed") + result + end + setup do # Setup the environment so that we have an isolated area # to run Vagrant. We do some configuration here as well in order diff --git a/test/acceptance/helpers/isolated_environment.rb b/test/acceptance/helpers/isolated_environment.rb index e23b0b9e2..58cde9022 100644 --- a/test/acceptance/helpers/isolated_environment.rb +++ b/test/acceptance/helpers/isolated_environment.rb @@ -41,7 +41,10 @@ module Acceptance @homedir.mkdir @workdir.mkdir + # Set the home directory and virtualbox home directory environmental + # variables so that Vagrant and VirtualBox see the proper paths here. @env["HOME"] = @homedir.to_s + @env["VBOX_USER_HOME"] = @homedir.to_s end # Executes a command in the context of this isolated environment. @@ -57,26 +60,48 @@ module Acceptance # return the IO streams. @logger.info("Executing: #{command} #{argN.inspect}. Output will stream in...") pid, stdin, stdout, stderr = popen4(@env, command, *argN) + status = nil io_data = { stdout => "", stderr => "" } - while results = IO.select([stdout, stderr], nil, nil, 5) - rs = results[0] - next if rs.empty? + while results = IO.select([stdout, stderr], [stdin], nil, 5) + # Check the readers first to see if they're ready + readers = results[0] + if !readers.empty? + begin + readers.each do |r| + data = r.readline + io_data[r] += data - rs.each do |r| - data = r.readline - io_data[r] += data + io_name = r == stdout ? "stdout" : "stderr" + @logger.debug("[#{io_name}] #{data.chomp}") + yield io_name.to_sym, data if block_given? + end + rescue EOFError + # Process exited, so break out of this while loop + break + end + end - io_name = r == stdout ? "stdout" : "stderr" - @logger.debug("[#{io_name}] #{data.chomp}") + # Check here if the process has exited, and if so, exit the + # loop. + exit_pid, status = Process.waitpid2(pid, Process::WNOHANG) + break if exit_pid + + # Check the writers to see if they're ready, and notify any + # listeners... + if !results[1].empty? + yield :stdin, stdin if block_given? end end - _pid, status = Process.waitpid2(pid) + # Only load the exit status if we don't already have it, since + # it is possible that it could've been obtained in the above + # while loop. + _pid, status = Process.waitpid2(pid) if !status @logger.debug("Exit status: #{status.exitstatus}") return ExecuteProcess.new(status.exitstatus, io_data[stdout], io_data[stderr]) diff --git a/test/acceptance/helpers/output.rb b/test/acceptance/helpers/output.rb index 176d337aa..524bfb98e 100644 --- a/test/acceptance/helpers/output.rb +++ b/test/acceptance/helpers/output.rb @@ -32,5 +32,11 @@ module Acceptance def is_version?(version) @text =~ /^Vagrant version #{version}$/ end + + # This checks that the VM with the given `vm_name` has the + # status of `status`. + def status(vm_name, status) + @text =~ /^#{vm_name}\s+#{status}$/ + end end end diff --git a/test/acceptance/up/basic_test.rb b/test/acceptance/up/basic_test.rb new file mode 100644 index 000000000..611f88cd1 --- /dev/null +++ b/test/acceptance/up/basic_test.rb @@ -0,0 +1,31 @@ +require File.expand_path("../../base", __FILE__) + +class BasicUpTest < AcceptanceTest + should "bring up a running virtual machine" do + assert_execute("vagrant", "box", "add", "base", config.boxes["default"]) + assert_execute("vagrant", "init") + assert_execute("vagrant", "up") + result = assert_execute("vagrant", "status") + + assert(output(result.stdout).status("default", "running"), + "Virtual machine should be running") + end + +=begin + +This shows how we can test that SSH is working. We'll use +this code later, but for now have no test that exercises it. + + outputted = false + result = assert_execute("vagrant", "ssh") do |io_type, data| + if io_type == :stdin and !outputted + data.puts("echo hello") + data.puts("exit") + outputted = true + end + end + + assert_equal("hello", result.stdout.chomp, + "Vagrant should bring up a virtual machine and be able to SSH in." +=end +end