Search code examples
rubydockerrspecserverspec

serverspec using wrong container


I have 2 spec files that use different docker images and therefore are suppose to start separate and different docker containers to run the examples.

In the snippets below I'm using the serverspec gem to test my containers

spec/dockerfile/ember_spec.rb

require 'spec_helper'
require 'shared_examples/release'

describe 'ember' do
  before(:all) do
    @image = Docker::Image.build_from_dir(image_path('ember'))

    set :os, family: :alpine
    set :backend, :docker
    set :docker_image, @image.id
    set :docker_container_create_options, { 'Entrypoint' => ['/bin/sh'] }
  end

  describe command('ember version') do
    its(:stdout) { should contain 'ember-cli: 3.3.0' }
    its(:stdout) { should contain 'node: 10.10.0' }
  end

  include_examples 'os release', 'Alpine Linux'
end

spec/dockerfile/gerbv_spec.rb

require 'spec_helper'
require 'shared_examples/release'

describe 'gerbv' do
  before(:all) do
    @image = Docker::Image.build_from_dir(image_path('gerbv'))

    set :os, family: :debian
    set :backend, :docker
    set :docker_image, @image.id
    set :docker_container_create_options, { 'Entrypoint' => ['/bin/sh'] }
  end

  describe package('gerbv') do
    it { should be_installed }
  end

  include_examples 'os release', 'Ubuntu 18.04'
end

However when running bundle exec rspec it is quite clear that the same container is being used to run each spec file. I have confirmed this by printing out the running containers before each of the examples. This is of course causing the specs to fail for one of the files (whichever runs second).

When the files are run independently using bundle exec rspec path/to/file then all the specs pass.

Is there any way to force a container to be spun down after the examples in one file have run and a new container created for the other set of examples?


Solution

  • I found a way to solve the problem, albeit a pretty hacky one. The key to this problem lay in how the container is finally released. When there are no longer any references pointing to the Docker instance it will be garbage collected and the container killed and deleted. However the object instance is held in a class level variable as a singleton in the base class. It would seem to me the only way to "reset" specinfra is to call the clear method inherited on the Docker class.

    In the end the following solved the problem and the correct class is being used to run each spec.

    after(:all) {
      Specinfra.backend.class.clear
    }
    

    It would be great to know there is a better way to access this methods without having to rely on a method not exposed through the serverspec gem.