From d24b43227300ed38e652fd58dcfb628cce89fd9f Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Fri, 25 May 2018 15:12:39 -0700 Subject: [PATCH] Add Hyper-V provider actions test coverage --- .../hyperv/action/check_enabled_test.rb | 27 ++++ .../providers/hyperv/action/configure_test.rb | 125 +++++++++++++++++ .../providers/hyperv/action/export_test.rb | 42 ++++++ .../providers/hyperv/action/import_test.rb | 130 ++++++++++++++++++ 4 files changed, 324 insertions(+) create mode 100644 test/unit/plugins/providers/hyperv/action/check_enabled_test.rb create mode 100644 test/unit/plugins/providers/hyperv/action/configure_test.rb create mode 100644 test/unit/plugins/providers/hyperv/action/export_test.rb create mode 100644 test/unit/plugins/providers/hyperv/action/import_test.rb diff --git a/test/unit/plugins/providers/hyperv/action/check_enabled_test.rb b/test/unit/plugins/providers/hyperv/action/check_enabled_test.rb new file mode 100644 index 000000000..288d61b1f --- /dev/null +++ b/test/unit/plugins/providers/hyperv/action/check_enabled_test.rb @@ -0,0 +1,27 @@ +require_relative "../../../../base" + +require Vagrant.source_root.join("plugins/providers/hyperv/action/check_enabled") + +describe VagrantPlugins::HyperV::Action::CheckEnabled do + let(:app){ double("app") } + let(:env){ {ui: ui, machine: machine} } + let(:ui){ double("ui") } + let(:provider){ double("provider", driver: driver) } + let(:driver){ double("driver") } + let(:machine){ double("machine", provider: provider) } + let(:subject){ described_class.new(app, env) } + + before{ allow(ui).to receive(:output) } + + it "should continue when Hyper-V is enabled" do + expect(driver).to receive(:execute).and_return("result" => true) + expect(app).to receive(:call) + subject.call(env) + end + + it "should raise error when Hyper-V is not enabled" do + expect(driver).to receive(:execute).and_return("result" => false) + expect(app).not_to receive(:call) + expect{ subject.call(env) }.to raise_error(VagrantPlugins::HyperV::Errors::PowerShellFeaturesDisabled) + end +end diff --git a/test/unit/plugins/providers/hyperv/action/configure_test.rb b/test/unit/plugins/providers/hyperv/action/configure_test.rb new file mode 100644 index 000000000..9b2d8222b --- /dev/null +++ b/test/unit/plugins/providers/hyperv/action/configure_test.rb @@ -0,0 +1,125 @@ +require_relative "../../../../base" + +require Vagrant.source_root.join("plugins/providers/hyperv/action/configure") + +describe VagrantPlugins::HyperV::Action::Configure do + let(:app){ double("app") } + let(:env){ {ui: ui, machine: machine} } + let(:ui){ double("ui") } + let(:provider){ double("provider", driver: driver) } + let(:driver){ double("driver") } + let(:machine){ double("machine", provider: provider, config: config, provider_config: provider_config, data_dir: data_dir, id: "machineID") } + let(:data_dir){ double("data_dir") } + let(:config){ double("config", vm: vm) } + let(:vm){ double("vm", networks: networks) } + let(:networks){ [] } + let(:switches){ [ + {"Name" => "Switch1", "Id" => "ID1"}, + {"Name" => "Switch2", "Id" => "ID2"} + ]} + let(:sentinel){ double("sentinel") } + let(:provider_config){ + double("provider_config", + memory: "1024", + maxmemory: "1024", + cpus: 1, + auto_start_action: "Nothing", + auto_stop_action: "Save", + enable_checkpoints: false, + enable_virtualization_extensions: false, + vm_integration_services: vm_integration_services + ) + } + let(:vm_integration_services){ {} } + + let(:subject){ described_class.new(app, env) } + + before do + allow(driver).to receive(:execute) + allow(app).to receive(:call) + expect(driver).to receive(:execute).with(:get_switches).and_return(switches) + allow(ui).to receive(:detail) + allow(ui).to receive(:output) + allow(ui).to receive(:ask).and_return("1") + allow(data_dir).to receive(:join).and_return(sentinel) + allow(sentinel).to receive(:file?).and_return(false) + allow(sentinel).to receive(:open) + end + + it "should call the app on success" do + expect(app).to receive(:call) + subject.call(env) + end + + context "with missing switch sentinel file" do + it "should prompt for switch to use" do + expect(ui).to receive(:ask) + subject.call(env) + end + + it "should write sentinel file" do + expect(sentinel).to receive(:open) + subject.call(env) + end + end + + context "with existing switch sentinel file" do + before{ allow(sentinel).to receive(:file?).twice.and_return(true) } + + it "should not prompt for switch to use" do + expect(ui).not_to receive(:ask) + subject.call(env) + end + + it "should not write sentinel file" do + expect(sentinel).not_to receive(:open) + subject.call(env) + end + end + + context "with bridge defined in networks" do + context "with valid bridge switch name" do + let(:networks){ [[:public_network, {bridge: "Switch1"}]] } + + it "should not prompt for switch" do + expect(ui).not_to receive(:ask) + subject.call(env) + end + end + + context "with valid bridge switch ID" do + let(:networks){ [[:public_network, {bridge: "ID1"}]] } + + it "should not prompt for switch" do + expect(ui).not_to receive(:ask) + subject.call(env) + end + end + + context "with invalid bridge switch name" do + let(:networks){ [[:public_network, {bridge: "UNKNOWN"}]] } + + it "should prompt for switch" do + expect(ui).to receive(:ask) + subject.call(env) + end + end + end + + context "with integration services enabled" do + let(:vm_integration_services){ {service: true} } + + it "should call the driver to set the services" do + expect(driver).to receive(:set_vm_integration_services) + subject.call(env) + end + end + + context "without available switches" do + let(:switches){ [] } + + it "should raise an error" do + expect{ subject.call(env) }.to raise_error(VagrantPlugins::HyperV::Errors::NoSwitches) + end + end +end diff --git a/test/unit/plugins/providers/hyperv/action/export_test.rb b/test/unit/plugins/providers/hyperv/action/export_test.rb new file mode 100644 index 000000000..257225219 --- /dev/null +++ b/test/unit/plugins/providers/hyperv/action/export_test.rb @@ -0,0 +1,42 @@ +require_relative "../../../../base" + +require Vagrant.source_root.join("plugins/providers/hyperv/action/export") + +describe VagrantPlugins::HyperV::Action::Export do + let(:app){ double("app") } + let(:env){ {ui: ui, machine: machine} } + let(:ui){ double("ui") } + let(:provider){ double("provider", driver: driver) } + let(:driver){ double("driver") } + let(:machine){ double("machine", provider: provider, state: state) } + let(:state){ double("state", id: machine_state) } + let(:machine_state){ :off } + + let(:subject){ described_class.new(app, env) } + + before do + allow(app).to receive(:call) + allow(ui).to receive(:info) + allow(ui).to receive(:clear_line) + allow(ui).to receive(:report_progress) + allow(driver).to receive(:export) + end + + it "should call the app on success" do + expect(app).to receive(:call) + subject.call(env) + end + + it "should call the driver to perform the export" do + expect(driver).to receive(:export) + subject.call(env) + end + + context "with invalid machine state" do + let(:machine_state){ :on } + + it "should raise an error" do + expect{ subject.call(env) }.to raise_error(Vagrant::Errors::VMPowerOffToPackage) + end + end +end diff --git a/test/unit/plugins/providers/hyperv/action/import_test.rb b/test/unit/plugins/providers/hyperv/action/import_test.rb new file mode 100644 index 000000000..32c68695c --- /dev/null +++ b/test/unit/plugins/providers/hyperv/action/import_test.rb @@ -0,0 +1,130 @@ +require_relative "../../../../base" + +require Vagrant.source_root.join("plugins/providers/hyperv/action/import") + +describe VagrantPlugins::HyperV::Action::Import do + let(:app){ double("app") } + let(:env){ {ui: ui, machine: machine} } + let(:ui){ double("ui") } + let(:provider){ double("provider", driver: driver) } + let(:driver){ double("driver") } + let(:machine){ double("machine", provider: provider, provider_config: provider_config, box: box, data_dir: data_dir) } + let(:provider_config){ + double("provider_config", + linked_clone: false, + vmname: "VMNAME" + ) + } + let(:box){ double("box", directory: box_directory) } + let(:box_directory){ double("box_directory") } + let(:data_dir){ double("data_dir") } + let(:vm_dir){ double("vm_dir") } + let(:hd_dir){ double("hd_dir") } + + let(:subject){ described_class.new(app, env) } + + before do + allow(app).to receive(:call) + allow(box_directory).to receive(:join).with("Virtual Machines").and_return(vm_dir) + allow(box_directory).to receive(:join).with("Virtual Hard Disks").and_return(hd_dir) + allow(vm_dir).to receive(:directory?).and_return(true) + allow(vm_dir).to receive(:each_child).and_yield(Pathname.new("file.txt")) + allow(hd_dir).to receive(:directory?).and_return(true) + allow(hd_dir).to receive(:each_child).and_yield(Pathname.new("file.txt")) + allow(driver).to receive(:has_vmcx_support?).and_return(true) + allow(data_dir).to receive(:join).and_return(data_dir) + allow(data_dir).to receive(:to_s).and_return("DATA_DIR_PATH") + allow(driver).to receive(:import).and_return("id" => "VMID") + allow(machine).to receive(:id=) + allow(ui).to receive(:output) + allow(ui).to receive(:detail) + end + + context "with missing virtual machines directory" do + before{ expect(vm_dir).to receive(:directory?).and_return(false) } + + it "should raise an error" do + expect{ subject.call(env) }.to raise_error(VagrantPlugins::HyperV::Errors::BoxInvalid) + end + end + + context "with missing hard disks directory" do + before{ expect(hd_dir).to receive(:directory?).and_return(false) } + + it "should raise an error" do + expect{ subject.call(env) }.to raise_error(VagrantPlugins::HyperV::Errors::BoxInvalid) + end + end + + context "with missing configuration file" do + before do + allow(hd_dir).to receive(:each_child).and_yield(Pathname.new("image.vhd")) + end + + it "should raise an error" do + expect{ subject.call(env) }.to raise_error(VagrantPlugins::HyperV::Errors::BoxInvalid) + end + end + + context "with missing image file" do + before do + allow(vm_dir).to receive(:each_child).and_yield(Pathname.new("config.xml")) + end + + it "should raise an error" do + expect{ subject.call(env) }.to raise_error(VagrantPlugins::HyperV::Errors::BoxInvalid) + end + end + + context "with image and config files" do + before do + allow(vm_dir).to receive(:each_child).and_yield(Pathname.new("config.xml")) + allow(hd_dir).to receive(:each_child).and_yield(Pathname.new("image.vhd")) + end + + it "should call the app on success" do + expect(app).to receive(:call) + subject.call(env) + end + + it "should request import via the driver" do + expect(driver).to receive(:import).and_return("id" => "VMID") + subject.call(env) + end + + it "should set the machine ID after import" do + expect(machine).to receive(:id=).with("VMID") + subject.call(env) + end + + context "with no vmcx support" do + before do + expect(driver).to receive(:has_vmcx_support?).and_return(false) + end + + it "should match XML config file" do + subject.call(env) + end + + it "should not match VMCX config file" do + expect(vm_dir).to receive(:each_child).and_yield(Pathname.new("config.vmcx")) + expect{ subject.call(env) }.to raise_error(VagrantPlugins::HyperV::Errors::BoxInvalid) + end + end + + context "with vmcx support" do + before do + expect(driver).to receive(:has_vmcx_support?).and_return(true) + end + + it "should match XML config file" do + subject.call(env) + end + + it "should match VMCX config file" do + expect(vm_dir).to receive(:each_child).and_yield(Pathname.new("config.vmcx")) + subject.call(env) + end + end + end +end