From 41bd20269e06cdafa8073cb482757a0c52f5853b Mon Sep 17 00:00:00 2001 From: Darragh Bailey Date: Mon, 13 Jun 2022 23:43:06 +0100 Subject: [PATCH] Migrate acceptance tests to rspec (#1513) Move existing tests executed with the help of bats to use rspec directly combined with tags to filter them out from being executed by default. This allows for more complex assertions as well as easier debug as the code supports use of setting 'VAGRANT_SPEC_SKIP_CLEANUP' to prevent the tests from removing the temporary directory created for home and work directories. Extend a number of classes from vagrant-spec to override default behaviour to allow passing of additional environment variables for packaging tests, as well as supporting the skip cleanup. Given the use of after to perform the cleanup, need to vendor the vagrant-spec acceptance context in order to modify it easily. --- .github/workflows/integration-tests.yml | 46 +-- .gitignore | 4 +- spec/acceptance/additional_storage_spec.rb | 32 ++ spec/acceptance/package_domain_spec.rb | 90 ++++++ spec/acceptance/provider_settings_spec.rb | 54 ++++ .../simple_vm_provision_via_shell_spec.rb | 31 ++ spec/acceptance/snapshots_spec.rb | 41 +++ .../additional_storage}/Vagrantfile | 0 .../adjusted_settings}/Vagrantfile | 2 + .../default_settings}/Vagrantfile | 0 .../package_complex}/Vagrantfile | 0 .../package_complex}/Vagrantfile.testbox | 3 +- .../package_complex}/scripts/sysprep.sh | 0 .../package_simple/Vagrantfile | 0 .../package_simple/Vagrantfile.testbox | 1 + .../support-skeletons}/qemu_agent/Vagrantfile | 0 .../simple_vm_provision}/Vagrantfile | 1 + .../support-skeletons/snapshots}/Vagrantfile | 0 .../support-skeletons}/two_disks/Vagrantfile | 0 spec/acceptance/two_disks_spec.rb | 29 ++ .../use_qemu_agent_for_connectivity_spec.rb | 34 +++ spec/spec_helper.rb | 3 + spec/support/acceptance/configuration.rb | 21 ++ spec/support/acceptance/context.rb | 70 +++++ .../acceptance/isolated_environment.rb | 41 +++ spec/support/libvirt_acceptance_context.rb | 64 ++++ tests/memory/Vagrantfile | 13 - tests/parse_tests.awk | 14 - tests/private_network/Vagrantfile | 14 - tests/runtests.bats | 275 ------------------ tests/snapshot/Vagrantfile | 13 - 31 files changed, 546 insertions(+), 350 deletions(-) create mode 100644 spec/acceptance/additional_storage_spec.rb create mode 100644 spec/acceptance/package_domain_spec.rb create mode 100644 spec/acceptance/provider_settings_spec.rb create mode 100644 spec/acceptance/simple_vm_provision_via_shell_spec.rb create mode 100644 spec/acceptance/snapshots_spec.rb rename {tests/second_disk => spec/acceptance/support-skeletons/additional_storage}/Vagrantfile (100%) rename {tests/default_prefix => spec/acceptance/support-skeletons/adjusted_settings}/Vagrantfile (88%) rename {tests/simple => spec/acceptance/support-skeletons/default_settings}/Vagrantfile (100%) rename {tests/package_complex_example => spec/acceptance/support-skeletons/package_complex}/Vagrantfile (100%) rename {tests/package_complex_example => spec/acceptance/support-skeletons/package_complex}/Vagrantfile.testbox (75%) rename {tests/package_complex_example => spec/acceptance/support-skeletons/package_complex}/scripts/sysprep.sh (100%) rename {tests => spec/acceptance/support-skeletons}/package_simple/Vagrantfile (100%) rename {tests => spec/acceptance/support-skeletons}/package_simple/Vagrantfile.testbox (87%) rename {tests => spec/acceptance/support-skeletons}/qemu_agent/Vagrantfile (100%) rename {tests/simple_provision_shell => spec/acceptance/support-skeletons/simple_vm_provision}/Vagrantfile (90%) rename {tests/cpus => spec/acceptance/support-skeletons/snapshots}/Vagrantfile (100%) rename {tests => spec/acceptance/support-skeletons}/two_disks/Vagrantfile (100%) create mode 100644 spec/acceptance/two_disks_spec.rb create mode 100644 spec/acceptance/use_qemu_agent_for_connectivity_spec.rb create mode 100644 spec/support/acceptance/configuration.rb create mode 100644 spec/support/acceptance/context.rb create mode 100644 spec/support/acceptance/isolated_environment.rb create mode 100644 spec/support/libvirt_acceptance_context.rb delete mode 100644 tests/memory/Vagrantfile delete mode 100644 tests/parse_tests.awk delete mode 100644 tests/private_network/Vagrantfile delete mode 100644 tests/runtests.bats delete mode 100644 tests/snapshot/Vagrantfile diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 4074552..663ae12 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -13,10 +13,35 @@ jobs: matrix: ${{ steps.generate-matrix.outputs.matrix }} steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set up libvirt for test generation + run: | + sudo apt-get update + sudo apt-get install -y \ + libvirt-dev \ + libz-dev \ + ; + - uses: actions/cache@v2 + with: + path: vendor/bundle + key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} + restore-keys: | + ${{ runner.os }}-gems- + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.6.6 + - name: Run bundler using cached path + run: | + bundle config path vendor/bundle + bundle install --jobs 4 --retry 3 - name: Generate matrix id: generate-matrix run: | - tests="$(awk -f tests/parse_tests.awk < tests/runtests.bats)" + bundle exec rspec --color --format json --fail-fast --dry-run --tag acceptance --out report.json + tests="$(jq -c '[.examples[].full_description]' report.json)" + echo "::set-output name=matrix::${tests}" run-tests: @@ -51,14 +76,10 @@ jobs: qemu-kvm \ qemu-utils \ ; - sudo apt-get install \ + sudo apt-get install -y \ libvirt-dev \ libz-dev \ ; - sudo apt-get install \ - bats \ - fping \ - ; # start daemon sudo systemctl start libvirtd @@ -81,22 +102,14 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: 2.6.6 - - name: Set up rubygems - run: | - gem update --system --conservative || (gem i "rubygems-update:~>2.7" --no-document && update_rubygems) - gem update bundler --conservative - name: Run bundler using cached path run: | bundle config path vendor/bundle bundle install --jobs 4 --retry 3 - - name: Install binstubs - run: | - bundle binstubs --all --path=./bin 1>/dev/null - ./bin/vagrant --version - name: Run tests run: | mkdir -p $HOME/.vagrant.d/ - # use export with full path to avoid needing to resolve ~ + # tell integration tests to use boxes from the cached location export VAGRANT_HOME=$HOME/.vagrant.d # use software emulation due to lack of nested emulation cat < $HOME/.vagrant.d/Vagrantfile @@ -105,6 +118,5 @@ jobs: libvirt.driver = "qemu" end end - EOF # run under libvirt group - sg libvirt -c "bats -f '${{ matrix.test_name }}' ./tests/runtests.bats" + sg libvirt -c "bundle exec rspec --color --fail-fast --tag acceptance -e '${{ matrix.test_name }}'" diff --git a/.gitignore b/.gitignore index 6689d63..1c714e4 100644 --- a/.gitignore +++ b/.gitignore @@ -16,9 +16,7 @@ spec/reports test/tmp test/version_tmp tmp -Vagrantfile -!tests/*/Vagrantfile -!example_box/Vagrantfile +/Vagrantfile .vagrant *.swp .deps diff --git a/spec/acceptance/additional_storage_spec.rb b/spec/acceptance/additional_storage_spec.rb new file mode 100644 index 0000000..11a5eae --- /dev/null +++ b/spec/acceptance/additional_storage_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'additional storage configured', acceptance: true do + include_context 'libvirt_acceptance' + + before do + environment.skeleton('additional_storage') + end + + after do + assert_execute('vagrant', 'destroy', '--force') + end + + it 'should succeed' do + status('Test: machine is created successfully') + result = environment.execute('vagrant', 'up') + expect(result).to exit_with(0) + + status('Test: additional storage configured') + expect(result.stdout).to match(/\(vda\).*work_default.img/) + expect(result.stdout).to match(/\(vdb\).*work_default-vdb\.qcow2/) + + status('Test: reload handles additional storage correctly') + result = environment.execute('vagrant', 'reload') + expect(result).to exit_with(0) + + status('Test: additional storage reported correctly') + expect(result.stdout).to match(/\(vdb\).*work_default-vdb\.qcow2/) + end +end diff --git a/spec/acceptance/package_domain_spec.rb b/spec/acceptance/package_domain_spec.rb new file mode 100644 index 0000000..3d574b9 --- /dev/null +++ b/spec/acceptance/package_domain_spec.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'package domain', acceptance: true do + include_context 'libvirt_acceptance' + + before(:all) do + expect(Vagrant::Util::Which.which('virt-sysprep')).to be_truthy, + 'packaging tests require virt-sysprep, please install' + expect(Vagrant::Util::Which.which('virt-sparsify')).to be_truthy, + 'packaging tests require virt-sparsify, please install' + + result = (File.exist?('C:\\') ? `dir /-C #{Dir.tmpdir}` : `df #{Dir.tmpdir}`).split("\n").last + expect(result.split[3].to_i).to be > 6 * 1024 * 1024, + "packaging tests require more than 6GiB of space under #{Dir.tmpdir}" + end + + after(:each) do + assert_execute('vagrant', 'destroy', '--force') + end + + let(:testbox_envvars) { { VAGRANT_VAGRANTFILE: 'Vagrantfile.testbox' } } + + context 'simple' do + before do + environment.skeleton('package_simple') + end + + after do + result = environment.execute('vagrant', 'destroy', '--force', extra_env: testbox_envvars) + expect(result).to exit_with(0) + + assert_execute('vagrant', 'box', 'remove', '--force', 'test-package-simple-domain') + end + + it 'should succeed' do + status('Test: machine is created successfully') + expect(environment.execute('vagrant', 'up')).to exit_with(0) + + status('Test: package machine successfully') + expect(environment.execute('vagrant', 'package')).to exit_with(0) + + status('Test: add packaged box') + expect(environment.execute( + 'vagrant', 'box', 'add', '--force', '--name', 'test-package-simple-domain', 'package.box' + )).to exit_with(0) + + status('Test: machine from packaged box is created successfully') + result = environment.execute('vagrant', 'up', extra_env: testbox_envvars) + expect(result).to exit_with(0) + expect(result.stdout).to match(/test-package-complex-domain/) + end + end + + context 'complex' do + before do + environment.skeleton('package_complex') + extra_env.merge!( + { + VAGRANT_LIBVIRT_VIRT_SYSPREP_OPERATIONS: 'defaults,-ssh-userdir,customize', + VAGRANT_LIBVIRT_VIRT_SYSPREP_OPTIONS: '--run $(pwd)/scripts/sysprep.sh', + } + ) + end + + after do + expect(environment.execute('vagrant', 'destroy', '--force', extra_env: testbox_envvars)).to exit_with(0) + assert_execute('vagrant', 'box', 'remove', '--force', 'test-package-complex-domain') + end + + it 'should succeed' do + status('Test: machine is created successfully') + expect(environment.execute('vagrant', 'up')).to exit_with(0) + + status('Test: package machine successfully') + expect(environment.execute('vagrant', 'package')).to exit_with(0) + + status('Test: add packaged box') + expect(environment.execute( + 'vagrant', 'box', 'add', '--force', '--name', 'test-package-complex-domain', 'package.box' + )).to exit_with(0) + + status('Test: machine from packaged box is created successfully') + result = environment.execute('vagrant', 'up', extra_env: testbox_envvars) + expect(result).to exit_with(0) + expect(result.stdout).to match(/test-package-complex-domain/) + end + end +end diff --git a/spec/acceptance/provider_settings_spec.rb b/spec/acceptance/provider_settings_spec.rb new file mode 100644 index 0000000..a46ed2c --- /dev/null +++ b/spec/acceptance/provider_settings_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'provider settings', acceptance: true do + include_context 'libvirt_acceptance' + + after do + assert_execute('vagrant', 'destroy', '--force') + end + + context 'with defaults' do + before do + environment.skeleton('default_settings') + end + + it 'should succeed' do + status('Test: machine is created successfully') + result = environment.execute('vagrant', 'up') + expect(result).to exit_with(0) + + status('Test: CPU matches default') + expect(result.stdout).to match(/Cpus:\s+1$/) + + status('Test: memory matches default') + expect(result.stdout).to match(/Memory:\s+512M/) + + status('Test: default prefix is used') + expect(result.stdout).to match(/Name:\s+work_default$/) + end + end + + context 'with modified config' do + before do + environment.skeleton('adjusted_settings') + end + + it 'should succeed' do + status('Test: machine is created successfully') + result = environment.execute('vagrant', 'up') + expect(result).to exit_with(0) + + status('Test: CPUs are changed') + expect(result.stdout).to match(/Cpus:\s+2$/) + + status('Test: memory is changed') + expect(result.stdout).to match(/Memory:\s+1000M$/) + + status('Test: default prefix is changed') + expect(result.stdout).to match(/Name:\s+changed_default_prefixdefault$/) + expect(result.stdout).to match(/\(vda\).*changed_default_prefixdefault\.img/) + end + end +end diff --git a/spec/acceptance/simple_vm_provision_via_shell_spec.rb b/spec/acceptance/simple_vm_provision_via_shell_spec.rb new file mode 100644 index 0000000..d392fd1 --- /dev/null +++ b/spec/acceptance/simple_vm_provision_via_shell_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'simple vm provision via shell', acceptance: true do + include_context 'libvirt_acceptance' + + before do + environment.skeleton('simple_vm_provision') + end + + after do + assert_execute('vagrant', 'destroy', '--force') + end + + it 'should succeed' do + status('Test: machine is created successfully') + result = environment.execute('vagrant', 'up') + expect(result).to exit_with(0) + + status('Test: provision script executed') + expect(result.stdout).to match(/Hello, World/) + + status('Test: reload') + result = environment.execute('vagrant', 'reload') + expect(result).to exit_with(0) + + status('Test: provision checked if already executed') + expect(result.stdout).to match(/Machine already provisioned/) + end +end diff --git a/spec/acceptance/snapshots_spec.rb b/spec/acceptance/snapshots_spec.rb new file mode 100644 index 0000000..c476b19 --- /dev/null +++ b/spec/acceptance/snapshots_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'snapshots', acceptance: true do + include_context 'libvirt_acceptance' + + after(:each) do + assert_execute('vagrant', 'destroy', '--force') + end + + before do + environment.skeleton('snapshots') + end + + it 'should succeed' do + status('Test: machine is created successfully') + expect(environment.execute('vagrant', 'up')).to exit_with(0) + + status('Test: add test file') + expect(environment.execute('vagrant', 'ssh', '--', '-t', 'touch a.txt')).to exit_with(0) + + status('Test: create snapshot') + expect(environment.execute('vagrant', 'snapshot', 'save', 'default', 'test')).to exit_with(0) + + status('Test: modify files') + expect(environment.execute('vagrant', 'ssh', '--', '-t', 'rm a.txt')).to exit_with(0) + expect(environment.execute('vagrant', 'ssh', '--', '-t', 'ls a.txt')).to exit_with(1) + expect(environment.execute('vagrant', 'ssh', '--', '-t', 'touch b.txt')).to exit_with(0) + + status('Test: restore snapshot') + expect(environment.execute('vagrant', 'snapshot', 'restore', 'test')).to exit_with(0) + + status('Test: files are as expected') + expect(environment.execute('vagrant', 'ssh', '--', '-t', 'ls a.txt')).to exit_with(0) + expect(environment.execute('vagrant', 'ssh', '--', '-t', 'ls b.txt')).to exit_with(1) + + status('Test: snapshot removal works') + expect(environment.execute('vagrant', 'snapshot', 'delete', 'test')).to exit_with(0) + end +end diff --git a/tests/second_disk/Vagrantfile b/spec/acceptance/support-skeletons/additional_storage/Vagrantfile similarity index 100% rename from tests/second_disk/Vagrantfile rename to spec/acceptance/support-skeletons/additional_storage/Vagrantfile diff --git a/tests/default_prefix/Vagrantfile b/spec/acceptance/support-skeletons/adjusted_settings/Vagrantfile similarity index 88% rename from tests/default_prefix/Vagrantfile rename to spec/acceptance/support-skeletons/adjusted_settings/Vagrantfile index 9746738..9a7c7a9 100644 --- a/tests/default_prefix/Vagrantfile +++ b/spec/acceptance/support-skeletons/adjusted_settings/Vagrantfile @@ -8,6 +8,8 @@ Vagrant.configure("2") do |config| config.ssh.shell = "/bin/sh" config.vm.synced_folder ".", "/vagrant", disabled: true config.vm.provider :libvirt do |libvirt| + libvirt.cpu = 2 + libvirt.memory = 1000 libvirt.default_prefix = "changed_default_prefix" end end diff --git a/tests/simple/Vagrantfile b/spec/acceptance/support-skeletons/default_settings/Vagrantfile similarity index 100% rename from tests/simple/Vagrantfile rename to spec/acceptance/support-skeletons/default_settings/Vagrantfile diff --git a/tests/package_complex_example/Vagrantfile b/spec/acceptance/support-skeletons/package_complex/Vagrantfile similarity index 100% rename from tests/package_complex_example/Vagrantfile rename to spec/acceptance/support-skeletons/package_complex/Vagrantfile diff --git a/tests/package_complex_example/Vagrantfile.testbox b/spec/acceptance/support-skeletons/package_complex/Vagrantfile.testbox similarity index 75% rename from tests/package_complex_example/Vagrantfile.testbox rename to spec/acceptance/support-skeletons/package_complex/Vagrantfile.testbox index e88e599..787833f 100644 --- a/tests/package_complex_example/Vagrantfile.testbox +++ b/spec/acceptance/support-skeletons/package_complex/Vagrantfile.testbox @@ -2,7 +2,8 @@ # vi: set ft=ruby : Vagrant.configure("2") do |config| - config.vm.box = "test-package-complex-example" + config.vm.box = "test-package-complex-domain" + config.vm.define 'package-complex' config.vm.synced_folder ".", "/vagrant", disabled: true config.vm.provider :libvirt do |libvirt| diff --git a/tests/package_complex_example/scripts/sysprep.sh b/spec/acceptance/support-skeletons/package_complex/scripts/sysprep.sh similarity index 100% rename from tests/package_complex_example/scripts/sysprep.sh rename to spec/acceptance/support-skeletons/package_complex/scripts/sysprep.sh diff --git a/tests/package_simple/Vagrantfile b/spec/acceptance/support-skeletons/package_simple/Vagrantfile similarity index 100% rename from tests/package_simple/Vagrantfile rename to spec/acceptance/support-skeletons/package_simple/Vagrantfile diff --git a/tests/package_simple/Vagrantfile.testbox b/spec/acceptance/support-skeletons/package_simple/Vagrantfile.testbox similarity index 87% rename from tests/package_simple/Vagrantfile.testbox rename to spec/acceptance/support-skeletons/package_simple/Vagrantfile.testbox index 4124024..c4cf8c8 100644 --- a/tests/package_simple/Vagrantfile.testbox +++ b/spec/acceptance/support-skeletons/package_simple/Vagrantfile.testbox @@ -3,6 +3,7 @@ Vagrant.configure("2") do |config| config.vm.box = "test-package-simple-domain" + config.vm.define 'package-simple' config.ssh.shell = "/bin/sh" config.ssh.insert_key = false config.vm.synced_folder ".", "/vagrant", disabled: true diff --git a/tests/qemu_agent/Vagrantfile b/spec/acceptance/support-skeletons/qemu_agent/Vagrantfile similarity index 100% rename from tests/qemu_agent/Vagrantfile rename to spec/acceptance/support-skeletons/qemu_agent/Vagrantfile diff --git a/tests/simple_provision_shell/Vagrantfile b/spec/acceptance/support-skeletons/simple_vm_provision/Vagrantfile similarity index 90% rename from tests/simple_provision_shell/Vagrantfile rename to spec/acceptance/support-skeletons/simple_vm_provision/Vagrantfile index cd0a956..b4837fc 100644 --- a/tests/simple_provision_shell/Vagrantfile +++ b/spec/acceptance/support-skeletons/simple_vm_provision/Vagrantfile @@ -6,6 +6,7 @@ Vagrant.configure("2") do |config| config.vm.box = "infernix/tinycore" config.ssh.shell = "/bin/sh" + config.ssh.insert_key = false config.vm.synced_folder ".", "/vagrant", disabled: true config.vm.provision "shell", inline: "echo Hello, World", privileged: false end diff --git a/tests/cpus/Vagrantfile b/spec/acceptance/support-skeletons/snapshots/Vagrantfile similarity index 100% rename from tests/cpus/Vagrantfile rename to spec/acceptance/support-skeletons/snapshots/Vagrantfile diff --git a/tests/two_disks/Vagrantfile b/spec/acceptance/support-skeletons/two_disks/Vagrantfile similarity index 100% rename from tests/two_disks/Vagrantfile rename to spec/acceptance/support-skeletons/two_disks/Vagrantfile diff --git a/spec/acceptance/two_disks_spec.rb b/spec/acceptance/two_disks_spec.rb new file mode 100644 index 0000000..e04ace3 --- /dev/null +++ b/spec/acceptance/two_disks_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'handle two disk machine', acceptance: true do + include_context 'libvirt_acceptance' + + after do + assert_execute('vagrant', 'destroy', '--force') + end + + before do + environment.skeleton('two_disks') + environment.execute(File.expand_path('../../tools/create_box_with_two_disks.sh', __dir__), + environment.homedir.to_s, 'vagrant') + end + + it 'should succeed' do + status('Test: machine is created successfully') + result = environment.execute('vagrant', 'up') + expect(result).to exit_with(0) + + status('Test: disk one referenced') + expect(result.stdout).to match(/Image\(vda\):.*work_default.img, virtio, 2G/) + + status('Test: disk two referenced') + expect(result.stdout).to match(/Image\(vdb\):.*work_default_1.img, virtio, 10G/) + end +end diff --git a/spec/acceptance/use_qemu_agent_for_connectivity_spec.rb b/spec/acceptance/use_qemu_agent_for_connectivity_spec.rb new file mode 100644 index 0000000..8efe4de --- /dev/null +++ b/spec/acceptance/use_qemu_agent_for_connectivity_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'use qemu agent to determine machine private address', acceptance: true do + include_context 'libvirt_acceptance' + + before do + environment.skeleton('qemu_agent') + end + + after do + assert_execute('vagrant', 'destroy', '--force') + end + + it 'should succeed' do + status('Test: machine is created successfully') + expect(environment.execute('vagrant', 'up')).to exit_with(0) + + # extract SSH IP address emitted as it should be the private network since + # the mgmt network has not been attached + hostname = result.stdout.each_line.find { |line| line.include?('SSH address:') } + expect(hostname).to_not be_nil + ip_address = hostname.strip.split.last.split(':').first + # default private network for vagrant-libvirt unless explicitly configured + expect(IPAddr.new('172.28.128.0/255.255.255.0')).to include(IPAddr.new(ip_address)) + + # ssh'ing successfully means that the private network is accessible + status('Test: machine private network is accessible') + result = environment.execute('vagrant', 'ssh', '-c', 'echo "hello, world"') + expect(result).to exit_with(0) + expect(result.stdout).to match(/hello, world/) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 01fd91b..b161c28 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -55,4 +55,7 @@ RSpec.configure do |config| config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end + + # don't run acceptance tests by default + config.filter_run_excluding :acceptance => true end diff --git a/spec/support/acceptance/configuration.rb b/spec/support/acceptance/configuration.rb new file mode 100644 index 0000000..ba5d5d9 --- /dev/null +++ b/spec/support/acceptance/configuration.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'vagrant-spec/acceptance/configuration' + +module VagrantPlugins + module VagrantLibvirt + module Spec + module Acceptance + class Configuration < Vagrant::Spec::Acceptance::Configuration + attr_accessor :clean_on_fail + + def initialize + super + + @clean_on_fail = true + end + end + end + end + end +end diff --git a/spec/support/acceptance/context.rb b/spec/support/acceptance/context.rb new file mode 100644 index 0000000..e59599f --- /dev/null +++ b/spec/support/acceptance/context.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'vagrant-spec/acceptance/configuration' +require "vagrant-spec/acceptance/rspec/matcher_exit_with" + +require_relative 'isolated_environment' + +shared_context "acceptance" do + # Setup the environment so that we have an isolated area + # to run Vagrant. We do some configuration here as well in order + # to replace "vagrant" with the proper path to Vagrant as well + # as tell the isolated environment about custom environmental + # variables to pass in. + let!(:environment) { new_environment } + + let(:config) { Vagrant::Spec::Acceptance::Configuration.new } + + let(:extra_env) { {} } + + # The skeleton paths that will be used to configure environments. + let(:skeleton_paths) do + root = Vagrant::Spec.source_root.join("acceptance", "support-skeletons") + config.skeleton_paths.dup.unshift(root) + end + + after(:each) do |example| + if example.exception.nil? || config.clean_on_fail + environment.close + else + example.reporter.message("Temporary work and home dirs (#{environment.workdir} and #{environment.homedir}) not removed to allow debug") + end + end + + # Creates a new isolated environment instance each time it is called. + # + # @return [Acceptance::IsolatedEnvironment] + def new_environment(env=nil) + apps = { "vagrant" => config.vagrant_path } + env = config.env.merge(env || {}) + env.merge!(extra_env) + + VagrantPlugins::VagrantLibvirt::Spec::AcceptanceIsolatedEnvironment.new( + apps: apps, + env: env, + skeleton_paths: skeleton_paths, + ) + end + + # Executes the given command in the context of the isolated environment. + # + # @return [Object] + def execute(*args, env: nil, log: true, &block) + env ||= environment + status("Execute: #{args.join(" ")}") if log + env.execute(*args, &block) + 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, env: nil, &block) + result = execute(*args, env: env, &block) + expect(result).to exit_with(0) + result + end + + def status(message) + RSpec.world.reporter.message(message) + end +end diff --git a/spec/support/acceptance/isolated_environment.rb b/spec/support/acceptance/isolated_environment.rb new file mode 100644 index 0000000..e8abde1 --- /dev/null +++ b/spec/support/acceptance/isolated_environment.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'vagrant-spec/acceptance/isolated_environment' +require 'vagrant-spec/subprocess' +require 'vagrant-spec/which' + +module VagrantPlugins + module VagrantLibvirt + module Spec + class AcceptanceIsolatedEnvironment < Vagrant::Spec::AcceptanceIsolatedEnvironment + # Executes a command in the context of this isolated environment. + # Any command executed will therefore see our temporary directory + # as the home directory. + # + # If the command has been defined with a special path, then the + # command will be replaced with the full path to that command. + def execute(command, *args, **options) + # Create the command + command = replace_command(command) + # Use provided command if it is a valid executable + if !File.executable?(command) + # If it's not a valid executable, search for vagrant + command = Vagrant::Spec::Which.which(command) + end + + # Build up the options + options[:env] = @env.merge(options.delete(:extra_env) || {}) + options[:notify] = [:stdin, :stderr, :stdout] + options[:workdir] = @workdir.to_s + + # Execute, logging out the stdout/stderr as we get it + @logger.info("Executing: #{[command].concat(args).inspect}") + Vagrant::Spec::Subprocess.execute(command, *args, **options) do |type, data| + @logger.debug("#{type}: #{data}") if type == :stdout || type == :stderr + yield type, data if block_given? + end + end + end + end + end +end diff --git a/spec/support/libvirt_acceptance_context.rb b/spec/support/libvirt_acceptance_context.rb new file mode 100644 index 0000000..028c05a --- /dev/null +++ b/spec/support/libvirt_acceptance_context.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require_relative 'acceptance/context' + +FALSEY_VALUES = %w[f false no n 0].freeze + +shared_context 'libvirt_acceptance' do + include_context 'acceptance' + + # The skeleton paths that will be used to configure environments. + let(:skeleton_paths) do + root = File.expand_path('../acceptance/support-skeletons', __dir__) + config.skeleton_paths.dup.unshift(root) + end + + let(:config) do + c = VagrantPlugins::VagrantLibvirt::Spec::Acceptance::Configuration.new + c.clean_on_fail = FALSEY_VALUES.include?(ENV.fetch('VAGRANT_SPEC_SKIP_CLEANUP', 'false').to_s.downcase) + + c + end + + before(:each) do + # allow execution environment to cache boxes used + symlink_boxes(ENV.fetch('VAGRANT_HOME', nil), environment) + end + + after(:each) do + # ensure we remove the symlink + boxes_symlink = File.join(environment.homedir, 'boxes') + File.delete(boxes_symlink) if File.symlink?(boxes_symlink) + end + + around do |example| + vagrant_cwd = ENV.delete('VAGRANT_CWD') + env_provider_before = ENV.fetch('VAGRANT_DEFAULT_PROVIDER', nil) + ENV['VAGRANT_DEFAULT_PROVIDER'] = 'libvirt' + + begin + example.run + ensure + ENV['VAGRANT_CWD'] = vagrant_cwd if vagrant_cwd + if env_provider_before.nil? + ENV.delete('VAGRANT_DEFAULT_PROVIDER') + else + ENV['VAGRANT_DEFAULT_PROVIDER'] = env_provider_before + end + end + end + + def duplicate_environment(env, *args) + dup_env = new_environment(*args) + symlink_boxes(env.homedir, dup_env) + + dup_env + end + + def symlink_boxes(vagrant_home, target_env) + return if vagrant_home.nil? + + # allow use the same boxes location as source environment + File.symlink File.realpath(File.join(vagrant_home, 'boxes')), File.join(target_env.homedir, 'boxes') + end +end diff --git a/tests/memory/Vagrantfile b/tests/memory/Vagrantfile deleted file mode 100644 index 2c872a0..0000000 --- a/tests/memory/Vagrantfile +++ /dev/null @@ -1,13 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : -# -# frozen_string_literal: true - -Vagrant.configure("2") do |config| - config.vm.box = "infernix/tinycore" - config.ssh.shell = "/bin/sh" - config.vm.synced_folder ".", "/vagrant", disabled: true - config.vm.provider :libvirt do |libvirt| - libvirt.memory = 1000 - end -end diff --git a/tests/parse_tests.awk b/tests/parse_tests.awk deleted file mode 100644 index 06a10b7..0000000 --- a/tests/parse_tests.awk +++ /dev/null @@ -1,14 +0,0 @@ -BEGIN { - printf "[" - previous="" -} -match($0, /@test "(.*)" \{/, arr) { - if ( previous != "" ) { - printf "%s, ",previous - } - previous = sprintf("\"%s\"", arr[1]) -} -END { - printf "%s",previous - print "]" -} diff --git a/tests/private_network/Vagrantfile b/tests/private_network/Vagrantfile deleted file mode 100644 index 114d6c1..0000000 --- a/tests/private_network/Vagrantfile +++ /dev/null @@ -1,14 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : -# -# frozen_string_literal: true - -Vagrant.configure("2") do |config| - # private network doesnt work with tinycore, use - # debian10 box for test - config.vm.box = "generic/debian10" - config.vm.synced_folder ".", "/vagrant", disabled: true - config.vm.define :test_vm1 do |test_vm1| - test_vm1.vm.network :private_network, :ip => "10.20.30.40" - end -end diff --git a/tests/runtests.bats b/tests/runtests.bats deleted file mode 100644 index 18b8b86..0000000 --- a/tests/runtests.bats +++ /dev/null @@ -1,275 +0,0 @@ -SCRIPT_DIR="$( cd "$BATS_TEST_DIRNAME" &> /dev/null && pwd )" -export PATH=$(dirname ${SCRIPT_DIR})/bin:${PATH} - -VAGRANT_CMD="vagrant" -VAGRANT_OPT="--provider=libvirt" - -TEMPDIR= - - -setup_file() { - # set VAGRANT_HOME to something else to reuse for tests to avoid clashes with - # user installed plugins when running tests locally. - if [ -z "${VAGRANT_HOME:-}" ] - then - TEMPDIR=$(mktemp -d 2>/dev/null) - - export VAGRANT_HOME=${TEMPDIR}/.vagrant.d - echo "# Using ${VAGRANT_HOME} for VAGRANT_HOME" >&3 - fi -} - -teardown_file() { - if [ -n "${TEMPDIR:-}" ] && [ -d "${TEMPDIR:-}" ] - then - rm -rf ${TEMPDIR:-} - fi -} - -cleanup() { - ${VAGRANT_CMD} destroy -f - if [ $? == "0" ]; then - return 0 - else - return 1 - fi -} - -@test "destroy simple vm" { - export VAGRANT_LOG=debug - export VAGRANT_CWD=tests/simple - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - cleanup -} - -@test "simple vm provision via shell" { - export VAGRANT_CWD=tests/simple_provision_shell - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "status = ${status}" - echo "${output}" - [ "$status" -eq 0 ] - [ $(expr "$output" : ".*Hello.*") -ne 0 ] - echo "${output}" - cleanup -} - -@test "bring up with custom default prefix" { - export VAGRANT_CWD=tests/default_prefix - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - [ "$status" -eq 0 ] - echo "${output}" - echo "status = ${status}" - [ $(expr "$output" : ".*changed_default_prefixdefault.*") -ne 0 ] - echo "${output}" - cleanup -} - -@test "bring up with second disk" { - export VAGRANT_CWD=tests/second_disk - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - echo "${output}" - [ $(expr "$output" : ".*second_disk_default-vdb.*") -ne 0 ] - run ${VAGRANT_CMD} halt - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - cleanup -} - -@test "bring up with two disks" { - export VAGRANT_CWD=tests/two_disks - cleanup - tools/create_box_with_two_disks.sh ${VAGRANT_HOME} ${VAGRANT_CMD} - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - echo "${output}" - [ $(expr "$output" : ".*Image.*2G") -ne 0 ] - [ $(expr "$output" : ".*Image.*10G") -ne 0 ] - cleanup -} - -@test "bring up with adjusted memory settings" { - export VAGRANT_CWD=tests/memory - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - echo "${output}" - [ $(expr "$output" : ".*Memory.*1000M.*") -ne 0 ] - cleanup -} - -@test "bring up with adjusted cpu settings" { - export VAGRANT_CWD=tests/cpus - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - echo "${output}" - [ $(expr "$output" : ".*Cpus.*2.*") -ne 0 ] - cleanup -} - -@test "bring up and use qemu agent for connectivity" { - export VAGRANT_CWD=tests/qemu_agent - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - echo "${output}" - cleanup -} - -@test "ip is reachable with private network" { - export VAGRANT_CWD=tests/private_network - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - echo "${output}" - [ $(expr "$output" : ".*Cpus.*2.*") -ne 0 ] - run fping 10.20.30.40 - [ "$status" -eq 0 ] - echo "${output}" - [ $(expr "$output" : ".*alive.*") -ne 0 ] - cleanup -} - -@test "package simple domain" { - export VAGRANT_CWD=tests/package_simple - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - rm -f package.box - run ${VAGRANT_CMD} package - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} destroy -f - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} box add --force package.box --name test-package-simple-domain - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - VAGRANT_VAGRANTFILE=Vagrantfile.testbox run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} box remove --force test-package-simple-domain - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - rm -f package.box - - cleanup -} - -@test "package complex example" { - export VAGRANT_CWD=tests/package_complex_example - # this will allow the host keys to be removed, and part of the sysprep script - # adds a step to trigger the regeneration. - export VAGRANT_LIBVIRT_VIRT_SYSPREP_OPERATIONS='defaults,-ssh-userdir,customize' - export VAGRANT_LIBVIRT_VIRT_SYSPREP_OPTIONS="--run $(pwd)/tests/package_complex_example/scripts/sysprep.sh" - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - rm -f package.box - run ${VAGRANT_CMD} package - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} destroy -f - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} box add --force package.box --name test-package-complex-example - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - VAGRANT_VAGRANTFILE=Vagrantfile.testbox run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} box remove --force test-package-complex-example - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - rm -f package.box - - cleanup -} - -@test "bring up and save a snapshot and restore it" { - export VAGRANT_CWD=tests/snapshot - - cleanup - run ${VAGRANT_CMD} up ${VAGRANT_OPT} - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} ssh -- -t 'touch a.txt' - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} snapshot save default test - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} ssh -- -t 'rm a.txt' - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} ssh -- -t 'ls a.txt' - echo "${output}" - echo "status = ${status}" - # This means that the file does not exist on the box. - [ "$status" -eq 1 ] - run ${VAGRANT_CMD} ssh -- -t 'touch b.txt' - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} snapshot restore default test - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} ssh -- -t 'ls b.txt' - echo "${output}" - echo "status = ${status}" - # This means that the file does not exist on the box. - [ "$status" -eq 1 ] - run ${VAGRANT_CMD} ssh -- -t 'ls a.txt' - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - run ${VAGRANT_CMD} snapshot delete default test - echo "${output}" - echo "status = ${status}" - [ "$status" -eq 0 ] - - cleanup -} diff --git a/tests/snapshot/Vagrantfile b/tests/snapshot/Vagrantfile deleted file mode 100644 index 150dfc7..0000000 --- a/tests/snapshot/Vagrantfile +++ /dev/null @@ -1,13 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : -# -# frozen_string_literal: true - -Vagrant.configure("2") do |config| - config.vm.box = "infernix/tinycore" - config.ssh.shell = "/bin/sh" - config.vm.synced_folder ".", "/vagrant", disabled: true - config.vm.provider :libvirt do |libvirt| - libvirt.cpus = 2 - end -end