test-kitchen 0.7.0 → 1.0.0.alpha.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/.travis.yml +11 -0
- data/.yardopts +3 -0
- data/Gemfile +13 -0
- data/Guardfile +11 -0
- data/LICENSE +15 -0
- data/README.md +131 -0
- data/Rakefile +69 -0
- data/bin/kitchen +9 -4
- data/features/cli.feature +17 -0
- data/features/cli_init.feature +156 -0
- data/features/support/env.rb +14 -0
- data/lib/kitchen/busser.rb +166 -0
- data/lib/kitchen/chef_data_uploader.rb +156 -0
- data/lib/kitchen/cli.rb +540 -0
- data/lib/kitchen/collection.rb +55 -0
- data/lib/kitchen/color.rb +46 -0
- data/lib/kitchen/config.rb +223 -0
- data/lib/kitchen/driver/base.rb +180 -0
- data/lib/kitchen/driver/dummy.rb +81 -0
- data/lib/kitchen/driver/ssh_base.rb +192 -0
- data/lib/kitchen/driver.rb +42 -0
- data/lib/kitchen/errors.rb +52 -0
- data/lib/kitchen/instance.rb +327 -0
- data/lib/kitchen/instance_actor.rb +42 -0
- data/lib/kitchen/loader/yaml.rb +105 -0
- data/lib/kitchen/logger.rb +145 -0
- data/{cookbooks/test-kitchen/libraries/helpers.rb → lib/kitchen/logging.rb} +13 -9
- data/lib/kitchen/manager.rb +45 -0
- data/lib/kitchen/metadata_chopper.rb +52 -0
- data/lib/kitchen/platform.rb +61 -0
- data/lib/kitchen/rake_tasks.rb +59 -0
- data/lib/kitchen/shell_out.rb +65 -0
- data/lib/kitchen/state_file.rb +88 -0
- data/lib/kitchen/suite.rb +76 -0
- data/lib/kitchen/thor_tasks.rb +62 -0
- data/lib/kitchen/util.rb +79 -0
- data/{cookbooks/test-kitchen/recipes/erlang.rb → lib/kitchen/version.rb} +9 -6
- data/lib/kitchen.rb +98 -0
- data/lib/vendor/hash_recursive_merge.rb +74 -0
- data/spec/kitchen/collection_spec.rb +80 -0
- data/spec/kitchen/color_spec.rb +54 -0
- data/spec/kitchen/config_spec.rb +201 -0
- data/spec/kitchen/driver/dummy_spec.rb +191 -0
- data/spec/kitchen/instance_spec.rb +162 -0
- data/spec/kitchen/loader/yaml_spec.rb +243 -0
- data/spec/kitchen/platform_spec.rb +48 -0
- data/spec/kitchen/state_file_spec.rb +122 -0
- data/spec/kitchen/suite_spec.rb +64 -0
- data/spec/spec_helper.rb +47 -0
- data/templates/plugin/driver.rb.erb +23 -0
- data/templates/plugin/license_apachev2.erb +15 -0
- data/templates/plugin/license_gplv2.erb +18 -0
- data/templates/plugin/license_gplv3.erb +16 -0
- data/templates/plugin/license_mit.erb +22 -0
- data/templates/plugin/license_reserved.erb +5 -0
- data/templates/plugin/version.rb.erb +12 -0
- data/test-kitchen.gemspec +44 -0
- metadata +290 -82
- data/config/Cheffile +0 -47
- data/config/Kitchenfile +0 -39
- data/config/Vagrantfile +0 -114
- data/cookbooks/test-kitchen/attributes/default.rb +0 -25
- data/cookbooks/test-kitchen/metadata.rb +0 -27
- data/cookbooks/test-kitchen/recipes/chef.rb +0 -19
- data/cookbooks/test-kitchen/recipes/compat.rb +0 -39
- data/cookbooks/test-kitchen/recipes/default.rb +0 -51
- data/cookbooks/test-kitchen/recipes/ruby.rb +0 -29
- data/lib/test-kitchen/cli/destroy.rb +0 -36
- data/lib/test-kitchen/cli/init.rb +0 -37
- data/lib/test-kitchen/cli/platform_list.rb +0 -37
- data/lib/test-kitchen/cli/project_info.rb +0 -44
- data/lib/test-kitchen/cli/ssh.rb +0 -36
- data/lib/test-kitchen/cli/status.rb +0 -36
- data/lib/test-kitchen/cli/test.rb +0 -68
- data/lib/test-kitchen/cli.rb +0 -282
- data/lib/test-kitchen/dsl.rb +0 -63
- data/lib/test-kitchen/environment.rb +0 -166
- data/lib/test-kitchen/platform.rb +0 -79
- data/lib/test-kitchen/project/base.rb +0 -159
- data/lib/test-kitchen/project/cookbook.rb +0 -97
- data/lib/test-kitchen/project/cookbook_copy.rb +0 -58
- data/lib/test-kitchen/project/ruby.rb +0 -37
- data/lib/test-kitchen/project/supported_platforms.rb +0 -75
- data/lib/test-kitchen/project.rb +0 -23
- data/lib/test-kitchen/runner/base.rb +0 -154
- data/lib/test-kitchen/runner/openstack/dsl.rb +0 -39
- data/lib/test-kitchen/runner/openstack/environment.rb +0 -141
- data/lib/test-kitchen/runner/openstack.rb +0 -147
- data/lib/test-kitchen/runner/vagrant.rb +0 -95
- data/lib/test-kitchen/runner.rb +0 -21
- data/lib/test-kitchen/scaffold.rb +0 -88
- data/lib/test-kitchen/ui.rb +0 -73
- data/lib/test-kitchen/version.rb +0 -21
- data/lib/test-kitchen.rb +0 -34
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
guard 'minitest' do
|
2
|
+
watch(%r|^spec/(.*)_spec\.rb|)
|
3
|
+
watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
4
|
+
watch(%r|^spec/spec_helper\.rb|) { "spec" }
|
5
|
+
end
|
6
|
+
|
7
|
+
guard 'cucumber' do
|
8
|
+
watch(%r{^features/.+\.feature$})
|
9
|
+
watch(%r{^features/support/.+$}) { 'features' }
|
10
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
11
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
2
|
+
|
3
|
+
Copyright 2012 Fletcher Nichol
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# Test Kitchen
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/opscode/test-kitchen.png?branch=1.0)](https://travis-ci.org/opscode/test-kitchen)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/opscode/test-kitchen.png)](https://codeclimate.com/github/opscode/test-kitchen)
|
5
|
+
|
6
|
+
A convergence integration test harness for configuration management systems.
|
7
|
+
|
8
|
+
# Getting started
|
9
|
+
|
10
|
+
|
11
|
+
Project Setup
|
12
|
+
-------------
|
13
|
+
|
14
|
+
In your `Gemfile`, add `test-kitchen` as a
|
15
|
+
dependency:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'test-kitchen', git: 'git://github.com/opscode/test-kitchen.git', branch: '1.0'
|
19
|
+
```
|
20
|
+
|
21
|
+
and run the `bundle` command to install:
|
22
|
+
|
23
|
+
$ bundle install
|
24
|
+
|
25
|
+
This will expose the `test-kitchen` CLI. Run `bundle exec kitchen init` to get started:
|
26
|
+
|
27
|
+
$ kitchen init
|
28
|
+
|
29
|
+
You will be prompted with a series of questions. In this guide, we
|
30
|
+
will be using the [kitchen vagrant driver](https://github.com/opscode/kitchen-vagrant).
|
31
|
+
|
32
|
+
```text
|
33
|
+
$ bundle exec kitchen init
|
34
|
+
create .kitchen.yml
|
35
|
+
append Rakefile
|
36
|
+
create test/integration/default
|
37
|
+
append .gitignore
|
38
|
+
append .gitignore
|
39
|
+
Add a Driver plugin to your Gemfile?
|
40
|
+
(y/n)> y
|
41
|
+
Enter gem name, `list', or `skip'>
|
42
|
+
kitchen-vagrant
|
43
|
+
append Gemfile
|
44
|
+
You must run `bundle install' to fetch any new gems.
|
45
|
+
```
|
46
|
+
|
47
|
+
Run the `bundle` command again to install the new vagrant driver:
|
48
|
+
|
49
|
+
$ bundle install
|
50
|
+
|
51
|
+
Open up the `.kitchen.yml` file created in the root of your
|
52
|
+
repository.
|
53
|
+
|
54
|
+
Now, it is time to get testing. Use the `--parallel` option to run
|
55
|
+
your tests in parallel. Trust us, it's faster!
|
56
|
+
|
57
|
+
$ bundle exec kitchen test
|
58
|
+
|
59
|
+
## The Kitchen YAML format
|
60
|
+
|
61
|
+
Test-Kitchen reads its configuration from the .kitchen.yml
|
62
|
+
configuration file at the root of your cookbook. It closely resembles
|
63
|
+
the format of .travis.yml which is intentional.
|
64
|
+
|
65
|
+
There are 4 stanzas in .kitchen.yml, driver_plugin, driver_config,
|
66
|
+
platforms, and suites. driver_plugin, platforms, and suites are
|
67
|
+
currently required. driver_config can optionally be used to set values
|
68
|
+
for all platforms defined.
|
69
|
+
|
70
|
+
The driver_plugin stanza is only one line long and defines which
|
71
|
+
driver is used by test-kitchen.
|
72
|
+
|
73
|
+
The platforms stanza defines individual virtual machines. Additional
|
74
|
+
driver_config, node attributes, and run_list can be defined in this stanza
|
75
|
+
|
76
|
+
The suites stanza defines sets of tests that you intend to be run on
|
77
|
+
each platform. A run_list and node attributes can be defined for each
|
78
|
+
suite. The run_list and node attributes will be merged with that of
|
79
|
+
each platform. In case of the conflict, the attributes defined on the
|
80
|
+
suite will triumph.
|
81
|
+
|
82
|
+
```yaml
|
83
|
+
|
84
|
+
---
|
85
|
+
driver_plugin: vagrant
|
86
|
+
|
87
|
+
platforms:
|
88
|
+
- name: ubuntu-12.04
|
89
|
+
driver_config:
|
90
|
+
box: opscode-ubuntu-12.04
|
91
|
+
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/boxes/opscode-ubuntu-12.04.box
|
92
|
+
|
93
|
+
- name: centos-6.3
|
94
|
+
driver_config:
|
95
|
+
box: opscode-centos-6.3
|
96
|
+
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/boxes/opscode-centos-6.3.box
|
97
|
+
run_list:
|
98
|
+
- recipe[yum::epel]
|
99
|
+
|
100
|
+
suites:
|
101
|
+
- name: stock_system_and_user
|
102
|
+
run_list:
|
103
|
+
- recipe[user::data_bag]
|
104
|
+
- recipe[rvm::system]
|
105
|
+
- recipe[rvm::user]
|
106
|
+
attributes:
|
107
|
+
users:
|
108
|
+
- wigglebottom
|
109
|
+
rvm:
|
110
|
+
user_installs:
|
111
|
+
- user: wigglebottom
|
112
|
+
default_ruby: 1.8.7
|
113
|
+
```
|
114
|
+
|
115
|
+
## Overriding .kitchen.yaml with .kitchen.<driver>.local.yml
|
116
|
+
|
117
|
+
TODO
|
118
|
+
|
119
|
+
## A Note
|
120
|
+
|
121
|
+
This project is currently in rapid development which means frequent releases,
|
122
|
+
potential for massive refactorings (that could be API breaking), and minimal
|
123
|
+
to no documentation. This will change as the project transitions to be used in
|
124
|
+
production environments.
|
125
|
+
|
126
|
+
Despite the warnings above, if you are still interested, please get in touch
|
127
|
+
via freenode/IRC (#chef-hacking),
|
128
|
+
Twitter ([@fnichol](https://twitter.com/fnichol)),
|
129
|
+
or Email ([fnichol@nichol.ca](mailto:fnichol@nichol.ca)).
|
130
|
+
|
131
|
+
For everyone else, watch [this space](https://github.com/opscode/test-kitchen).
|
data/Rakefile
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
Rake::TestTask.new do |t|
|
5
|
+
t.libs.push "lib"
|
6
|
+
t.test_files = FileList['spec/**/*_spec.rb']
|
7
|
+
t.verbose = true
|
8
|
+
end
|
9
|
+
|
10
|
+
task :default => [:test]
|
11
|
+
|
12
|
+
unless RUBY_ENGINE == 'jruby'
|
13
|
+
require 'cane/rake_task'
|
14
|
+
require 'tailor/rake_task'
|
15
|
+
require 'cucumber'
|
16
|
+
require 'cucumber/rake/task'
|
17
|
+
|
18
|
+
desc "Run cane to check quality metrics"
|
19
|
+
Cane::RakeTask.new do |cane|
|
20
|
+
cane.abc_exclude = %w(
|
21
|
+
Kitchen::RakeTasks#define
|
22
|
+
Kitchen::ThorTasks#define
|
23
|
+
Kitchen::CLI#pry_prompts
|
24
|
+
Kitchen::Instance#synchronize_or_call
|
25
|
+
)
|
26
|
+
cane.style_exclude = %w(
|
27
|
+
lib/vendor/hash_recursive_merge.rb
|
28
|
+
)
|
29
|
+
cane.doc_exclude = %w(
|
30
|
+
lib/vendor/hash_recursive_merge.rb
|
31
|
+
)
|
32
|
+
cane.style_measure = 160
|
33
|
+
end
|
34
|
+
|
35
|
+
Tailor::RakeTask.new do |task|
|
36
|
+
task.file_set('bin/*', 'binaries')
|
37
|
+
task.file_set('lib/**/*.rb', 'code') do |style|
|
38
|
+
# TODO: Tailor is confused thinking `module Kitchen` is a class. Until
|
39
|
+
# the classes are split in seperate files, let's punt on this
|
40
|
+
style.max_code_lines_in_class 1550, level: :warn
|
41
|
+
# NOTE: Kitchen::InitGenerator.default_yaml is over the default 30 lines
|
42
|
+
# and produces a warning. Since most of it is increasing readability of
|
43
|
+
# the data structure, allowing it here to prevent it from growing
|
44
|
+
style.max_code_lines_in_method 34
|
45
|
+
style.max_line_length 80, level: :warn
|
46
|
+
style.max_line_length 160, level: :error
|
47
|
+
end
|
48
|
+
task.file_set('spec/**/*.rb', 'tests') do |style|
|
49
|
+
# allow vertical alignment of `let(:foo) { block }` blocks
|
50
|
+
style.spaces_before_lbrace 1, level: :off
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
55
|
+
t.cucumber_opts = ['features', '-x', '--format progress']
|
56
|
+
end
|
57
|
+
|
58
|
+
Rake::Task[:default].enhance [:cane, :features, :tailor]
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "Display LOC stats"
|
62
|
+
task :stats do
|
63
|
+
puts "\n## Production Code Stats"
|
64
|
+
sh "countloc -r lib/kitchen lib/kitchen.rb"
|
65
|
+
puts "\n## Test Code Stats"
|
66
|
+
sh "countloc -r spec features"
|
67
|
+
end
|
68
|
+
|
69
|
+
Rake::Task[:default].enhance [:stats]
|
data/bin/kitchen
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: utf-8 -*-
|
2
3
|
|
3
|
-
|
4
|
-
#
|
5
|
-
|
4
|
+
# Trap interrupts to quit cleanly. See
|
5
|
+
# https://twitter.com/mitchellh/status/283014103189053442
|
6
|
+
Signal.trap("INT") { exit 1 }
|
6
7
|
|
7
|
-
|
8
|
+
$:.unshift File.join(File.dirname(__FILE__), %w{.. lib})
|
9
|
+
require 'rubygems'
|
10
|
+
require 'kitchen/cli'
|
11
|
+
|
12
|
+
Kitchen::CLI.start
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: Ensure that the Command Line Interface works as designed
|
2
|
+
In order to test code via CLI
|
3
|
+
As an Operator
|
4
|
+
I want to run the CLI with different arguments
|
5
|
+
|
6
|
+
Scenario: Running the help command exits cleanly
|
7
|
+
When I successfully run `kitchen help`
|
8
|
+
Then the exit status should be 0
|
9
|
+
And the output should contain "kitchen console"
|
10
|
+
And a file named ".kitchen/logs/kitchen.log" should exist
|
11
|
+
|
12
|
+
Scenario: Show the version number
|
13
|
+
When I successfully run `kitchen version`
|
14
|
+
Then the exit status should be 0
|
15
|
+
|
16
|
+
|
17
|
+
|
@@ -0,0 +1,156 @@
|
|
1
|
+
Feature: Ensure that the Command Line Interface init creates the correct files
|
2
|
+
In order to initialize an un-Kitchenified cookbook
|
3
|
+
As an Operator
|
4
|
+
I want to initialize a cookbook
|
5
|
+
|
6
|
+
|
7
|
+
@ok
|
8
|
+
Scenario: Basic init with no extras succeeds
|
9
|
+
When I run `kitchen init` interactively
|
10
|
+
And I type "n"
|
11
|
+
Then the exit status should be 0
|
12
|
+
And a directory named ".kitchen" should exist
|
13
|
+
And a directory named "test/integration/default" should exist
|
14
|
+
And the file ".gitignore" should contain:
|
15
|
+
"""
|
16
|
+
.kitchen/
|
17
|
+
.kitchen.local.yml
|
18
|
+
"""
|
19
|
+
And the file ".kitchen.yml" should contain:
|
20
|
+
"""
|
21
|
+
---
|
22
|
+
driver_plugin: vagrant
|
23
|
+
platforms:
|
24
|
+
- name: ubuntu-12.04
|
25
|
+
driver_config:
|
26
|
+
box: opscode-ubuntu-12.04
|
27
|
+
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/boxes/opscode-ubuntu-12.04.box
|
28
|
+
run_list:
|
29
|
+
- recipe[apt]
|
30
|
+
- name: ubuntu-10.04
|
31
|
+
driver_config:
|
32
|
+
box: opscode-ubuntu-10.04
|
33
|
+
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/boxes/opscode-ubuntu-10.04.box
|
34
|
+
run_list:
|
35
|
+
- recipe[apt]
|
36
|
+
- name: centos-6.3
|
37
|
+
driver_config:
|
38
|
+
box: opscode-centos-6.3
|
39
|
+
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/boxes/opscode-centos-6.3.box
|
40
|
+
run_list:
|
41
|
+
- recipe[yum::epel]
|
42
|
+
- name: centos-5.8
|
43
|
+
driver_config:
|
44
|
+
box: opscode-centos-5.8
|
45
|
+
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/boxes/opscode-centos-5.8.box
|
46
|
+
run_list:
|
47
|
+
- recipe[yum::epel]
|
48
|
+
suites:
|
49
|
+
- name: default
|
50
|
+
run_list: []
|
51
|
+
attributes: {}
|
52
|
+
"""
|
53
|
+
And a file named "Gemfile" should not exist
|
54
|
+
And a file named "Rakefile" should not exist
|
55
|
+
And a file named "Thorfile" should not exist
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
@ok
|
60
|
+
Scenario: Running with a Rakefile file appends Kitchen tasks
|
61
|
+
Given an empty file named "Rakefile"
|
62
|
+
When I run `kitchen init` interactively
|
63
|
+
And I type "n"
|
64
|
+
Then the exit status should be 0
|
65
|
+
And the file "Rakefile" should contain exactly:
|
66
|
+
"""
|
67
|
+
|
68
|
+
begin
|
69
|
+
require 'kitchen/rake_tasks'
|
70
|
+
Kitchen::RakeTasks.new
|
71
|
+
rescue LoadError
|
72
|
+
puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI']
|
73
|
+
end
|
74
|
+
|
75
|
+
"""
|
76
|
+
|
77
|
+
|
78
|
+
@ok
|
79
|
+
Scenario: Running with a Thorfile file appends Kitchen tasks
|
80
|
+
Given an empty file named "Thorfile"
|
81
|
+
When I run `kitchen init` interactively
|
82
|
+
And I type "n"
|
83
|
+
Then the exit status should be 0
|
84
|
+
And the file "Thorfile" should contain exactly:
|
85
|
+
"""
|
86
|
+
|
87
|
+
begin
|
88
|
+
require 'kitchen/thor_tasks'
|
89
|
+
Kitchen::ThorTasks.new
|
90
|
+
rescue LoadError
|
91
|
+
puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI']
|
92
|
+
end
|
93
|
+
|
94
|
+
"""
|
95
|
+
|
96
|
+
|
97
|
+
@ok
|
98
|
+
Scenario: Listing the drivers provides correct output, does not write Gemfile
|
99
|
+
When I run `kitchen init` interactively
|
100
|
+
And I type "y"
|
101
|
+
And I type "list"
|
102
|
+
And I type "skip"
|
103
|
+
Then the exit status should be 0
|
104
|
+
And a file named ".kitchen.yml" should exist
|
105
|
+
And a directory named ".kitchen" should exist
|
106
|
+
And a file named "Gemfile" should not exist
|
107
|
+
|
108
|
+
|
109
|
+
@ok
|
110
|
+
Scenario: Running the init command without a Gemfile provides warning and fails
|
111
|
+
When I run `kitchen init` interactively
|
112
|
+
And I type "y"
|
113
|
+
And I type "kitchen-vagrant"
|
114
|
+
And the output should contain "You do not have an existing Gemfile"
|
115
|
+
Then the exit status should be 1
|
116
|
+
|
117
|
+
|
118
|
+
@ok
|
119
|
+
Scenario: Running the init command succeeds
|
120
|
+
Given an empty file named "Gemfile"
|
121
|
+
When I run `kitchen init` interactively
|
122
|
+
And I type "y"
|
123
|
+
And I type "kitchen-vagrant"
|
124
|
+
Then the exit status should be 0
|
125
|
+
And the output should contain "You must run `bundle install' to fetch any new gems."
|
126
|
+
And a file named ".kitchen.yml" should exist
|
127
|
+
And a file named ".gitignore" should exist
|
128
|
+
And the file "Gemfile" should contain "gem 'kitchen-vagrant', :group => :integration"
|
129
|
+
|
130
|
+
|
131
|
+
@ok
|
132
|
+
Scenario: Running init with a correct metadata.rb works
|
133
|
+
Given a file named "metadata.rb" with:
|
134
|
+
"""
|
135
|
+
name "ntp"
|
136
|
+
license "Apache 2.0"
|
137
|
+
description "Installs and configures ntp as a client or server"
|
138
|
+
version "0.1.0"
|
139
|
+
recipe "ntp", "Installs and configures ntp either as a server or client"
|
140
|
+
|
141
|
+
%w{ ubuntu debian redhat centos fedora scientific amazon oracle freebsd }.each do |os|
|
142
|
+
supports os
|
143
|
+
end
|
144
|
+
"""
|
145
|
+
When I run `kitchen init` interactively
|
146
|
+
And I type "n"
|
147
|
+
Then the exit status should be 0
|
148
|
+
And the file ".kitchen.yml" should contain:
|
149
|
+
"""
|
150
|
+
suites:
|
151
|
+
- name: default
|
152
|
+
run_list:
|
153
|
+
- recipe[ntp]
|
154
|
+
attributes: {}
|
155
|
+
"""
|
156
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Set up the environment for testing
|
2
|
+
require 'aruba/cucumber'
|
3
|
+
require 'kitchen'
|
4
|
+
|
5
|
+
Before do
|
6
|
+
@aruba_timeout_seconds = 5
|
7
|
+
end
|
8
|
+
|
9
|
+
After do |s|
|
10
|
+
# Tell Cucumber to quit after this scenario is done - if it failed.
|
11
|
+
# This is useful to inspect the 'tmp/aruba' directory before any other
|
12
|
+
# steps are executed and clear it out.
|
13
|
+
Cucumber.wants_to_quit = true if s.failed?
|
14
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require 'base64'
|
20
|
+
require 'digest'
|
21
|
+
require 'net/https'
|
22
|
+
|
23
|
+
module Kitchen
|
24
|
+
|
25
|
+
# Command string generator to interface with Kitchen Busser (kb). The
|
26
|
+
# commands that are generated are safe to pass to an SSH command or as an
|
27
|
+
# unix command argument (escaped in single quotes).
|
28
|
+
#
|
29
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
30
|
+
class Busser
|
31
|
+
|
32
|
+
# Constructs a new busser command generator, given a suite name.
|
33
|
+
#
|
34
|
+
# @param [String] suite_name name of suite on which to operate
|
35
|
+
# (**Required**)
|
36
|
+
# @param [Hash] opts optional configuration
|
37
|
+
# @option opts [TrueClass, FalseClass] :use_sudo whether or not to invoke
|
38
|
+
# sudo before commands requiring root access (default: `true`)
|
39
|
+
def initialize(suite_name, opts = { :use_sudo => true })
|
40
|
+
validate_options(suite_name)
|
41
|
+
|
42
|
+
@suite_name = suite_name
|
43
|
+
@use_sudo = opts[:use_sudo]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns a command string which installs the Kitchen Busser (kb), installs
|
47
|
+
# all required kb plugins for the suite.
|
48
|
+
#
|
49
|
+
# If no work needs to be performed, for example if there are no tests for
|
50
|
+
# the given suite, then `nil` will be returned.
|
51
|
+
#
|
52
|
+
# @return [String] a command string to setup the test suite, or nil if no
|
53
|
+
# work needs to be performed
|
54
|
+
def setup_cmd
|
55
|
+
@setup_cmd ||= if local_suite_files.empty?
|
56
|
+
nil
|
57
|
+
else
|
58
|
+
<<-INSTALL_CMD.gsub(/^ {10}/, '')
|
59
|
+
#{sudo}#{ruby_bin} -e "$(cat <<"EOF"
|
60
|
+
#{install_script}
|
61
|
+
EOF
|
62
|
+
)"
|
63
|
+
#{sudo}#{kb_bin} install #{plugins.join(' ')}
|
64
|
+
INSTALL_CMD
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns a command string which transfers all suite test files to the
|
69
|
+
# instance.
|
70
|
+
#
|
71
|
+
# If no work needs to be performed, for example if there are no tests for
|
72
|
+
# the given suite, then `nil` will be returned.
|
73
|
+
#
|
74
|
+
# @return [String] a command string to transfer all suite test files, or
|
75
|
+
# nil if no work needs to be performed.
|
76
|
+
def sync_cmd
|
77
|
+
@sync_cmd ||= if local_suite_files.empty?
|
78
|
+
nil
|
79
|
+
else
|
80
|
+
<<-INSTALL_CMD.gsub(/^ {10}/, '')
|
81
|
+
#{sudo}#{kb_bin} cleanup-suites
|
82
|
+
#{local_suite_files.map { |f| stream_file(f, remote_file(f)) }.join}
|
83
|
+
INSTALL_CMD
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns a command string which runs all kb suite tests for the suite.
|
88
|
+
#
|
89
|
+
# If no work needs to be performed, for example if there are no tests for
|
90
|
+
# the given suite, then `nil` will be returned.
|
91
|
+
#
|
92
|
+
# @return [String] a command string to run the test suites, or nil if no
|
93
|
+
# work needs to be performed
|
94
|
+
def run_cmd
|
95
|
+
@run_cmd ||= local_suite_files.empty? ? nil : "#{sudo}#{kb_bin} test"
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
INSTALL_URL = "https://raw.github.com/opscode/kb/go".freeze
|
101
|
+
DEFAULT_RUBY_BINPATH = "/opt/chef/embedded/bin".freeze
|
102
|
+
DEFAULT_KB_ROOT = "/opt/kb".freeze
|
103
|
+
DEFAULT_TEST_ROOT = File.join(Dir.pwd, "test/integration").freeze
|
104
|
+
|
105
|
+
def validate_options(suite_name)
|
106
|
+
raise ClientError, "Busser#new requires a suite_name" if suite_name.nil?
|
107
|
+
end
|
108
|
+
|
109
|
+
def install_script
|
110
|
+
@install_script ||= begin
|
111
|
+
uri = URI.parse(INSTALL_URL)
|
112
|
+
http = Net::HTTP.new(uri.host, 443)
|
113
|
+
http.use_ssl = true
|
114
|
+
response = http.request(Net::HTTP::Get.new(uri.path))
|
115
|
+
response.body
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def plugins
|
120
|
+
Dir.glob(File.join(test_root, @suite_name, "*")).select { |d|
|
121
|
+
File.directory?(d) && File.basename(d) != "data_bags"
|
122
|
+
}.map { |d| File.basename(d) }.sort.uniq
|
123
|
+
end
|
124
|
+
|
125
|
+
def local_suite_files
|
126
|
+
Dir.glob(File.join(test_root, @suite_name, "*/**/*")).reject do |f|
|
127
|
+
f["data_bags"] || File.directory?(f)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def remote_file(file)
|
132
|
+
local_prefix = File.join(test_root, @suite_name)
|
133
|
+
"$(#{kb_bin} suitepath)/".concat(file.sub(%r{^#{local_prefix}/}, ''))
|
134
|
+
end
|
135
|
+
|
136
|
+
def stream_file(local_path, remote_path)
|
137
|
+
local_file = IO.read(local_path)
|
138
|
+
md5 = Digest::MD5.hexdigest(local_file)
|
139
|
+
perms = sprintf("%o", File.stat(local_path).mode)[3, 3]
|
140
|
+
kb_stream_file = "#{kb_bin} stream-file #{remote_path} #{md5} #{perms}"
|
141
|
+
|
142
|
+
<<-STREAMFILE.gsub(/^ {8}/, '')
|
143
|
+
echo "Uploading #{remote_path} (mode=#{perms})"
|
144
|
+
cat <<"__EOFSTREAM__" | #{sudo}#{kb_stream_file}
|
145
|
+
#{Base64.encode64(local_file)}
|
146
|
+
__EOFSTREAM__
|
147
|
+
STREAMFILE
|
148
|
+
end
|
149
|
+
|
150
|
+
def sudo
|
151
|
+
@use_sudo ? "sudo " : ""
|
152
|
+
end
|
153
|
+
|
154
|
+
def ruby_bin
|
155
|
+
File.join(DEFAULT_RUBY_BINPATH, "ruby")
|
156
|
+
end
|
157
|
+
|
158
|
+
def kb_bin
|
159
|
+
File.join(DEFAULT_KB_ROOT, "bin/kb")
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_root
|
163
|
+
DEFAULT_TEST_ROOT
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|