Skip to content
This repository has been archived by the owner on Jul 14, 2021. It is now read-only.

Verify command for chef which runs the specs for the components. #4

Merged
merged 3 commits into from
Mar 7, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Gemfile.local
# http://gembundler.com/man/bundle-exec.1.html
b/
binstubs/
vendor/

# RVM and RBENV ruby version files
.rbenv-version
Expand Down
1 change: 1 addition & 0 deletions chef-dk.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Gem::Specification.new do |gem|
gem.require_paths = ["lib"]

gem.add_dependency "mixlib-cli", "~> 1.4"
gem.add_dependency "mixlib-shellout", "~> 1.3"

%w(rspec-core rspec-expectations rspec-mocks).each do |dev_gem|
gem.add_development_dependency dev_gem, "~> 2.14.0"
Expand Down
20 changes: 3 additions & 17 deletions lib/chef-dk/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
require 'chef-dk/version'
require 'chef-dk/commands_map'
require 'chef-dk/builtin_commands'
require 'chef-dk/helpers'

module ChefDK
class CLI
include Mixlib::CLI
include ChefDK::Helpers

banner(<<-BANNER)
Usage:
Expand Down Expand Up @@ -78,7 +80,7 @@ def run_subcommands(params)
return false if subcommand_name.nil?
return false if option?(subcommand_name)
if have_command?(subcommand_name)
instantiate_subcommand(subcommand_name).run(subcommand_params)
instantiate_subcommand(subcommand_name).run_with_default_options(subcommand_params)
else
err("Unknown command `#{subcommand_name}'.")
show_help
Expand All @@ -96,22 +98,6 @@ def show_help
end
end

def err(message)
stderr.print("#{message}\n")
end

def msg(message)
stdout.print("#{message}\n")
end

def stdout
$stdout
end

def stderr
$stderr
end

def exit(n)
Kernel.exit(n)
end
Expand Down
36 changes: 35 additions & 1 deletion lib/chef-dk/command/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,56 @@
#

require 'mixlib/cli'
require 'chef-dk/helpers'
require 'chef-dk/version'

module ChefDK
module Command
class Base
include Mixlib::CLI
include ChefDK::Helpers

option :help,
:short => "-h",
:long => "--help",
:description => "Show this message",
:on => :tail,
:boolean => true

option :version,
:short => "-v",
:long => "--version",
:description => "Show chef version",
:boolean => true

def initialize
super
end

#
# optparser overwrites -h / --help options with its own.
# In order to control this behavior, make sure the default options are
# handled here.
#
def run_with_default_options(params = [ ])
if needs_help?(params)
msg(banner)
0
elsif needs_version?(params)
msg("Chef Development Kit Version: #{ChefDK::VERSION}")
0
else
run(params)
end
end

def needs_help?(params)
params.include?("-h") || params.include?("--help")
end

def needs_version?(params)
params.include?("-v") || params.include?("--version")
end

end
end
end
137 changes: 133 additions & 4 deletions lib/chef-dk/command/verify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,145 @@
#

require 'chef-dk/command/base'
require 'chef-dk/exceptions'

module ChefDK
module Command
class Verify < ChefDK::Command::Base
banner "Usage: chef verify <<TBD: options>>"
include ChefDK::Exceptions

def run(params)
parse_options
puts "TODO: Implement verify."
banner "Usage: chef verify"

class << self
def component(name, arguments)
components[name] = arguments
end

def components
@components ||= {}
@components
end
end

def components
self.class.components
end

#
# Components included in Chef Development kit:
# :base_dir => Relative path of the component w.r.t. #{omnibus_dir}/apps
# :test_cmd => Test command to be launched for the component
#
component "berkshelf",
:base_dir => "berkshelf",
# For berks the real command to run is "bundle exec thor spec:ci"
# We can't run it right now since mercurial specs are included in the
# test suite by default. We will be able to switch to that command when
# this is merged:
# https://github.com/berkshelf/berkshelf/pull/1021
:test_cmd => "bundle exec rspec --color --format progress spec/unit --tag ~hg && \
bundle exec cucumber --color --format progress --tags ~@no_run --strict"

