test-kitchen 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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