class Specinfra::Backend::DockerCompose

Specinfra and Serverspec backend for Docker Compose.

Public Class Methods

new(config = {}) click to toggle source

Constructs a Docker Compose Specinfra Backend.

@param config [Hash] Configuration options. @option config [String] docker_compose_file: Docker Compose

configuration file path (**required**).

@option config [String] docker_compose_container: The name of the

container you want to test (**required**). Only one can be tested.

@option config [Fixnum] docker_wait: Seconds to wait for containers to

start (i.e., time to sleep before running the tests)
(**recommended**).

@api public

Calls superclass method
# File lib/specinfra/backend/docker_compose.rb, line 40
def initialize(config = {})
  super

  ::Docker.url = get_config(:docker_url)

  file = get_config(:docker_compose_file)
  fail 'Please specify docker_compose_file.' unless file

  @compose = ::DockerCompose.load(file)
  ObjectSpace.define_finalizer(self, proc { finalize })
  Dir.chdir(::File.dirname(file)) { do_start }
end

Public Instance Methods

add_pre_command(cmd) click to toggle source

Adds a prefix or previous instruction to the command.

Does nothing.

@param cmd [String] The command to run. @return [String] The command. @api public

# File lib/specinfra/backend/docker_compose.rb, line 83
def add_pre_command(cmd)
  cmd
end
build_command(cmd) click to toggle source

Builds a command.

Does nothing.

@param cmd [String] The command to run. @return [String] The command. @api public

# File lib/specinfra/backend/docker_compose.rb, line 72
def build_command(cmd)
  cmd
end
run_command(cmd, opts = {}) click to toggle source

Runs a Specinfra command.

@param cmd [String] The command to run. @param opts [Hash] Options to pass to {Docker::Container#exec}. @return nil @api public

# File lib/specinfra/backend/docker_compose.rb, line 59
def run_command(cmd, opts = {})
  cmd = build_command(cmd)
  cmd = add_pre_command(cmd)
  docker_compose_run!(cmd, opts)
end
send_file(_from, _to) click to toggle source

Sends a file.

@note Not implemented yet. @param _from [String] The file origin. @param _to [String] The file destination. @raise [RuntimeError] Always raises an error. @return nil @api public

# File lib/specinfra/backend/docker_compose.rb, line 95
def send_file(_from, _to)
  fail 'docker_compose does not support send_file'
end

Protected Instance Methods

container() click to toggle source

Returns the selected Docker Container object.

Gets the container name to return from the `:docker_compose_container` Specinfra configuration option.

@return [Docker::Container] The container object. @raise [RuntimeError] When the container is not selected or the

selected container is not found.

@api private

# File lib/specinfra/backend/docker_compose.rb, line 121
def container
  if docker_compose_container.empty?
    fail 'Please specify docker_compose_container.'
  end
  compose_container = @compose.containers[docker_compose_container]
  if compose_container.nil?
    fail "Container not found: #{docker_compose_container.inspect}"
  end
  compose_container.container
end
do_start() click to toggle source

Starts Docker Compose and its containers.

It also calculates the time to wait before running the tests.

@return nil @api private

# File lib/specinfra/backend/docker_compose.rb, line 196
def do_start
  start_time = Time.new
  @compose.start
  do_wait((Time.new - start_time).to_i)
end
do_wait(waited) click to toggle source

Sleeps for some time if required.

Reads the seconds to sleep from the `:docker_wait` Specinfra configuration option.

@param waited [Integer] The time already waited. @return nil @api private

# File lib/specinfra/backend/docker_compose.rb, line 210
def do_wait(waited)
  wait = get_config(:docker_wait)
  return unless wait.is_a?(Integer) || wait.is_a?(Float)
  return if waited >= wait
  sleep(wait - waited)
end
docker_compose_container() click to toggle source

Returns the selected Docker Container name.

Gets the container name to return from the `:docker_compose_container` Specinfra configuration option.

@return [String] The container name. @api private

# File lib/specinfra/backend/docker_compose.rb, line 108
def docker_compose_container
  get_config(:docker_compose_container).to_s
end
docker_compose_run!(cmd, opts = {}) click to toggle source

Runs a command inside a Docker Compose container.

@param cmd [String] The command to run. @param opts [Hash] Options to pass to {Docker::Container#exec}. @return [Specinfra::CommandResult] The result. @api public

# File lib/specinfra/backend/docker_compose.rb, line 177
def docker_compose_run!(cmd, opts = {})
  stdout, stderr, status = container.exec(['/bin/sh', '-c', cmd], opts)
  rspec_example_metadata(cmd, stdout.join, stderr.join)
  CommandResult.new(
    stdout: stdout.join, stderr: stderr.join, exit_status: status
  )
rescue ::Docker::Error::DockerError
  raise
rescue => e
  finalize
  erroneous_result(cmd, e)
end
erroneous_result(cmd, exception) click to toggle source

Parses a rescued exception and returns the command result.

@param cmd [Array<String>, String] The command. @param exception [Exception] The exception to parse. @return [Specinfra::CommandResult] The generated result object. @api public

# File lib/specinfra/backend/docker_compose.rb, line 149
def erroneous_result(cmd, exception)
  stdout = nil
  stderr = ([exception.message] + exception.backtrace).join("\n")
  status = 1
  rspec_example_metadata(cmd, stdout, stderr)
  CommandResult.new(stdout: stdout, stderr: stderr, exit_status: status)
end
finalize() click to toggle source

Stops the containers started by Docker Compose and deletes them.

Called automatically when this object is destroyed.

@return nil @api private

# File lib/specinfra/backend/docker_compose.rb, line 138
def finalize
  @compose.stop
  @compose.delete
end
rspec_example_metadata(cmd, stdout, stderr) click to toggle source

Updates RSpec metadata used by Serverspec.

@param cmd [Array<String>, String] The command. @param stdout [String, nil] The stdout output. @param stderr [String, nil] The stderr output. @return nil @api public

# File lib/specinfra/backend/docker_compose.rb, line 164
def rspec_example_metadata(cmd, stdout, stderr)
  return unless @example
  @example.metadata[:command] = cmd
  @example.metadata[:stdout] = stdout
  @example.metadata[:stderr] = stderr
end