component "test-kitchen",
:base_dir => "test-kitchen",
:test_cmd => "bundle exec rake"

component "chef-client",
:base_dir => "chef",
:test_cmd => "bundle exec rspec"


attr_reader :omnibus_dir
attr_reader :verification_threads
attr_reader :verification_results
attr_reader :verification_status

def initialize
super
@verification_threads = [ ]
@verification_results = [ ]
@verification_status = 0
end

def run(params = [ ])
locate_omnibus_dir
invoke_tests
wait_for_tests
report_results

verification_status
end

#
# Locates the directory components are installed on the system.
#
# In omnibus installations ruby lives at:
# omnibus_install_dir/embedded/bin and components live at
# omnibus_install_dir/embedded/apps
#
def locate_omnibus_dir
@omnibus_dir = File.expand_path(File.join(Gem.ruby, "..","..", "apps"))
raise OmnibusInstallNotFound.new() unless File.directory? omnibus_dir

components.each do |component, component_info|
unless File.exists? component_path(component_info)
raise MissingComponentError.new(component)
end
end
end

def component_path(component_info)
File.join(omnibus_dir, component_info[:base_dir])
end

def invoke_tests
components.each do |component, component_info|
# Run the component specs in parallel
verification_threads << Thread.new do
result = system_command component_info[:test_cmd],
:cwd => component_path(component_info),
:env => {
"PATH" => "#{File.join(omnibus_dir, "bin")}:#{ENV['PATH']}"
},
:timeout => 3600

@verification_status = 1 if result.exitstatus != 0

{
:component => component,
:result => result
}
end

msg("Running verification for component '#{component}'")
end
end

def wait_for_tests
while !verification_threads.empty?
verification_threads.each do |t|
if t.join(1)
verification_threads.delete t
verification_results << t.value
msg("")
msg(t.value[:result].stdout)
msg(t.value[:result].stderr) if t.value[:result].stderr
else
$stdout.write "."
end
end
end
end

def report_results
msg("")
msg("---------------------------------------------")
verification_results.each do |result|
message = result[:result].exitstatus == 0 ? "succeeded" : "failed"
msg("Verification of component '#{result[:component]}' #{message}.")
end
end

end
end
end
34 changes: 34 additions & 0 deletions lib/chef-dk/exceptions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#
# Copyright:: Copyright (c) 2014 Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

module ChefDK
module Exceptions

class MissingComponentError < RuntimeError
def initialize(component_name)
super("Component #{component_name} is missing.")
end
end

class OmnibusInstallNotFound < RuntimeError
def initialize()
super("Can not find omnibus installation directory for Chef.")
end
end

end
end
49 changes: 49 additions & 0 deletions lib/chef-dk/helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#
# Copyright:: Copyright (c) 2014 Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'mixlib/shellout'

module ChefDK
module Helpers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we break this up by function? It's not very unwieldy right now, but I can easily imagine library code wanting the system_command part but not needing the IO stuff. Long term as we accumulate more of this stuff, it'll be nice if it's separated by common function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agreed. Makes sense to leave this separation to future?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's fine for now, we just want to make sure we don't get stuck with it when we go 1.0


#
# Runs given commands using mixlib-shellout
#
def system_command(*command_args)
cmd = Mixlib::ShellOut.new(*command_args)
cmd.run_command
cmd
end

def err(message)
stderr.print("#{message}\n")
end

def msg(message)
stdout.print("#{message}\n")
end

def stdout
$stdout
end

def stderr
$stderr
end

end
end
22 changes: 22 additions & 0 deletions spec/helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# Copyright:: Copyright (c) 2014 Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

module Helpers
def fixtures_path
File.expand_path(File.dirname(__FILE__) + "/unit/fixtures/")
end
end
3 changes: 2 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
require 'rubygems'
require 'rspec/mocks'
require 'pry-debugger'
require 'helpers'

RSpec.configure do |c|
c.include ChefDK
c.include Helpers
end

2 changes: 1 addition & 1 deletion spec/unit/cli_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#
#
# Copyright:: Copyright (c) 2014 Chef Software Inc.
# License:: Apache License, Version 2.0
#
Expand Down
Loading