Skip to content
This repository was archived by the owner on Nov 2, 2019. It is now read-only.

Commit

Permalink
Merge branch 'master' of github.com:miroswan/vagrant_spec
Browse files Browse the repository at this point in the history
  • Loading branch information
Demitri Swan committed Aug 9, 2016
2 parents 4099206 + cfedf9a commit c61dca9
Show file tree
Hide file tree
Showing 15 changed files with 206 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.vagrant
Gemfile.lock
vagrantspec_inventory
.vagrantspec_machine_data
serverspec/spec_helper.rb
coverage
pkg
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# vagrant_spec

[![Gem Version](https://badge.fury.io/rb/vagrant_spec.svg)](https://badge.fury.io/rb/vagrant_spec)
[![Build Status](https://travis-ci.org/miroswan/vagrant_spec.svg?branch=master)](https://travis-ci.org/miroswan/vagrant_spec)
[![Coverage Status](https://coveralls.io/repos/github/miroswan/vagrant_spec/badge.svg?branch=master)](https://coveralls.io/github/miroswan/vagrant_spec?branch=master)
[![Gem Version](https://badge.fury.io/rb/vagrant_spec.svg)](https://badge.fury.io/rb/vagrant_spec)


Vagrant Spec is a Vagrant plugin that makes integration testing for deployments
to clustered systems a breeze. It also separates the build and deployment steps
Expand Down Expand Up @@ -71,7 +72,14 @@ defaults to serverspec.
You can specify as many groups as you need. You can match nodes by regular
expression or explicitly provide an array of node names. This will generate
an vagrantspec_inventory based on your active nodes. You use this file for
running ansible playbooks against your Vagrant instances.
running ansible playbooks against your Vagrant instances. Use this configuration
directive if you use ansible for orchestration.

* config.spec.generate_machine_data: a boolean. If true, the init sub-command
will generate a json file at .vagrantspec_machine_data containing relevant
ssh information for each of your nodes. This can be helpful when leveraging
orchestration tooling aside from ansible. You can use this data to direct your
orchestration to your local instances. The default is set to true.

* config.spec.test_plan: an array of hashes. nodes can either be a regular
expression object that matches your desired nodes or an explicit array of
Expand Down
20 changes: 15 additions & 5 deletions lib/vagrant_spec/command/init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'vagrant_spec/ansible_inventory'
require 'vagrant_spec/spec_helper'
require 'vagrant_spec/machine_data'
require 'vagrant_spec/config'

module VagrantSpec
Expand All @@ -15,12 +16,17 @@ class Init < Vagrant.plugin(2, :command)

DEFAULTS = VagrantSpec::Config::DEFAULTS

attr_accessor :config, :directory, :ansible_inventory
attr_accessor :config
attr_accessor :directory
attr_accessor :ansible_inventory
attr_accessor :generate_machine_data

def initialize(argv, env)
super
@config = VagrantSpec::Config.load env
@directory = @config.spec.directory
@ansible_inventory = @config.spec.ansible_inventory
@config = VagrantSpec::Config.load env
@directory = @config.spec.directory
@ansible_inventory = @config.spec.ansible_inventory
@generate_machine_data = @config.spec.generate_machine_data
end

def execute
Expand All @@ -29,14 +35,18 @@ def execute
unless @ansible_inventory == DEFAULTS['ansible_inventory']
VagrantSpec::AnsibleInventory.new(@env).generate
end
if @generate_machine_data == DEFAULTS['generate_machine_data']
VagrantSpec::MachineData.new(@env).generate
end
end

def parse_opts
opts = OptionParser.new do |o|
o.banner = "\nCreates the serverspec/spec_helper.rb file for testing"
o.banner = "\nInit: Initializes state configuration"
o.separator ''
o.separator 'Usage: vagrant spec init'
o.separator ''
o.separator IO.read(File.join(template_dir, 'init_help'))
end
parse_options(opts)
end
Expand Down
5 changes: 4 additions & 1 deletion lib/vagrant_spec/command/test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# encoding: UTF-8

require 'vagrant_spec/test_plan'
require 'vagrant_spec/utils'

module VagrantSpec
module Command
Expand All @@ -9,6 +10,7 @@ module Command
# argv
# env [Vagrant::Environment]
class Test < Vagrant.plugin(2, :command)
include VagrantSpec::Utils
def initialize(argv, env)
super
end
Expand All @@ -20,10 +22,11 @@ def execute

def parse_opts
opts = OptionParser.new do |o|
o.banner = "\nRun the tests configured in the Vagrantfile"
o.banner = "\nTest: Run the tests configured in the Vagrantfile"
o.separator ''
o.separator 'Usage: vagrant spec test'
o.separator ''
o.separator IO.read(File.join(template_dir, 'test_help'))
end
parse_options(opts)
end
Expand Down
7 changes: 4 additions & 3 deletions lib/vagrant_spec/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ module Config
autoload :Base, 'vagrant_spec/config/base'

DEFAULTS = {
'directory' => 'serverspec',
'ansible_inventory' => {},
'test_plan' => []
'directory' => 'serverspec',
'ansible_inventory' => {},
'test_plan' => [],
'generate_machine_data' => true
}.freeze

class << self
Expand Down
15 changes: 12 additions & 3 deletions lib/vagrant_spec/config/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ class Base < Vagrant.plugin(2, :config)
attr_accessor :directory
attr_accessor :ansible_inventory
attr_accessor :test_plan
attr_accessor :generate_machine_data

def initialize
@directory = UNSET_VALUE
@ansible_inventory = UNSET_VALUE
@test_plan = UNSET_VALUE
@directory = UNSET_VALUE
@ansible_inventory = UNSET_VALUE
@test_plan = UNSET_VALUE
@generate_machine_data = UNSET_VALUE
end

def final_directory
Expand All @@ -32,10 +34,17 @@ def final_test_plan
@test_plan = DEFAULTS['test_plan'] if @test_plan == UNSET_VALUE
end

def final_generate_machine_data
if @generate_machine_data == UNSET_VALUE
@generate_machine_data = DEFAULTS['generate_machine_data']
end
end

def finalize!
final_directory
final_ansible_inventory
final_test_plan
final_generate_machine_data
end
end
end
Expand Down
34 changes: 34 additions & 0 deletions lib/vagrant_spec/machine_data.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# encoding: UTF-8

require 'json'
require 'vagrant_spec/machine_finder'

module VagrantSpec
# Handle machine data generation
class MachineData
attr_accessor :env, :m_finder, :data
def initialize(env)
@env = env
@m_finder = VagrantSpec::MachineFinder.new(@env)
@data = []
end

def generate
populate_data
IO.write('.vagrantspec_machine_data', JSON.pretty_generate(@data))
end

def populate_data
@m_finder.machines do |m|
private_key = m.ssh_info[:private_key_path][0]
@data << {
name: m.name,
host: m.ssh_info[:host],
port: m.ssh_info[:port],
username: m.ssh_info[:username],
private_key: private_key
}
end
end
end
end
7 changes: 7 additions & 0 deletions lib/vagrant_spec/machine_finder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ def machine(name)
nil
end

# Yield active machines
#
# yield [Vagrant::Machine]
def machines
@env.active_machines.each { |m| yield @env.machine(*m) }
end

# reg [Regexp]
#
# return [Array<Vagrant::Machine>]
Expand Down
16 changes: 16 additions & 0 deletions lib/vagrant_spec/templates/init_help
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
The init subcommand initializes state-based configuration for vagrant_spec.

It creates a spec_helper.rb file under the configured serverspec directory. This
file is used to setup serverspec backend configuration and ease serverspec
testing.

If config.spec.ansible_inventory configuration directive is used within the
Vagrantfile, then init will generate a test inventory file
vagrantspec_inventory. This file can be used for ansible orchestration against
the vagrant instances.

By default, init will generate a json file containing machine data for each
vagrant instance at .vagrantspec_machine_data. This file can be used by
orchestration tooling outside of ansible to map events to vagrant nodes. The
config.spec.generate_machine_data configuration parameter controls the
generation of this file.
2 changes: 1 addition & 1 deletion lib/vagrant_spec/templates/spec_helper.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ options[:keys] = ENV['VAGRANT_KEY']
options[:port] = ENV['VAGRANT_PORT']

set :host, host
set :ssh_options, options
set :ssh_options, options
21 changes: 21 additions & 0 deletions lib/vagrant_spec/templates/test_help
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The test subcommand will execute the serverspec tests configured in the
Vagrantfile under the config.spec.test_plan directive. This directive accepts
an array of hashes. For example:

config.spec.test_plan = [
{
'nodes' => /nginx/,
'flags' => '--format documentation --pattern serverspec/nginx*'
},
{
'nodes' => %w(app1 app2),
'flags' => '--format documentation --pattern serverspec/app*'
}
]

Each hash have two required keys: nodes and flags. The nodes key accepts a
regular expression object matching the names of the vagrant machines defined in
the Vagrantfile. Alternatively, you can explicility pass an array of node names.
The flags key accepts a string of command line arguments to pass to rspec. Any
of the acceptable rspec options and parameters are leagle.

1 change: 1 addition & 0 deletions scripts/poor_mans_smoke_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ bundle exec vagrant spec init -h
bundle exec vagrant spec test -h
bundle exec vagrant spec no_command -h
rm -f serverspec/spec_helper.rb
rm -f .vagrantspec_machine_data
bundle exec vagrant up
bundle exec vagrant spec init
ansible-playbook site.yml -i vagrantspec_inventory
Expand Down
32 changes: 28 additions & 4 deletions spec/unit/vagrant_spec_test/command_spec/init_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@
double(VagrantSpec::AnsibleInventory)
end

let(:mock_machine_data) do
double(VagrantSpec::MachineData)
end

before do
allow(mock_spec).to receive(:ansible_inventory) { { 'all' => /node/ } }
allow(mock_spec).to receive(:generate_machine_data)
end

subject { VagrantSpec::Command::Init.new([], iso_env) }
Expand All @@ -29,8 +34,10 @@ def execute_proc
proc do
allow_any_instance_of(VagrantSpec::SpecHelper).to receive(:generate)
allow_any_instance_of(VagrantSpec::AnsibleInventory).to receive(:generate)
allow(mock_spec_helper).to receive(:generate)
allow_any_instance_of(VagrantSpec::MachineData).to receive(:generate)
allow(mock_spec_helper).to receive(:generate)
allow(mock_ansible_inventory).to receive(:generate)
allow(mock_machine_data).to receive(:generate)
end
end

Expand All @@ -46,12 +53,11 @@ def execute_proc
def execute_protection_proc
proc do
allow(subject).to receive(:parse_opts) { 'not_nil' }
allow(VagrantSpec::SpecHelper).to receive(:new) do
mock_spec_helper
end
allow(VagrantSpec::SpecHelper).to receive(:new) { mock_spec_helper }
allow(VagrantSpec::AnsibleInventory).to receive(:new) do
mock_ansible_inventory
end
allow(VagrantSpec::MachineData).to receive(:new) { mock_machine_data }
execute_proc.call
end
end
Expand All @@ -77,6 +83,24 @@ def execute_protection_proc
subject.execute
end
end

context 'and when @generate_machine_data is true' do
it '#execute generates a .vagrantspec_machine_data file' do
execute_protection_proc.call
subject.generate_machine_data = true
expect(mock_machine_data).to receive(:generate)
subject.execute
end
end

context 'and when @generate_machine_data is false' do
it '#execute does not generate a .vagrantspec_machine_data file' do
execute_protection_proc.call
subject.generate_machine_data = false
expect(mock_machine_data).not_to receive(:generate)
subject.execute
end
end
end

it '#parse_opts calls parse_options' do
Expand Down
51 changes: 51 additions & 0 deletions spec/unit/vagrant_spec_test/machine_data_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# encoding: UTF-8

require 'spec_helper'
require 'vagrant_spec/machine_data'

describe VagrantSpec::MachineData do
include_context 'unit'
include_examples 'shared_mocks'

let(:mock_machine_ssh_config) do
{
host: '127.0.0.1',
port: '2222',
username: 'vagrant',
private_key_path: %w(mock_key)
}
end

let(:mock_data) do
{
name: 'default',
host: '127.0.0.1',
port: '2222',
username: 'vagrant',
private_key: 'mock_key'
}
end

before do
allow(mock_node).to receive(:name) { 'default' }
allow(mock_node).to receive(:ssh_info) { mock_machine_ssh_config }
end

subject { VagrantSpec::MachineData.new(iso_env) }

it '#generate create the .vagrantspec_machine_data file' do
allow(subject).to receive(:populate_data)
allow(IO).to receive(:write)
.with('.vagrantspec_machine_data', JSON.pretty_generate(subject.data))
expect(IO).to receive(:write)
.with('.vagrantspec_machine_data', JSON.pretty_generate(subject.data))
subject.generate
end

it '#populate_data stores json data' do
allow(subject.m_finder).to receive(:machines).and_yield(mock_node)
allow(mock_node).to receive(:ssh_info) { mock_machine_ssh_config }
expect(subject.data).to receive(:<<).with(mock_data)
subject.populate_data
end
end
1 change: 1 addition & 0 deletions vagrant_spec.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Gem::Specification.new do |s|
s.name = 'vagrant_spec'
s.version = VagrantSpec::VERSION
s.platform = Gem::Platform::RUBY
s.licenses = %w(Apache2)
s.authors = %w(Demitri Swan)
s.email = %w([email protected])
s.homepage = 'http://github.com/miroswan/vagrant_spec'
Expand Down

0 comments on commit c61dca9

Please sign in to comment.