foodtaster 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in foodtaster.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Mike Lapshin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # Foodtaster
2
+
3
+ Foodtaster is a library for testing your Chef code with RSpec. Specs
4
+ are actually executed on VirtualBox machine(s) managed by
5
+ [Vagrant](http://www.vagrantup.com/).
6
+
7
+ Foodtaster uses VM snapshots to bring something like DB transactions
8
+ into your cookbook specs. Before each Chef Run VM is rolled-back into
9
+ initial 'clean' state which removes any modifications made by
10
+ previously executed specs. It allows you to independently test different
11
+ cookbooks on a single VM.
12
+
13
+ Of course, you aren't limited by just one VM for your specs, you may
14
+ run as many as you need. PostgreSQL replication, load balancing and
15
+ even entire application environments becomes testable (of course, if
16
+ you have enought amount of RAM).
17
+
18
+ Foodtaster is on early development stage, so feedback is very
19
+ appreciated.
20
+
21
+ ## Quick Example
22
+
23
+ ```ruby
24
+ require 'spec_helper'
25
+
26
+ describe "nginx::default" do
27
+ run_chef_on :vm0 do |c|
28
+ c.json = {}
29
+ c.add_recipe 'nginx'
30
+ end
31
+
32
+ it "should install nginx as a daemon" do
33
+ vm0.should have_package 'nginx'
34
+ vm0.should have_user('www-data').in_group('www-data')
35
+ vm0.should listen_port(80)
36
+ vm0.should open_page("http://localhost/")
37
+
38
+ vm0.should have_file("/etc/init.d/nginx")
39
+ vm0.should have_file("/etc/nginx/nginx.conf").with_content(/gzip on/)
40
+ end
41
+
42
+ it "should have valid nginx config" do
43
+ result = vm0.execute("nginx -t")
44
+
45
+ result.should be_successfull
46
+ result.stdout.should include("/etc/nginx/nginx.conf syntax is ok")
47
+ end
48
+ end
49
+ ```
50
+
51
+ ## Installation
52
+
53
+ First, install Vagrant for your system following [official
54
+ instructions](http://docs.vagrantup.com/v2/installation/index.html).
55
+ Then, install two plugins: `sahara` and `vagrant-foodtaster-server`:
56
+
57
+ vagrant plugin install sahara
58
+ vagrant plugin install vagrant-foodtaster-server
59
+
60
+ That's all, you are ready to go.
61
+
62
+ ## Usage
63
+
64
+ In your Chef repository, create a basic Gemfile:
65
+
66
+ source 'https://rubygems.org/'
67
+
68
+ gem 'rspec'
69
+ gem 'foodtaster'
70
+
71
+ Then, create a Vagrantfile describing VMs you need for specs. Here is
72
+ [example
73
+ Vagrantfile](http://raw.github.com/mlapshin/foodtaster-example/master/Vagrantfile).
74
+
75
+ Create `spec` folder with `spec_helper.rb` file:
76
+
77
+ ```ruby
78
+ require 'foodtaster'
79
+
80
+ RSpec.configure do |config|
81
+ config.color_enabled = true
82
+ end
83
+
84
+ Foodtaster.configure do |config|
85
+ config.log_level = :info
86
+ end
87
+ ```
88
+
89
+ You are ready to write cookbook specs. Run them as usual with command:
90
+
91
+ bundle exec rspec spec
92
+
93
+ ## Contributing
94
+
95
+ 1. Fork it
96
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
97
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
98
+ 4. Push to the branch (`git push origin my-new-feature`)
99
+ 5. Create new Pull Request
100
+
101
+ ## License
102
+
103
+ Foodtaster is distributed under [MIT
104
+ License](http://raw.github.com/mlapshin/foodtaster/master/LICENSE).
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'foodtaster/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "foodtaster"
8
+ gem.version = Foodtaster::VERSION
9
+ gem.authors = ["Mike Lapshin"]
10
+ gem.email = ["mikhail.a.lapshin@gmail.com"]
11
+ gem.description = %q{RSpec for Chef cookbooks run on Vagrant}
12
+ gem.summary = %q{Foodtaster is a library for testing your Chef code with RSpec.}
13
+ gem.homepage = "http://github.com/mlapshin/foodtaster"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency('rspec', '>= 2.10.0')
21
+ end
@@ -0,0 +1,30 @@
1
+ require 'drb'
2
+
3
+ module Foodtaster
4
+ class Client
5
+ def initialize(drb_port)
6
+ # start local service to be able to redirect stdout & stderr
7
+ # to client
8
+ DRb.start_service("druby://localhost:0")
9
+ @v = DRbObject.new_with_uri("druby://localhost:#{drb_port}")
10
+
11
+ init
12
+ end
13
+
14
+ [:vm_defined?, :prepare_vm, :rollback_vm,
15
+ :run_chef_on_vm, :execute_command_on_vm].each do |method_name|
16
+ define_method method_name do |*args|
17
+ @v.send(method_name, *args)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def init
24
+ $stdout.extend DRbUndumped
25
+ $stderr.extend DRbUndumped
26
+
27
+ @v.redirect_stdstreams($stdout, $stderr)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ module Foodtaster
2
+ class Config
3
+ %w(log_level drb_port vagrant_binary).each do |attr|
4
+ attr_accessor attr.to_sym
5
+ end
6
+
7
+ def initialize
8
+ @log_level = :info
9
+ @drb_port = 35672
10
+ @vagrant_binary = 'vagrant'
11
+ end
12
+
13
+ def self.default
14
+ self.new
15
+ end
16
+ end
17
+
18
+ class << self
19
+ def config
20
+ @config ||= Config.default
21
+ end
22
+
23
+ def configure
24
+ if block_given?
25
+ yield(self.config)
26
+ else
27
+ raise ArgumentError, "No block given"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ RSpec::configure do |config|
2
+ config.include Foodtaster::RSpec::ExampleMethods
3
+ config.extend Foodtaster::RSpec::DslMethods
4
+
5
+ config.before(:suite) do
6
+ Foodtaster::RSpecRun.current.start
7
+ end
8
+
9
+ config.after(:suite) do
10
+ Foodtaster::RSpecRun.current.stop
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ module Foodtaster
2
+ module RSpec
3
+ module DslMethods
4
+ def run_chef_on(vm_name, &block)
5
+ Foodtaster::RSpecRun.current.require_vm(vm_name)
6
+
7
+ skip_rollback = true
8
+
9
+ before(:all) do
10
+ vm = get_vm(vm_name)
11
+ vm.rollback unless skip_rollback
12
+ run_chef_on(vm_name, &block)
13
+ end
14
+
15
+ let(vm_name) { get_vm(vm_name) }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,40 @@
1
+ module Foodtaster
2
+ module RSpec
3
+ module ExampleMethods
4
+ def get_vm(vm_name)
5
+ Foodtaster::RSpecRun.current.get_vm(vm_name)
6
+ end
7
+
8
+ def run_chef_on(vm_name, &block)
9
+ chef_config = ChefConfig.new.tap{ |conf| block.call(conf) }.to_hash
10
+ vm = get_vm(vm_name)
11
+ vm.run_chef(chef_config)
12
+ end
13
+
14
+ private
15
+
16
+ class ChefConfig
17
+ attr_accessor :json, :run_list
18
+
19
+ def initialize
20
+ @json = {}
21
+ @run_list = []
22
+ end
23
+
24
+ def add_recipe(name)
25
+ name = "recipe[#{name}]" unless name =~ /^recipe\[(.+?)\]$/
26
+ run_list << name
27
+ end
28
+
29
+ def add_role(name)
30
+ name = "role[#{name}]" unless name =~ /^role\[(.+?)\]$/
31
+ run_list << name
32
+ end
33
+
34
+ def to_hash
35
+ { json: json, run_list: run_list }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,72 @@
1
+ module Foodtaster
2
+ module RSpec
3
+ module Matchers
4
+ class FileMatcher
5
+ def initialize(path)
6
+ @path = path
7
+ end
8
+
9
+ def matches?(vm)
10
+ @vm = vm
11
+ @results = {}
12
+ return false unless vm.execute("sudo test -e #{@path}").successful?
13
+
14
+
15
+ if @content
16
+ @actual_content = vm.execute("sudo cat #{@path}").stdout
17
+
18
+ if @content.is_a?(Regexp)
19
+ @results[:content] = !!@actual_content.match(@content)
20
+ else
21
+ @results[:content] = (@actual_content.to_s == @content.to_s)
22
+ end
23
+ end
24
+
25
+ if @owner
26
+ @actual_owner = vm.execute("sudo stat #{@path} -c \"%U\"").stdout.chomp
27
+
28
+ @results[:owner] = (@actual_owner.to_s == @owner.to_s)
29
+ end
30
+
31
+ @results.values.all?
32
+ end
33
+
34
+ def with_content(content)
35
+ @content = content
36
+
37
+ self
38
+ end
39
+
40
+ def with_owner(owner)
41
+ @owner = owner
42
+
43
+ self
44
+ end
45
+
46
+ def failure_message_for_should
47
+ ["expected that #{@vm.name} should have file '#{@path}'",
48
+ @content && !@results[:content] && "with content #{@content.inspect}, but actual content is:\n#{@actual_content.inspect}\n",
49
+ @owner && !@results[:owner] && "with owner #{@owner}, but actual owner is #{@actual_owner}"].delete_if { |a| !a }.join(" ")
50
+ end
51
+
52
+ def failure_message_for_should_not
53
+ "expected that #{@vm.name} should not have file '#{@path}'"
54
+ end
55
+
56
+ def description
57
+ ["have file '#{@path}'",
58
+ @content && "with content #{@content.inspect}",
59
+ @owner && "with owner #{@owner}"].delete_if { |a| !a }.join(" ")
60
+ end
61
+ end
62
+
63
+ module MatcherMethods
64
+ def have_file(path)
65
+ FileMatcher.new(path)
66
+ end
67
+
68
+ alias_method :have_directory, :have_file
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,120 @@
1
+ require 'timeout'
2
+
3
+ # RSpec::Matchers.send(:include, VagrantHelper::Matchers::MatcherMethods)
4
+
5
+ RSpec::Matchers.define :have_running_process do |process|
6
+ match do |vm|
7
+ vm.execute("pgrep #{process}").successful?
8
+ end
9
+
10
+ failure_message_for_should do |vm|
11
+ "expected that #{vm.name} should have running process '#{process}'"
12
+ end
13
+
14
+ failure_message_for_should_not do |vm|
15
+ "expected that #{vm.name} should not have running process '#{process}'"
16
+ end
17
+
18
+ description do
19
+ "have running process '#{process}'"
20
+ end
21
+ end
22
+
23
+ RSpec::Matchers.define :have_package do |package|
24
+ match do |vm|
25
+ vm.execute("dpkg --status #{package}").successful?
26
+ end
27
+
28
+ failure_message_for_should do |vm|
29
+ "expected that #{vm.name} should have installed package '#{package}'"
30
+ end
31
+
32
+ failure_message_for_should_not do |vm|
33
+ "expected that #{vm.name} should not have installed package '#{package}'"
34
+ end
35
+
36
+ description do
37
+ "have installed package '#{package}'"
38
+ end
39
+ end
40
+
41
+ # TODO: I'm not sure if lsof is installed by default
42
+ RSpec::Matchers.define :listen_port do |port|
43
+ match do |vm|
44
+ ->{ vm.execute("sudo lsof -i :#{port.to_s} > /dev/null") }.should be_successful
45
+ end
46
+
47
+ failure_message_for_should do |vm|
48
+ "expected that #{vm.name} should listen port '#{port}'"
49
+ end
50
+
51
+ failure_message_for_should_not do |vm|
52
+ "expected that #{vm.name} should not listen port '#{port}'"
53
+ end
54
+
55
+ description do
56
+ "listen port '#{port}'"
57
+ end
58
+ end
59
+
60
+ RSpec::Matchers.define :have_group do |group|
61
+ match do |vm|
62
+ vm.execute("cat /etc/group | cut -d: -f1 | grep \"\\<#{group}\\>\"").successful?
63
+ end
64
+
65
+ failure_message_for_should do |vm|
66
+ "expected that #{vm.name} should have group '#{group}'"
67
+ end
68
+
69
+ failure_message_for_should_not do |vm|
70
+ "expected that #{vm.name} should not have group '#{group}'"
71
+ end
72
+
73
+ description do
74
+ "have group '#{group}'"
75
+ end
76
+ end
77
+
78
+ RSpec::Matchers.define :open_page do |address|
79
+ match do |vm|
80
+ result = vm.execute("wget #{address} -O /tmp/test-page").successful?
81
+ vm.execute("rm /tmp/test-page")
82
+ result
83
+ end
84
+
85
+ failure_message_for_should do |vm|
86
+ "expected that #{vm.name} should open page '#{address}'"
87
+ end
88
+
89
+ failure_message_for_should_not do |vm|
90
+ "expected that #{vm.name} should not open page '#{address}'"
91
+ end
92
+
93
+ description do
94
+ "open page '#{address}'"
95
+ end
96
+ end
97
+
98
+ def wait_until(_timeout = 5)
99
+ begin
100
+ timeout _timeout do
101
+ until (result = yield)
102
+ sleep 0.5
103
+ end
104
+ result
105
+ end
106
+ rescue Timeout::Error
107
+ nil
108
+ end
109
+ end
110
+
111
+ RSpec::Matchers.define :be_successful do |opts = {}|
112
+ match do |command|
113
+ if command.respond_to?(:call)
114
+ wait_until(opts[:timeout] || 5) { command.call.successful? }
115
+ else
116
+ command.successful?
117
+ end
118
+ end
119
+ end
120
+
@@ -0,0 +1,63 @@
1
+ module Foodtaster
2
+ module RSpec
3
+ module Matchers
4
+ class UserMatcher
5
+ def initialize(username)
6
+ @username = username
7
+ end
8
+
9
+ def matches?(vm)
10
+ @vm = vm
11
+ @results = {}
12
+
13
+ unless vm.execute("cat /etc/passwd | cut -d: -f1 | grep \"\\<#{@username}\\>\"").successful?
14
+ @results[:user] = false
15
+ return false
16
+ end
17
+
18
+ if @group
19
+ @actual_groups = vm.execute("groups #{@username}").stdout.to_s.chomp.split(" ")[2..-1] || []
20
+ @results[:group] = !!@actual_groups.include?(@group)
21
+ end
22
+
23
+ @results.values.all?
24
+ end
25
+
26
+ def in_group(group)
27
+ @group = group
28
+
29
+ self
30
+ end
31
+
32
+ def failure_message_for_should
33
+ msg = ["expected that #{@vm.name} should have user '#{@username}'"]
34
+
35
+ if @group
36
+ msg << "in group #{@group.inspect}"
37
+
38
+ if @results.key?(:group) && !@results[:group]
39
+ msg << " but actual user groups are:\n#{@actual_groups.join(", ")}\n"
40
+ end
41
+ end
42
+
43
+ msg.join(" ")
44
+ end
45
+
46
+ def failure_message_for_should_not
47
+ "expected that #{@vm.name} should not have user '#{@username}'"
48
+ end
49
+
50
+ def description
51
+ ["have user '#{@username}'",
52
+ @group && "in group #{@group}"].delete_if { |a| !a }.join(" ")
53
+ end
54
+ end
55
+
56
+ module MatcherMethods
57
+ def have_user(username)
58
+ UserMatcher.new(username)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,15 @@
1
+ module Foodtaster
2
+ module RSpec
3
+ autoload :ExampleMethods, "foodtaster/rspec/example_methods"
4
+ autoload :DslMethods, "foodtaster/rspec/dsl_methods"
5
+ end
6
+ end
7
+
8
+ require 'foodtaster/rspec/config'
9
+
10
+ # require all matchers
11
+ Dir[File.dirname(__FILE__) + "/rspec/matchers/*.rb"].each do |f|
12
+ require f
13
+ end
14
+
15
+ RSpec::Matchers.send(:include, Foodtaster::RSpec::Matchers::MatcherMethods)
@@ -0,0 +1,97 @@
1
+ require 'set'
2
+
3
+ module Foodtaster
4
+ class RSpecRun
5
+ def initialize
6
+ @required_vm_names = Set.new
7
+ @client = nil
8
+ @server_pid = nil
9
+ end
10
+
11
+ def require_vm(vm_name)
12
+ @required_vm_names.add(vm_name.to_sym)
13
+ end
14
+
15
+ def required_vm_names
16
+ @required_vm_names
17
+ end
18
+
19
+ def get_vm(vm_name)
20
+ Foodtaster::Vm.new(vm_name, @client)
21
+ end
22
+
23
+ def start
24
+ at_exit { self.stop }
25
+
26
+ Foodtaster.logger.debug "Starting Foodtaster specs run"
27
+ start_server_and_connect_client
28
+ prepare_required_vms
29
+ end
30
+
31
+ def stop
32
+ puts "" # newline after rspec output
33
+ terminate_server
34
+ end
35
+
36
+ def client
37
+ @client
38
+ end
39
+
40
+ class << self
41
+ @instance = nil
42
+
43
+ def current
44
+ @instance ||= self.new
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def prepare_required_vms
51
+ self.required_vm_names.each { |vm_name| get_vm(vm_name).prepare }
52
+ end
53
+
54
+ def start_server_and_connect_client(drb_port = Foodtaster.config.drb_port)
55
+ vagrant_binary = Foodtaster.config.vagrant_binary
56
+ vagrant_server_cmd = "#{vagrant_binary} foodtaster-server #{drb_port.to_s} &> /tmp/vagrant-foodtaster-server-output.txt"
57
+
58
+ @server_pid = Process.spawn(vagrant_server_cmd, pgroup: true)
59
+ Foodtaster.logger.debug "Started foodtaster-server on port #{drb_port} with PID #{@server_pid}"
60
+
61
+ connect_client(drb_port)
62
+ end
63
+
64
+ def connect_client(drb_port)
65
+ retry_count = 0
66
+ begin
67
+ sleep 0.2
68
+ @client = Foodtaster::Client.new(drb_port)
69
+ rescue DRb::DRbConnError => e
70
+ Foodtaster.logger.debug "DRb connection failed: #{e.message}"
71
+ retry_count += 1
72
+ retry if retry_count < 10
73
+ end
74
+
75
+ if @client.nil?
76
+ server_output = File.read("/tmp/vagrant-foodtaster-server-output.txt")
77
+
78
+ Foodtaster.logger.fatal "Cannot start or connect to Foodtaster DRb server."
79
+ Foodtaster.logger.fatal "Server output:\n#{server_output}\n"
80
+
81
+ exit 1
82
+ else
83
+ Foodtaster.logger.debug "DRb connection established"
84
+ end
85
+ end
86
+
87
+ def terminate_server
88
+ pgid = Process.getpgid(@server_pid) rescue 0
89
+
90
+ if pgid > 0
91
+ Process.kill("INT", -pgid)
92
+ Process.wait(-pgid)
93
+ Foodtaster.logger.debug "Terminated foodtaster-server process"
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,3 @@
1
+ module Foodtaster
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,58 @@
1
+ module Foodtaster
2
+ class Vm
3
+ class ExecResult
4
+ attr_reader :stderr
5
+ attr_reader :stdout
6
+ attr_reader :exit_status
7
+
8
+ def initialize(hash)
9
+ @stderr = hash[:stderr]
10
+ @stdout = hash[:stdout]
11
+ @exit_status = hash[:exit_status]
12
+ end
13
+
14
+ def successful?
15
+ exit_status == 0
16
+ end
17
+ end
18
+
19
+ attr_reader :name
20
+
21
+ def initialize(name, client)
22
+ @name = name
23
+ @client = client
24
+
25
+ unless @client.vm_defined?(name)
26
+ raise ArgumentError, "No machine defined with name #{name}"
27
+ end
28
+ end
29
+
30
+ def prepare
31
+ Foodtaster.logger.info "#{name}: Preparing VM"
32
+ @client.prepare_vm(name)
33
+ end
34
+
35
+ def rollback
36
+ Foodtaster.logger.info "#{name}: Rollbacking VM"
37
+ @client.rollback_vm(name)
38
+ end
39
+
40
+ def execute(command)
41
+ Foodtaster.logger.debug "#{name}: Executing #{command}"
42
+ exec_result_hash = @client.execute_command_on_vm(name, command)
43
+
44
+ Foodtaster.logger.debug "#{name}: Finished with #{exec_result_hash[:exit_status]}"
45
+ Foodtaster.logger.debug "#{name}: STDOUT: #{exec_result_hash[:stdout].chomp}"
46
+ Foodtaster.logger.debug "#{name}: STDERR: #{exec_result_hash[:stderr].chomp}"
47
+
48
+ ExecResult.new(exec_result_hash)
49
+ end
50
+
51
+ def run_chef(config)
52
+ Foodtaster.logger.info "#{name}: Running Chef with Run List #{config[:run_list].join(', ')}"
53
+ Foodtaster.logger.debug "#{name}: with JSON: #{config[:json].inspect}"
54
+ @client.run_chef_on_vm(name, config)
55
+ Foodtaster.logger.debug "#{name}: Chef Run finished"
56
+ end
57
+ end
58
+ end
data/lib/foodtaster.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'foodtaster/config'
2
+ require 'foodtaster/rspec'
3
+
4
+ require 'logger'
5
+
6
+ module Foodtaster
7
+ autoload :Client, 'foodtaster/client'
8
+ autoload :Vm, 'foodtaster/vm'
9
+ autoload :RSpecRun, 'foodtaster/rspec_run'
10
+
11
+ class << self
12
+ def logger
13
+ @logger ||= Logger.new(STDOUT).tap do |log|
14
+ log_level = ENV['FT_LOGLEVEL'] || self.config.log_level.to_s.upcase
15
+ log.level = Logger.const_get(log_level)
16
+
17
+ log.formatter = proc do |severity, datetime, progname, msg|
18
+ "[FT #{severity}]: #{msg}\n"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: foodtaster
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mike Lapshin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.10.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 2.10.0
30
+ description: RSpec for Chef cookbooks run on Vagrant
31
+ email:
32
+ - mikhail.a.lapshin@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE
40
+ - README.md
41
+ - Rakefile
42
+ - foodtaster.gemspec
43
+ - lib/foodtaster.rb
44
+ - lib/foodtaster/client.rb
45
+ - lib/foodtaster/config.rb
46
+ - lib/foodtaster/rspec.rb
47
+ - lib/foodtaster/rspec/config.rb
48
+ - lib/foodtaster/rspec/dsl_methods.rb
49
+ - lib/foodtaster/rspec/example_methods.rb
50
+ - lib/foodtaster/rspec/matchers/file_matcher.rb
51
+ - lib/foodtaster/rspec/matchers/simple_matchers.rb
52
+ - lib/foodtaster/rspec/matchers/user_matcher.rb
53
+ - lib/foodtaster/rspec_run.rb
54
+ - lib/foodtaster/version.rb
55
+ - lib/foodtaster/vm.rb
56
+ homepage: http://github.com/mlapshin/foodtaster
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.24
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Foodtaster is a library for testing your Chef code with RSpec.
80
+ test_files: []