test-kitchen 0.5.0

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.
Files changed (37) hide show
  1. data/bin/kitchen +7 -0
  2. data/config/Cheffile +55 -0
  3. data/config/Kitchenfile +39 -0
  4. data/config/Vagrantfile +109 -0
  5. data/cookbooks/test-kitchen/attributes/default.rb +25 -0
  6. data/cookbooks/test-kitchen/libraries/helpers.rb +25 -0
  7. data/cookbooks/test-kitchen/metadata.rb +27 -0
  8. data/cookbooks/test-kitchen/recipes/chef.rb +19 -0
  9. data/cookbooks/test-kitchen/recipes/compat.rb +39 -0
  10. data/cookbooks/test-kitchen/recipes/default.rb +51 -0
  11. data/cookbooks/test-kitchen/recipes/erlang.rb +19 -0
  12. data/cookbooks/test-kitchen/recipes/ruby.rb +40 -0
  13. data/lib/test-kitchen.rb +34 -0
  14. data/lib/test-kitchen/cli.rb +267 -0
  15. data/lib/test-kitchen/cli/destroy.rb +42 -0
  16. data/lib/test-kitchen/cli/init.rb +37 -0
  17. data/lib/test-kitchen/cli/platform_list.rb +37 -0
  18. data/lib/test-kitchen/cli/project_info.rb +44 -0
  19. data/lib/test-kitchen/cli/ssh.rb +36 -0
  20. data/lib/test-kitchen/cli/status.rb +36 -0
  21. data/lib/test-kitchen/cli/test.rb +60 -0
  22. data/lib/test-kitchen/dsl.rb +59 -0
  23. data/lib/test-kitchen/environment.rb +164 -0
  24. data/lib/test-kitchen/platform.rb +63 -0
  25. data/lib/test-kitchen/project.rb +23 -0
  26. data/lib/test-kitchen/project/base.rb +159 -0
  27. data/lib/test-kitchen/project/cookbook.rb +87 -0
  28. data/lib/test-kitchen/project/cookbook_copy.rb +58 -0
  29. data/lib/test-kitchen/project/ruby.rb +37 -0
  30. data/lib/test-kitchen/project/supported_platforms.rb +75 -0
  31. data/lib/test-kitchen/runner.rb +20 -0
  32. data/lib/test-kitchen/runner/base.rb +144 -0
  33. data/lib/test-kitchen/runner/vagrant.rb +92 -0
  34. data/lib/test-kitchen/scaffold.rb +73 -0
  35. data/lib/test-kitchen/ui.rb +73 -0
  36. data/lib/test-kitchen/version.rb +21 -0
  37. metadata +196 -0
