From 929e41aa5c7da2a8478cbc2472e1e72d1f91c4e0 Mon Sep 17 00:00:00 2001 From: Shawn Neal Date: Tue, 22 Apr 2014 11:03:37 -0700 Subject: [PATCH] Backfilled unit tests for Windows guest support - Fixed typo in helper test - Removed extraneous machine.config prefix from Windows guest config validation - Added WinRM communicator unit tests - Added Windows guest capability unit tests --- plugins/guests/windows/config.rb | 11 +-- .../communicators/winrm/communicator_test.rb | 92 +++++++++++++++++++ .../communicators/winrm/helper_test.rb | 2 +- .../plugins/communicators/winrm/shell_test.rb | 58 ++++++++++++ .../windows/cap/change_host_name_test.rb | 29 ++++++ .../plugins/guests/windows/cap/halt_test.rb | 33 +++++++ .../windows/cap/mount_shared_folder_test.rb | 82 +++++++++++++++++ .../plugins/guests/windows/cap/reboot_test.rb | 54 +++++++++++ .../plugins/guests/windows/config_test.rb | 41 +++++++++ 9 files changed, 395 insertions(+), 7 deletions(-) create mode 100644 test/unit/plugins/communicators/winrm/communicator_test.rb create mode 100644 test/unit/plugins/communicators/winrm/shell_test.rb create mode 100644 test/unit/plugins/guests/windows/cap/change_host_name_test.rb create mode 100644 test/unit/plugins/guests/windows/cap/halt_test.rb create mode 100644 test/unit/plugins/guests/windows/cap/mount_shared_folder_test.rb create mode 100644 test/unit/plugins/guests/windows/cap/reboot_test.rb create mode 100644 test/unit/plugins/guests/windows/config_test.rb diff --git a/plugins/guests/windows/config.rb b/plugins/guests/windows/config.rb index 6ac7d894a..4f44ec6e1 100644 --- a/plugins/guests/windows/config.rb +++ b/plugins/guests/windows/config.rb @@ -14,17 +14,16 @@ module VagrantPlugins def validate(machine) errors = [] - errors << "windows.halt_timeout cannot be nil." if machine.config.windows.halt_timeout.nil? - errors << "windows.halt_check_interval cannot be nil." if machine.config.windows.halt_check_interval.nil? - - errors << "windows.set_work_network cannot be nil." if machine.config.windows.set_work_network.nil? + errors << "windows.halt_timeout cannot be nil." if @halt_timeout.nil? + errors << "windows.halt_check_interval cannot be nil." if @halt_check_interval.nil? + errors << "windows.set_work_network cannot be nil." if @set_work_network.nil? { "Windows Guest" => errors } end def finalize! - @halt_timeout = 30 if @halt_timeout == UNSET_VALUE - @halt_check_interval = 1 if @halt_check_interval == UNSET_VALUE + @halt_timeout = 30 if @halt_timeout == UNSET_VALUE + @halt_check_interval = 1 if @halt_check_interval == UNSET_VALUE @set_work_network = false if @set_work_network == UNSET_VALUE end end diff --git a/test/unit/plugins/communicators/winrm/communicator_test.rb b/test/unit/plugins/communicators/winrm/communicator_test.rb new file mode 100644 index 000000000..0a884008b --- /dev/null +++ b/test/unit/plugins/communicators/winrm/communicator_test.rb @@ -0,0 +1,92 @@ +require File.expand_path("../../../../base", __FILE__) + +require Vagrant.source_root.join("plugins/communicators/winrm/communicator") + +describe VagrantPlugins::CommunicatorWinRM::Communicator do + include_context "unit" + + let(:winrm) { double("winrm", :timeout => 1) } + let(:config) { double("config", :winrm => winrm) } + let(:machine) { double("machine", :config => config) } + + let(:shell) { double("shell") } + + subject do + comm = described_class.new(machine) + allow(comm).to receive(:create_shell).and_return(shell) + comm + end + + describe ".ready?" do + it "returns true if hostname command executes without error" do + expect(shell).to receive(:powershell).with("hostname").and_return({ :exitcode => 0 }) + expect(subject.ready?).to be_true + end + + it "returns false if hostname command fails to execute without error" do + expect(shell).to receive(:powershell).with("hostname").and_raise(Vagrant::Errors::VagrantError) + expect(subject.ready?).to be_false + end + + it "raises timeout error when hostname command takes longer then winrm timeout" do + expect(shell).to receive(:powershell).with("hostname") do + sleep 2 # winrm.timeout = 1 + end + expect { subject.ready? }.to raise_error(Timeout::Error) + end + end + + describe ".execute" do + it "defaults to running in powershell" do + expect(shell).to receive(:powershell).with(kind_of(String)).and_return({ :exitcode => 0 }) + expect(subject.execute("dir")).to eq(0) + end + + it "can use cmd shell" do + expect(shell).to receive(:cmd).with(kind_of(String)).and_return({ :exitcode => 0 }) + expect(subject.execute("dir", { :shell => :cmd })).to eq(0) + end + + it "raises error when error_check is true and exit code is non-zero" do + expect(shell).to receive(:powershell).with(kind_of(String)).and_return({ :exitcode => 1 }) + expect { subject.execute("dir") }.to raise_error( + VagrantPlugins::CommunicatorWinRM::Errors::ExecutionError) + end + + it "does not raise error when error_check is false and exit code is non-zero" do + expect(shell).to receive(:powershell).with(kind_of(String)).and_return({ :exitcode => 1 }) + expect(subject.execute("dir", { :error_check => false })).to eq(1) + end + end + + describe ".test" do + it "returns true when exit code is zero" do + expect(shell).to receive(:powershell).with(kind_of(String)).and_return({ :exitcode => 0 }) + expect(subject.test("test -d c:/windows")).to be_true + end + + it "returns false when exit code is non-zero" do + expect(shell).to receive(:powershell).with(kind_of(String)).and_return({ :exitcode => 1 }) + expect(subject.test("test -d /tmp/foobar")).to be_false + end + + it "returns false when command is testing for linux OS" do + expect(subject.test("uname -s | grep Debian")).to be_false + end + end + + describe ".upload" do + it "calls upload on shell" do + expect(shell).to receive(:upload).with("from", "to") + subject.upload("from", "to") + end + end + + describe ".download" do + it "calls download on shell" do + expect(shell).to receive(:download).with("from", "to") + subject.download("from", "to") + end + end + +end diff --git a/test/unit/plugins/communicators/winrm/helper_test.rb b/test/unit/plugins/communicators/winrm/helper_test.rb index deb7917e5..e7031a5dc 100644 --- a/test/unit/plugins/communicators/winrm/helper_test.rb +++ b/test/unit/plugins/communicators/winrm/helper_test.rb @@ -31,7 +31,7 @@ describe VagrantPlugins::CommunicatorWinRM::Helper do expect(subject.winrm_address(machine)).to eq("bar") end - it "raisee an exception if it can't detect a host" do + it "raise an exception if it can't detect a host" do machine.stub(ssh_info: nil) expect { subject.winrm_address(machine) }. to raise_error(VagrantPlugins::CommunicatorWinRM::Errors::WinRMNotReady) diff --git a/test/unit/plugins/communicators/winrm/shell_test.rb b/test/unit/plugins/communicators/winrm/shell_test.rb new file mode 100644 index 000000000..e3ef7a18f --- /dev/null +++ b/test/unit/plugins/communicators/winrm/shell_test.rb @@ -0,0 +1,58 @@ +require File.expand_path("../../../../base", __FILE__) + +require Vagrant.source_root.join("plugins/communicators/winrm/shell") + +describe VagrantPlugins::CommunicatorWinRM::WinRMShell do + include_context "unit" + + let(:session) { double("winrm_session") } + + subject do + comm = described_class.new('localhost', 'username', 'password') + allow(comm).to receive(:new_session).and_return(session) + comm + end + + describe ".powershell" do + it "should call winrm powershell" do + expect(session).to receive(:powershell).with("dir").and_return({ :exitcode => 0 }) + expect(subject.powershell("dir")[:exitcode]).to eq(0) + end + + it "should raise auth error when exception message contains 401" do + expect(session).to receive(:powershell).with("dir").and_raise( + StandardError.new("Oh no! a 401 SOAP error!")) + expect { subject.powershell("dir") }.to raise_error( + VagrantPlugins::CommunicatorWinRM::Errors::AuthError) + end + + it "should raise an execution error when an exception occurs" do + expect(session).to receive(:powershell).with("dir").and_raise( + StandardError.new("Oh no! a 500 SOAP error!")) + expect { subject.powershell("dir") }.to raise_error( + VagrantPlugins::CommunicatorWinRM::Errors::ExecutionError) + end + end + + describe ".cmd" do + it "should call winrm cmd" do + expect(session).to receive(:cmd).with("dir").and_return({ :exitcode => 0 }) + expect(subject.cmd("dir")[:exitcode]).to eq(0) + end + end + + describe ".endpoint" do + it "should create winrm endpoint address" do + expect(subject.send(:endpoint)).to eq("http://localhost:5985/wsman") + end + end + + describe ".endpoint_options" do + it "should create endpoint options" do + expect(subject.send(:endpoint_options)).to eq( + { :user => "username", :pass => "password", :host => "localhost", :port => 5985, + :operation_timeout => 60, :basic_auth_only => true }) + end + end + +end diff --git a/test/unit/plugins/guests/windows/cap/change_host_name_test.rb b/test/unit/plugins/guests/windows/cap/change_host_name_test.rb new file mode 100644 index 000000000..bf17d7854 --- /dev/null +++ b/test/unit/plugins/guests/windows/cap/change_host_name_test.rb @@ -0,0 +1,29 @@ +require File.expand_path("../../../../../base", __FILE__) + +require Vagrant.source_root.join("plugins/guests/windows/cap/change_host_name") + +describe "VagrantPlugins::GuestWindows::Cap::ChangeHostName" do + let(:described_class) do + VagrantPlugins::GuestWindows::Plugin.components.guest_capabilities[:windows].get(:change_host_name) + end + let(:machine) { double("machine") } + let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + let(:old_hostname) {'oldhostname.olddomain.tld' } + + before do + allow(machine).to receive(:communicate).and_return(communicator) + end + + after do + communicator.verify_expectations! + end + + describe ".change_host_name" do + + it "changes the hostname" do + communicator.expect_command('wmic computersystem where name="%COMPUTERNAME%" call rename name="newhostname.newdomain.tld"') + described_class.change_host_name(machine, 'newhostname.newdomain.tld') + end + + end +end diff --git a/test/unit/plugins/guests/windows/cap/halt_test.rb b/test/unit/plugins/guests/windows/cap/halt_test.rb new file mode 100644 index 000000000..da4f51f38 --- /dev/null +++ b/test/unit/plugins/guests/windows/cap/halt_test.rb @@ -0,0 +1,33 @@ +require File.expand_path("../../../../../base", __FILE__) + +require Vagrant.source_root.join("plugins/guests/windows/cap/halt") + +describe "VagrantPlugins::GuestWindows::Cap::Halt" do + let(:described_class) do + VagrantPlugins::GuestWindows::Plugin.components.guest_capabilities[:windows].get(:halt) + end + let(:machine) { double("machine") } + let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(communicator) + end + + after do + communicator.verify_expectations! + end + + describe ".halt" do + + it "cancels any existing scheduled shut down" do + communicator.expect_command("shutdown -a") + described_class.halt(machine) + end + + it "shuts down immediately" do + communicator.expect_command('shutdown /s /t 1 /c "Vagrant Halt" /f /d p:4:1') + described_class.halt(machine) + end + + end +end diff --git a/test/unit/plugins/guests/windows/cap/mount_shared_folder_test.rb b/test/unit/plugins/guests/windows/cap/mount_shared_folder_test.rb new file mode 100644 index 000000000..93fe41799 --- /dev/null +++ b/test/unit/plugins/guests/windows/cap/mount_shared_folder_test.rb @@ -0,0 +1,82 @@ +require File.expand_path("../../../../../base", __FILE__) + +require Vagrant.source_root.join("plugins/guests/windows/cap/mount_shared_folder") + +describe "VagrantPlugins::GuestWindows::Cap::MountSharedFolder" do + + let(:machine) { double("machine") } + let(:communicator) { double(:execute) } + + before do + allow(machine).to receive(:communicate).and_return(communicator) + allow(communicator).to receive(:execute) + end + + describe "virtualbox" do + + let(:described_class) do + VagrantPlugins::GuestWindows::Plugin.components.guest_capabilities[:windows].get(:mount_virtualbox_shared_folder) + end + + describe ".mount_shared_folder" do + it "should call mount_volume script with correct args" do + expect(Vagrant::Util::TemplateRenderer).to receive(:render).with( + /.+scripts\/mount_volume.ps1/, options: { + mount_point: "guestpath", + share_name: "name", + vm_provider_unc_path: "\\\\vboxsrv\\name", + }) + described_class.mount_virtualbox_shared_folder(machine, 'name', 'guestpath', {}) + end + + it "should replace invalid Windows share chars" do + expect(Vagrant::Util::TemplateRenderer).to receive(:render).with( + kind_of(String), options: { + mount_point: kind_of(String), + share_name: "invalid-windows_sharename", + vm_provider_unc_path: "\\\\vboxsrv\\invalid-windows_sharename", + }) + described_class.mount_virtualbox_shared_folder(machine, "/invalid-windows/sharename", "guestpath", {}) + end + end + end + + describe "vmware" do + + let(:described_class) do + VagrantPlugins::GuestWindows::Plugin.components.guest_capabilities[:windows].get(:mount_vmware_shared_folder) + end + + describe ".mount_shared_folder" do + it "should call mount_volume script with correct args" do + expect(Vagrant::Util::TemplateRenderer).to receive(:render).with( + /.+scripts\/mount_volume.ps1/, options: { + mount_point: "guestpath", + share_name: "name", + vm_provider_unc_path: "\\\\vmware-host\\Shared Folders\\name", + }) + described_class.mount_vmware_shared_folder(machine, 'name', 'guestpath', {}) + end + end + end + + describe "parallels" do + + let(:described_class) do + VagrantPlugins::GuestWindows::Plugin.components.guest_capabilities[:windows].get(:mount_parallels_shared_folder) + end + + describe ".mount_shared_folder" do + it "should call mount_volume script with correct args" do + expect(Vagrant::Util::TemplateRenderer).to receive(:render).with( + /.+scripts\/mount_volume.ps1/, options: { + mount_point: "guestpath", + share_name: "name", + vm_provider_unc_path: "\\\\psf\\name", + }) + described_class.mount_parallels_shared_folder(machine, 'name', 'guestpath', {}) + end + end + end + +end diff --git a/test/unit/plugins/guests/windows/cap/reboot_test.rb b/test/unit/plugins/guests/windows/cap/reboot_test.rb new file mode 100644 index 000000000..7f8266759 --- /dev/null +++ b/test/unit/plugins/guests/windows/cap/reboot_test.rb @@ -0,0 +1,54 @@ +require File.expand_path("../../../../../base", __FILE__) + +require Vagrant.source_root.join("plugins/guests/windows/cap/reboot") + +describe "VagrantPlugins::GuestWindows::Cap::Reboot" do + let(:described_class) do + VagrantPlugins::GuestWindows::Plugin.components.guest_capabilities[:windows].get(:wait_for_reboot) + end + let(:vm) { double("vm") } + let(:config) { double("config") } + let(:machine) { double("machine") } + let(:communicator) { double(:execute) } + + before do + allow(machine).to receive(:communicate).and_return(communicator) + allow(machine).to receive(:config).and_return(config) + allow(config).to receive(:vm).and_return(vm) + end + + describe "winrm communicator" do + + before do + allow(vm).to receive(:communicator).and_return(:winrm) + end + + describe ".wait_for_reboot" do + + it "runs reboot detect script" do + expect(communicator).to receive(:execute) do |cmd| + expect(cmd).to include("SM_SHUTTINGDOWN") + end.and_return(0) + described_class.wait_for_reboot(machine) + end + + end + end + + describe "ssh communicator" do + + before do + allow(vm).to receive(:communicator).and_return(:ssh) + end + + describe ".wait_for_reboot" do + + it "runs reboot detect script" do + expect(communicator).to_not receive(:execute) + described_class.wait_for_reboot(machine) + end + + end + end + +end diff --git a/test/unit/plugins/guests/windows/config_test.rb b/test/unit/plugins/guests/windows/config_test.rb new file mode 100644 index 000000000..28ab7a2d4 --- /dev/null +++ b/test/unit/plugins/guests/windows/config_test.rb @@ -0,0 +1,41 @@ +require File.expand_path("../../../../base", __FILE__) + +require Vagrant.source_root.join("plugins/guests/windows/config") + +describe VagrantPlugins::GuestWindows::Config do + let(:machine) { double("machine") } + + subject { described_class.new } + + it "is valid by default" do + subject.finalize! + result = subject.validate(machine) + expect(result["Windows Guest"]).to be_empty + end + + describe "default values" do + before { subject.finalize! } + + its("halt_timeout") { should == 30 } + its("halt_check_interval") { should == 1 } + its("set_work_network") { should == false } + end + + describe "attributes" do + [:halt_timeout, :halt_check_interval, :set_work_network].each do |attribute| + it "should not default #{attribute} if overridden" do + subject.send("#{attribute}=".to_sym, 10) + subject.finalize! + subject.send(attribute).should == 10 + end + + it "should return error #{attribute} if nil" do + subject.send("#{attribute}=".to_sym, nil) + subject.finalize! + result = subject.validate(machine) + expect(result["Windows Guest"]).to include("windows.#{attribute} cannot be nil.") + end + end + end + +end