Skip to content

Testing

Modules should be tested at three increasing levels of fidelity: smoke tests, unit tests, and acceptance tests. jig handles smoke and unit testing directly; voxbox runs the full suite — including acceptance tests — in a container.

Smoke tests

Smoke tests are simple lint and parser checks. Run them with:

$ jig validate

This catches syntax errors and style violations early. Many style issues can be auto-corrected by the underlying linters (puppet-lint, rubocop), which are included in voxbox.

Unit tests

Unit tests are Ruby scripts that use rspec-puppet to test a module's behavior. A basic unit test — like the one created by jig new class or jig new defined_type — just checks that the code compiles:

require 'spec_helper'

describe 'classname' do
  on_supported_os.each do |os, os_facts|
    context "on #{os}" do
      let(:facts) { os_facts }

      it { is_expected.to compile }
    end
  end
end

Run a module's unit tests with either tool:

$ jig test unit
$ podman run -it --rm -v $PWD:/repo:Z ghcr.io/voxpupuli/voxbox:8 spec

A more thorough unit test asserts that specific resources are present with the expected attributes:

# zram/spec/classes/init_spec.rb
require 'spec_helper'
describe 'zram' do
  on_supported_os.each do |os, facts|
    context "on #{os} with defaults for all parameters" do
      let(:facts) do
        facts.merge(
          :processorcount => 4,
          :memorysize_mb  => 4096,
          :augeasversion  => '1.4.0',
        )
      end
      it { is_expected.to compile }
      it { is_expected.to contain_class('zram') }
      it { is_expected.to contain_file('/lib/udev/zram').with(
        'ensure' => 'file',
        'owner'  => 'root',
        'group'  => 'root',
        'mode'   => '0755',
      )}
      it { is_expected.to contain_file('/etc/udev/rules.d/01-zram.rules').with(
        'ensure' => 'file',
      ).with_content(%r{^KERNEL=="zram\*", ACTION=="add", RUN=="/lib/udev/zram 536870912"$})}
    end
  end
end

Acceptance tests

Acceptance tests are Ruby scripts that apply code to a real (or containerized) system and validate the results. Common frameworks include:

These in turn use Serverspec and rspec-puppet.

jig focuses on scaffolding and unit testing and does not run acceptance tests directly. voxbox, however, bundles the Vox Pupuli acceptance toolchain (voxpupuli-acceptance, beaker), so you can run the acceptance rake task in the container:

$ podman run -it --rm -v $PWD:/repo:Z ghcr.io/voxpupuli/voxbox:8 beaker

The acceptance frameworks can typically drive Docker containers, Vagrant VMs, and other backends to run tests against real systems. An example acceptance test:

# zram/spec/acceptance/init_spec.rb
require 'spec_helper_acceptance'

describe 'zram' do
  context 'default parameters' do
    it 'is expected to apply with no errors' do
      # Run twice to test idempotency
      apply_manifest('class { zram: }', 'catch_failures' => true)
      apply_manifest('class { zram: }', 'catch_changes' => true)
    end
    describe kernel_module('zram') do
      it { is_expected.to be_loaded }
    end
    describe file('/proc/swaps') do
      its(:content) { is_expected.to match(%r{^\/dev\/zram[0-9]}) }
    end
  end
end