@@ -0,0 +1,34 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'ripper'
20
+ require 'test-kitchen/cli'
21
+ require 'test-kitchen/dsl'
22
+ require 'test-kitchen/project'
23
+ require 'test-kitchen/runner'
24
+ require 'test-kitchen/version'
25
+
26
+ module TestKitchen
27
+
28
+ # The source root is the path to the root directory of
29
+ # the test-kitchen gem.
30
+ def self.source_root
31
+ @source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
32
+ end
33
+
34
+ end
@@ -0,0 +1,267 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'test-kitchen/environment'
20
+ require 'test-kitchen/ui'
21
+ require 'mixlib/cli'
22
+
23
+ module TestKitchen
24
+ module CLI
25
+ class Kitchen
26
+ include Mixlib::CLI
27
+
28
+ option :platform,
29
+ :long => "--platform PLATFORM",
30
+ :description => "The platform to use. If not specified tests will be run against all platforms."
31
+
32
+ option :configuration,
33
+ :long => "--configuration CONFIG",
34
+ :description => "The project configuration to test. Defaults to all configurations."
35
+
36
+ option :runner,
37
+ :short => "-r RUNNER",
38
+ :long => "--runner RUNNER",
39
+ :description => "The underlying virtualization platform to test with."
40
+
41
+ option :teardown,
42
+ :boolean => true,
43
+ :default => false,
44
+ :long => "--teardown",
45
+ :description => "Teardown test nodes between runs."
46
+
47
+ option :help,
48
+ :short => "-h",
49
+ :long => "--help",
50
+ :description => "Show this message",
51
+ :on => :tail,
52
+ :boolean => true,
53
+ :show_options => true,
54
+ :exit => 0
55
+
56
+ attr_accessor :runner
57
+ attr_accessor :env
58
+ attr_accessor :ui
59
+
60
+ def command_help?
61
+ ARGV.last == '--help'
62
+ end
63
+
64
+ def scaffolding?
65
+ ARGV == ['init']
66
+ end
67
+
68
+ def run
69
+ validate_and_parse_options
70
+ quiet_traps
71
+ Kitchen.run(ARGV, options)
72
+ exit 0
73
+ end
74
+
75
+ def initialize(argv=[])
76
+ $stdout.sync = true
77
+ $stderr.sync = true
78
+ super()
79
+ parse_options(argv)
80
+ @ui = TestKitchen::UI.new(STDOUT, STDERR, STDIN, {})
81
+
82
+ # TODO: Move this out of the constructor
83
+ load_environment unless command_help? || scaffolding?
84
+ end
85
+
86
+ def load_environment
87
+ @env = TestKitchen::Environment.new(:ui => @ui).tap{|e| e.load!}
88
+ end
89
+
90
+ def runner
91
+ @runner ||= begin
92
+ # CLI option takes precedence, then project
93
+ runner_name = config[:runner] || env.project.runner || 'vagrant'
94
+ runner_class = TestKitchen::Runner.targets[runner_name]
95
+ runner = runner_class.new(env, config)
96
+ end
97
+ end
98
+
99
+ # Class Methods
100
+
101
+ def self.run(argv, options={})
102
+ load_commands
103
+ subcommand_class = Kitchen.subcommand_class_from(argv)
104
+ subcommand_class.options = options.merge!(subcommand_class.options)
105
+
106
+ instance = subcommand_class.new(ARGV)
107
+ instance.run
108
+ end
109
+
110
+ def self.load_commands
111
+ @commands_loaded ||= begin
112
+ if subcommand_files = Dir[File.join(TestKitchen.source_root, 'lib', 'test-kitchen', 'cli', '*.rb')]
113
+ subcommand_files.each { |subcommand| Kernel.load subcommand.to_s }
114
+ end
115
+ true
116
+ end
117
+ end
118
+
119
+ NO_COMMAND_GIVEN = "You need to pass a sub-command (e.g., kitchen SUB-COMMAND)\n"
120
+
121
+ # BEGIN CARGO CULT FROM Chef::Knife
122
+ def self.inherited(subclass)
123
+ unless subclass.unnamed?
124
+ subcommands[subclass.snake_case_name] = subclass
125
+ end
126
+ end
127
+
128
+ def self.subcommands
129
+ @@subcommands ||= {}
130
+ end
131
+
132
+ def self.subcommand_category
133
+ @category || snake_case_name.split('_').first unless unnamed?
134
+ end
135
+
136
+ def self.snake_case_name
137
+ convert_to_snake_case(name.split('::').last) unless unnamed?
138
+ end
139
+
140
+ def self.convert_to_snake_case(str, namespace=nil)
141
+ str = str.dup
142
+ str.sub!(/^#{namespace}(\:\:)?/, '') if namespace
143
+ str.gsub!(/[A-Z]/) {|s| "_" + s}
144
+ str.downcase!
145
+ str.sub!(/^\_/, "")
146
+ str
147
+ end
148
+
149
+ # Does this class have a name? (Classes created via Class.new don't)
150
+ def self.unnamed?
151
+ name.nil? || name.empty?
152
+ end
153
+
154
+ def self.subcommands_by_category
155
+ unless @subcommands_by_category
156
+ @subcommands_by_category = Hash.new { |hash, key| hash[key] = [] }
157
+ subcommands.each do |snake_cased, klass|
158
+ @subcommands_by_category[klass.subcommand_category] << snake_cased
159
+ end
160
+ end
161
+ @subcommands_by_category
162
+ end
163
+
164
+ # Print the list of subcommands knife knows about. If +preferred_category+
165
+ # is given, only subcommands in that category are shown
166
+ def self.list_commands(preferred_category=nil)
167
+ load_commands
168
+
169
+ category_desc = preferred_category ? preferred_category + " " : ''
170
+ $stdout.puts "Available #{category_desc}subcommands: (for details, kitchen SUB-COMMAND --help)\n\n"
171
+
172
+ if preferred_category && subcommands_by_category.key?(preferred_category)
173
+ commands_to_show = {preferred_category => subcommands_by_category[preferred_category]}
174
+ else
175
+ commands_to_show = subcommands_by_category
176
+ end
177
+
178
+ commands_to_show.sort.each do |category, commands|
179
+ next if category =~ /deprecated/i
180
+ $stdout.puts "** #{category.upcase} COMMANDS **"
181
+ commands.each do |command|
182
+ $stdout.puts subcommands[command].banner if subcommands[command]
183
+ end
184
+ $stdout.puts
185
+ end
186
+ end
187
+
188
+ def self.subcommand_class_from(args)
189
+ command_words = args.select {|arg| arg =~ /^(([[:alnum:]])[[:alnum:]\_\-]+)$/ }
190
+
191
+ subcommand_class = nil
192
+
193
+ while ( !subcommand_class ) && ( !command_words.empty? )
194
+ snake_case_class_name = command_words.join("_")
195
+ unless subcommand_class = subcommands[snake_case_class_name]
196
+ command_words.pop
197
+ end
198
+ end
199
+ # see if we got the command as e.g., knife node-list
200
+ subcommand_class ||= subcommands[args.first.gsub('-', '_')]
201
+ subcommand_class || subcommand_not_found!(args)
202
+ end
203
+
204
+ # :nodoc:
205
+ # Error out and print usage. probably becuase the arguments given by the
206
+ # user could not be resolved to a subcommand.
207
+ def self.subcommand_not_found!(args)
208
+ $stderr.puts "Cannot find sub command for: '#{args.join(' ')}'"
209
+ list_commands
210
+ exit 10
211
+ end
212
+ # END CARGO CULT FROM Chef::Knife
213
+
214
+ private
215
+
216
+ # BEGIN CARGO CULT FROM Chef::Application::Knife
217
+ def quiet_traps
218
+ trap("TERM") do
219
+ exit 1
220
+ end
221
+
222
+ trap("INT") do
223
+ exit 2
224
+ end
225
+ end
226
+
227
+ def validate_and_parse_options
228
+ # Checking ARGV validity *before* parse_options because parse_options
229
+ # mangles ARGV in some situations
230
+ if no_command_given?
231
+ print_help_and_exit(1, NO_COMMAND_GIVEN)
232
+ elsif no_subcommand_given?
233
+ if (want_help? || want_version?)
234
+ print_help_and_exit
235
+ else
236
+ print_help_and_exit(2, NO_COMMAND_GIVEN)
237
+ end
238
+ end
239
+ end
240
+
241
+ def no_subcommand_given?
242
+ ARGV[0] =~ /^-/
243
+ end
244
+
245
+ def no_command_given?
246
+ ARGV.empty?
247
+ end
248
+
249
+ def want_help?
250
+ ARGV[0] =~ /^(--help|-h)$/
251
+ end
252
+
253
+ def want_version?
254
+ ARGV[0] =~ /^(--version|-v)$/
255
+ end
256
+
257
+ def print_help_and_exit(exitcode=1, fatal_message=nil)
258
+ $stderr.puts(fatal_message) if fatal_message
259
+ puts self.opt_parser
260
+ puts
261
+ TestKitchen::CLI::Kitchen.list_commands
262
+ exit exitcode
263
+ end
264
+ # END CARGO CULT FROM Chef::Application::Knife
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,42 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'test-kitchen/cli'
20
+ require 'test-kitchen/runner'
21
+
22
+ module TestKitchen
23
+ module CLI
24
+ class Kitchen
25
+ class Destroy < Kitchen
26
+
27
+ banner "kitchen destroy (options)"
28
+
29
+ def run
30
+ options = {
31
+ :platform => config[:platform],
32
+ :configuration => config[:configuration]
33
+ }
34
+
35
+ runner = TestKitchen::Runner.targets['vagrant'].new(env, options)
36
+ runner.destroy
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'test-kitchen/cli'
20
+ require 'test-kitchen/scaffold'
21
+
22
+ module TestKitchen
23
+ module CLI
24
+ class Kitchen
25
+ class Init < Kitchen
26
+
27
+ banner "kitchen init"
28
+
29
+ def run
30
+ scaffold = TestKitchen::Scaffold.new
31
+ scaffold.generate(Dir.pwd)
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'test-kitchen/cli'
20
+
21
+ module TestKitchen
22
+ module CLI
23
+ class Kitchen
24
+ class PlatformList < Kitchen
25
+
26
+ banner "kitchen platform list (options)"
27
+
28
+ def run
29
+ env.platform_names.each do |platform|
30
+ ui.info " #{platform}"
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,44 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'test-kitchen/cli'
20
+
21
+ module TestKitchen
22
+ module CLI
23
+ class Kitchen
24
+ class ProjectInfo < Kitchen
25
+
26
+ banner "kitchen project info (options)"
27
+
28
+ def run
29
+ ui.info("Project: ", :green, :bold)
30
+ ui.info(" #{env.project.name}\n")
31
+ ui.info("Configurations: ", :yellow)
32
+ if env.project.configurations.any?
33
+ env.project.configurations.each_key do |config_name|
34
+ ui.info(" #{config_name}")
35
+ end
36
+ else
37
+ ui.info(" default")
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
44
+ end