test-kitchen 1.7.0 → 1.7.1.dev

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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +8 -8
  3. data/.gitattributes +3 -0
  4. data/.github/ISSUE_TEMPLATE.md +55 -55
  5. data/.gitignore +28 -28
  6. data/.kitchen.ci.yml +23 -23
  7. data/.kitchen.proxy.yml +27 -27
  8. data/.rubocop.yml +3 -3
  9. data/.travis.yml +70 -70
  10. data/.yardopts +3 -3
  11. data/Berksfile +3 -3
  12. data/CHANGELOG.md +1090 -1083
  13. data/CONTRIBUTING.md +14 -14
  14. data/Gemfile +19 -19
  15. data/Gemfile.proxy_tests +4 -4
  16. data/Guardfile +42 -42
  17. data/LICENSE +15 -15
  18. data/MAINTAINERS.md +23 -23
  19. data/README.md +135 -135
  20. data/Rakefile +61 -61
  21. data/appveyor.yml +44 -44
  22. data/features/kitchen_action_commands.feature +164 -164
  23. data/features/kitchen_command.feature +16 -16
  24. data/features/kitchen_console_command.feature +34 -34
  25. data/features/kitchen_defaults.feature +38 -38
  26. data/features/kitchen_diagnose_command.feature +96 -96
  27. data/features/kitchen_driver_create_command.feature +64 -64
  28. data/features/kitchen_driver_discover_command.feature +25 -25
  29. data/features/kitchen_help_command.feature +16 -16
  30. data/features/kitchen_init_command.feature +274 -274
  31. data/features/kitchen_list_command.feature +104 -104
  32. data/features/kitchen_login_command.feature +62 -62
  33. data/features/kitchen_sink_command.feature +30 -30
  34. data/features/kitchen_test_command.feature +88 -88
  35. data/features/step_definitions/gem_steps.rb +36 -36
  36. data/features/step_definitions/git_steps.rb +5 -5
  37. data/features/step_definitions/output_steps.rb +5 -5
  38. data/features/support/env.rb +75 -75
  39. data/lib/kitchen.rb +150 -150
  40. data/lib/kitchen/base64_stream.rb +55 -55
  41. data/lib/kitchen/cli.rb +419 -419
  42. data/lib/kitchen/collection.rb +55 -55
  43. data/lib/kitchen/color.rb +65 -65
  44. data/lib/kitchen/command.rb +185 -185
  45. data/lib/kitchen/command/action.rb +45 -45
  46. data/lib/kitchen/command/console.rb +58 -58
  47. data/lib/kitchen/command/diagnose.rb +92 -92
  48. data/lib/kitchen/command/driver_discover.rb +105 -105
  49. data/lib/kitchen/command/exec.rb +41 -41
  50. data/lib/kitchen/command/list.rb +119 -119
  51. data/lib/kitchen/command/login.rb +43 -43
  52. data/lib/kitchen/command/sink.rb +54 -54
  53. data/lib/kitchen/command/test.rb +51 -51
  54. data/lib/kitchen/config.rb +322 -322
  55. data/lib/kitchen/configurable.rb +529 -529
  56. data/lib/kitchen/data_munger.rb +959 -959
  57. data/lib/kitchen/diagnostic.rb +141 -141
  58. data/lib/kitchen/driver.rb +56 -56
  59. data/lib/kitchen/driver/base.rb +134 -134
  60. data/lib/kitchen/driver/dummy.rb +108 -108
  61. data/lib/kitchen/driver/proxy.rb +72 -72
  62. data/lib/kitchen/driver/ssh_base.rb +357 -357
  63. data/lib/kitchen/errors.rb +229 -229
  64. data/lib/kitchen/generator/driver_create.rb +177 -177
  65. data/lib/kitchen/generator/init.rb +296 -296
  66. data/lib/kitchen/instance.rb +662 -662
  67. data/lib/kitchen/lazy_hash.rb +142 -142
  68. data/lib/kitchen/loader/yaml.rb +349 -349
  69. data/lib/kitchen/logger.rb +423 -423
  70. data/lib/kitchen/logging.rb +56 -56
  71. data/lib/kitchen/login_command.rb +52 -52
  72. data/lib/kitchen/metadata_chopper.rb +52 -52
  73. data/lib/kitchen/platform.rb +67 -67
  74. data/lib/kitchen/provisioner.rb +54 -54
  75. data/lib/kitchen/provisioner/base.rb +236 -236
  76. data/lib/kitchen/provisioner/chef/berkshelf.rb +114 -114
  77. data/lib/kitchen/provisioner/chef/common_sandbox.rb +322 -322
  78. data/lib/kitchen/provisioner/chef/librarian.rb +112 -112
  79. data/lib/kitchen/provisioner/chef_apply.rb +124 -124
  80. data/lib/kitchen/provisioner/chef_base.rb +341 -341
  81. data/lib/kitchen/provisioner/chef_solo.rb +88 -88
  82. data/lib/kitchen/provisioner/chef_zero.rb +245 -245
  83. data/lib/kitchen/provisioner/dummy.rb +79 -79
  84. data/lib/kitchen/provisioner/shell.rb +138 -138
  85. data/lib/kitchen/rake_tasks.rb +63 -63
  86. data/lib/kitchen/shell_out.rb +93 -93
  87. data/lib/kitchen/ssh.rb +276 -276
  88. data/lib/kitchen/state_file.rb +120 -120
  89. data/lib/kitchen/suite.rb +51 -51
  90. data/lib/kitchen/thor_tasks.rb +66 -66
  91. data/lib/kitchen/transport.rb +54 -54
  92. data/lib/kitchen/transport/base.rb +176 -176
  93. data/lib/kitchen/transport/dummy.rb +79 -79
  94. data/lib/kitchen/transport/ssh.rb +364 -364
  95. data/lib/kitchen/transport/winrm.rb +486 -486
  96. data/lib/kitchen/util.rb +147 -147
  97. data/lib/kitchen/verifier.rb +55 -55
  98. data/lib/kitchen/verifier/base.rb +235 -235
  99. data/lib/kitchen/verifier/busser.rb +277 -277
  100. data/lib/kitchen/verifier/dummy.rb +79 -79
  101. data/lib/kitchen/verifier/shell.rb +101 -101
  102. data/lib/kitchen/version.rb +21 -21
  103. data/lib/vendor/hash_recursive_merge.rb +82 -82
  104. data/spec/kitchen/base64_stream_spec.rb +77 -77
  105. data/spec/kitchen/cli_spec.rb +56 -56
  106. data/spec/kitchen/collection_spec.rb +80 -80
  107. data/spec/kitchen/color_spec.rb +54 -54
  108. data/spec/kitchen/config_spec.rb +408 -408
  109. data/spec/kitchen/configurable_spec.rb +1095 -1095
  110. data/spec/kitchen/data_munger_spec.rb +2694 -2694
  111. data/spec/kitchen/diagnostic_spec.rb +129 -129
  112. data/spec/kitchen/driver/base_spec.rb +121 -121
  113. data/spec/kitchen/driver/dummy_spec.rb +199 -199
  114. data/spec/kitchen/driver/proxy_spec.rb +138 -138
  115. data/spec/kitchen/driver/ssh_base_spec.rb +1115 -1115
  116. data/spec/kitchen/driver_spec.rb +112 -112
  117. data/spec/kitchen/errors_spec.rb +309 -309
  118. data/spec/kitchen/instance_spec.rb +1419 -1419
  119. data/spec/kitchen/lazy_hash_spec.rb +117 -117
  120. data/spec/kitchen/loader/yaml_spec.rb +774 -774
  121. data/spec/kitchen/logger_spec.rb +429 -429
  122. data/spec/kitchen/logging_spec.rb +59 -59
  123. data/spec/kitchen/login_command_spec.rb +68 -68
  124. data/spec/kitchen/metadata_chopper_spec.rb +82 -82
  125. data/spec/kitchen/platform_spec.rb +89 -89
  126. data/spec/kitchen/provisioner/base_spec.rb +386 -386
  127. data/spec/kitchen/provisioner/chef_apply_spec.rb +136 -136
  128. data/spec/kitchen/provisioner/chef_base_spec.rb +1161 -1161
  129. data/spec/kitchen/provisioner/chef_solo_spec.rb +557 -557
  130. data/spec/kitchen/provisioner/chef_zero_spec.rb +1001 -1001
  131. data/spec/kitchen/provisioner/dummy_spec.rb +99 -99
  132. data/spec/kitchen/provisioner/shell_spec.rb +566 -566
  133. data/spec/kitchen/provisioner_spec.rb +107 -107
  134. data/spec/kitchen/shell_out_spec.rb +150 -150
  135. data/spec/kitchen/ssh_spec.rb +693 -693
  136. data/spec/kitchen/state_file_spec.rb +129 -129
  137. data/spec/kitchen/suite_spec.rb +62 -62
  138. data/spec/kitchen/transport/base_spec.rb +89 -89
  139. data/spec/kitchen/transport/ssh_spec.rb +1255 -1255
  140. data/spec/kitchen/transport/winrm_spec.rb +1143 -1143
  141. data/spec/kitchen/transport_spec.rb +112 -112
  142. data/spec/kitchen/util_spec.rb +165 -165
  143. data/spec/kitchen/verifier/base_spec.rb +362 -362
  144. data/spec/kitchen/verifier/busser_spec.rb +610 -610
  145. data/spec/kitchen/verifier/dummy_spec.rb +99 -99
  146. data/spec/kitchen/verifier/shell_spec.rb +160 -160
  147. data/spec/kitchen/verifier_spec.rb +120 -120
  148. data/spec/kitchen_spec.rb +114 -114
  149. data/spec/spec_helper.rb +85 -85
  150. data/spec/support/powershell_max_size_spec.rb +40 -40
  151. data/support/busser_install_command.ps1 +14 -14
  152. data/support/busser_install_command.sh +14 -14
  153. data/support/chef-client-zero.rb +77 -77
  154. data/support/chef_base_init_command.ps1 +18 -18
  155. data/support/chef_base_init_command.sh +2 -2
  156. data/support/chef_base_install_command.ps1 +85 -85
  157. data/support/chef_base_install_command.sh +229 -229
  158. data/support/chef_zero_prepare_command_legacy.ps1 +9 -9
  159. data/support/chef_zero_prepare_command_legacy.sh +10 -10
  160. data/support/download_helpers.sh +109 -109
  161. data/support/dummy-validation.pem +27 -27
  162. data/templates/driver/CHANGELOG.md.erb +3 -3
  163. data/templates/driver/Gemfile.erb +3 -3
  164. data/templates/driver/README.md.erb +64 -64
  165. data/templates/driver/Rakefile.erb +21 -21
  166. data/templates/driver/driver.rb.erb +23 -23
  167. data/templates/driver/gemspec.erb +29 -29
  168. data/templates/driver/gitignore.erb +17 -17
  169. data/templates/driver/license_apachev2.erb +15 -15
  170. data/templates/driver/license_lgplv3.erb +16 -16
  171. data/templates/driver/license_mit.erb +22 -22
  172. data/templates/driver/license_reserved.erb +5 -5
  173. data/templates/driver/tailor.erb +4 -4
  174. data/templates/driver/travis.yml.erb +11 -11
  175. data/templates/driver/version.rb.erb +12 -12
  176. data/templates/init/chefignore.erb +1 -1
  177. data/templates/init/kitchen.yml.erb +18 -18
  178. data/test-kitchen.gemspec +62 -62
  179. data/test/integration/default/default_spec.rb +3 -3
  180. data/testing_windows.md +37 -37
  181. metadata +5 -4
@@ -1,51 +1,51 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
- #
5
- # Copyright (C) 2013, 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 "kitchen/command"
20
-
21
- require "benchmark"
22
-
23
- module Kitchen
24
-
25
- module Command
26
-
27
- # Command to test one or more instances.
28
- #
29
- # @author Fletcher Nichol <fnichol@nichol.ca>
30
- class Test < Kitchen::Command::Base
31
-
32
- include RunAction
33
-
34
- # Invoke the command.
35
- def call
36
- if !%w[passing always never].include?(options[:destroy])
37
- raise ArgumentError, "Destroy mode must be passing, always, or never."
38
- end
39
-
40
- banner "Starting Kitchen (v#{Kitchen::VERSION})"
41
- elapsed = Benchmark.measure do
42
- destroy_mode = options[:destroy].to_sym
43
- results = parse_subcommand(args.join("|"))
44
-
45
- run_action(:test, results, destroy_mode)
46
- end
47
- banner "Kitchen is finished. #{Util.duration(elapsed.real)}"
48
- end
49
- end
50
- end
51
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2013, 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 "kitchen/command"
20
+
21
+ require "benchmark"
22
+
23
+ module Kitchen
24
+
25
+ module Command
26
+
27
+ # Command to test one or more instances.
28
+ #
29
+ # @author Fletcher Nichol <fnichol@nichol.ca>
30
+ class Test < Kitchen::Command::Base
31
+
32
+ include RunAction
33
+
34
+ # Invoke the command.
35
+ def call
36
+ if !%w[passing always never].include?(options[:destroy])
37
+ raise ArgumentError, "Destroy mode must be passing, always, or never."
38
+ end
39
+
40
+ banner "Starting Kitchen (v#{Kitchen::VERSION})"
41
+ elapsed = Benchmark.measure do
42
+ destroy_mode = options[:destroy].to_sym
43
+ results = parse_subcommand(args.join("|"))
44
+
45
+ run_action(:test, results, destroy_mode)
46
+ end
47
+ banner "Kitchen is finished. #{Util.duration(elapsed.real)}"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,322 +1,322 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
- #
5
- # Copyright (C) 2012, 2013, 2014, 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
- module Kitchen
20
-
21
- # Base configuration class for Kitchen. This class exposes configuration such
22
- # as the location of the Kitchen config file, instances, log_levels, etc.
23
- # This object is a factory object, meaning that it is responsible for
24
- # consuming the desired testing configuration in and returning Ruby objects
25
- # which are used to perfom the work.
26
- #
27
- # Most internal objects are created with the expectation of being
28
- # *immutable*, meaning that internal state cannot be modified after creation.
29
- # Any data manipulation or thread-unsafe activity is performed in this object
30
- # so that the subsequently created objects (such as Instances, Platforms,
31
- # Drivers, etc.) can safely run in concurrent threads of execution. To
32
- # prevent the re-creation of duplicate objects, most created objects are
33
- # memoized. The consequence of this is that once the Instance Array has
34
- # been requested (with the `#instances` message), you will always be returned
35
- # the same Instance objects.
36
- #
37
- # @example fetching all instances
38
- #
39
- # Kitchen::Config.new.instances
40
- #
41
- # @example fetching an instance by name
42
- #
43
- # Kitchen::Config.new.instances.get("default-ubuntu-12.04")
44
- #
45
- # @example fetching all instances matching a regular expression
46
- #
47
- # Kitchen::Config.new.instances.get_all(/ubuntu/)
48
- #
49
- # @author Fletcher Nichol <fnichol@nichol.ca>
50
- class Config
51
-
52
- # @return [String] the absolute path to the root of a Test Kitchen project
53
- # @api private
54
- attr_reader :kitchen_root
55
-
56
- # @return [String] the absolute path to the directory into which all Test
57
- # Kitchen log files will be written
58
- # @api private
59
- attr_reader :log_root
60
-
61
- # @return [String] the absolute path to the directory containing test
62
- # suites and other testing-related file and directories
63
- # @api private
64
- attr_reader :test_base_path
65
-
66
- # @return [#read] the data loader that responds to a `#read` message,
67
- # returning a Hash data structure
68
- # @api private
69
- attr_reader :loader
70
-
71
- # @return [Symbol] the logging verbosity level
72
- # @api private
73
- attr_accessor :log_level
74
-
75
- # @return [Boolean] whether to overwrite the log file when
76
- # Test Kitchen runs
77
- # @api private
78
- attr_accessor :log_overwrite
79
-
80
- # @return [String] an absolute path to the directory containing test suites
81
- # @api private
82
- attr_accessor :test_base_path
83
-
84
- # Creates a new configuration, representing a particular testing
85
- # configuration for a project.
86
- #
87
- # @param [Hash] options configuration
88
- # @option options [#read] :loader an object that responds to `#read` with
89
- # a Hash structure suitable for manipulating
90
- # (default: `Kitchen::Loader::YAML.new`)
91
- # @option options [String] :kitchen_root an absolute path to the root of a
92
- # Test Kitchen project, usually containing a `.kitchen.yml` file
93
- # (default `Dir.pwd`)
94
- # @option options [String] :log_root an absolute path to the directory
95
- # into which all Test Kitchen log files will be written
96
- # (default: `"#{kitchen_root}/.kitchen/logs"`)
97
- # @option options [String] :test_base_path an absolute path to the
98
- # directory containing test suites and other testing-related files and
99
- # directories (default: `"#{kitchen_root}/test/integration"`)
100
- # @option options [Symbol] :log_level the log level verbosity that the
101
- # loggers will use when outputing information (default: `:info`)
102
- def initialize(options = {})
103
- @loader = options.fetch(:loader) { Kitchen::Loader::YAML.new }
104
- @kitchen_root = options.fetch(:kitchen_root) { Dir.pwd }
105
- @log_level = options.fetch(:log_level) { Kitchen::DEFAULT_LOG_LEVEL }
106
- @log_overwrite = options.fetch(:log_overwrite) { Kitchen::DEFAULT_LOG_OVERWRITE }
107
- @log_root = options.fetch(:log_root) { default_log_root }
108
- @test_base_path = options.fetch(:test_base_path) { default_test_base_path }
109
- end
110
-
111
- # @return [Collection<Instance>] all instances, resulting from all
112
- # platform and suite combinations
113
- def instances
114
- @instances ||= Collection.new(build_instances)
115
- end
116
-
117
- # @return [Collection<Platform>] all defined platforms which will be used
118
- # in convergence integration
119
- def platforms
120
- @platforms ||= Collection.new(
121
- data.platform_data.map { |pdata| Platform.new(pdata) })
122
- end
123
-
124
- # @return [Collection<Suite>] all defined suites which will be used in
125
- # convergence integration
126
- def suites
127
- @suites ||= Collection.new(
128
- data.suite_data.map { |sdata| Suite.new(sdata) })
129
- end
130
-
131
- private
132
-
133
- # Builds the filtered list of Instance objects.
134
- #
135
- # @return [Array<Instance] an array of Instances
136
- # @api private
137
- def build_instances
138
- filter_instances.map.with_index do |(suite, platform), index|
139
- new_instance(suite, platform, index)
140
- end
141
- end
142
-
143
- # Returns an object which can generate configuration hashes for all the
144
- # primary Test Kitchen objects such as Drivers, Provisioners, etc.
145
- #
146
- # @return [DataMunger] a data manipulator
147
- # @api private
148
- def data
149
- @data ||= DataMunger.new(loader.read, kitchen_config)
150
- end
151
-
152
- # Determines the default absolute path to a log directory, based on the
153
- # value of `#kitchen_root`.
154
- #
155
- # @return [String] an absolute path to the log directory
156
- # @api private
157
- def default_log_root
158
- File.join(kitchen_root, Kitchen::DEFAULT_LOG_DIR)
159
- end
160
-
161
- # Determines the default absolute path to the testing files directory,
162
- # based on the the value of `#kitchen_root`.
163
- #
164
- # @return [String] an absolute path to the testing files directory
165
- # @api private
166
- def default_test_base_path
167
- File.join(kitchen_root, Kitchen::DEFAULT_TEST_DIR)
168
- end
169
-
170
- # Generates a filtered Array of tuples (Suite/Platform pairs) which is the
171
- # cartesian product of suites and platforms. A Suite has two optional
172
- # arrays (`#includes` and `#excludes`) which can be used to drop or
173
- # select certain Platforms with which to join.
174
- #
175
- # @return [Array<Array<Suite, Platform>>] an Array of Suite/Platform
176
- # tuples
177
- # @api private
178
- def filter_instances
179
- suites.product(platforms).select do |suite, platform|
180
- if !suite.includes.empty?
181
- suite.includes.include?(platform.name)
182
- elsif !suite.excludes.empty?
183
- !suite.excludes.include?(platform.name)
184
- else
185
- true
186
- end
187
- end
188
- end
189
-
190
- # Determines the String name for an Instance, given a Suite and a Platform.
191
- #
192
- # @param suite [Suite,#name] a Suite
193
- # @param platform [Platform,#name] a Platform
194
- # @return [String] an Instance name
195
- # @api private
196
- def instance_name(suite, platform)
197
- Instance.name_for(suite, platform)
198
- end
199
-
200
- # Generates the immutable Test Kitchen configuration and reasonable
201
- # defaults for Drivers, Provisioners and Transports.
202
- #
203
- # @return [Hash] a configuration Hash
204
- # @api private
205
- def kitchen_config
206
- @kitchen_config ||= {
207
- :defaults => {
208
- :driver => Driver::DEFAULT_PLUGIN,
209
- :provisioner => Provisioner::DEFAULT_PLUGIN,
210
- :verifier => Verifier::DEFAULT_PLUGIN,
211
- :transport => lambda { |_suite, platform|
212
- platform =~ /^win/i ? "winrm" : Transport::DEFAULT_PLUGIN
213
- }
214
- },
215
- :kitchen_root => kitchen_root,
216
- :test_base_path => test_base_path,
217
- :log_level => log_level,
218
- :log_overwrite => log_overwrite
219
- }
220
- end
221
-
222
- # Builds a newly configured Driver object, for a given Suite and Platform.
223
- #
224
- # @param suite [Suite,#name] a Suite
225
- # @param platform [Platform,#name] a Platform
226
- # @return [Driver] a new Driver object
227
- # @api private
228
- def new_driver(suite, platform)
229
- ddata = data.driver_data_for(suite.name, platform.name)
230
- Driver.for_plugin(ddata[:name], ddata)
231
- end
232
-
233
- # Builds a newly configured Instance object, for a given Suite and
234
- # Platform.
235
- #
236
- # @param suite [Suite,#name] a Suite
237
- # @param platform [Platform,#name] a Platform
238
- # @param index [Integer] an index used for colorizing output
239
- # @return [Instance] a new Instance object
240
- # @api private
241
- def new_instance(suite, platform, index)
242
- Instance.new(
243
- :driver => new_driver(suite, platform),
244
- :logger => new_instance_logger(suite, platform, index),
245
- :suite => suite,
246
- :platform => platform,
247
- :provisioner => new_provisioner(suite, platform),
248
- :transport => new_transport(suite, platform),
249
- :verifier => new_verifier(suite, platform),
250
- :state_file => new_state_file(suite, platform)
251
- )
252
- end
253
-
254
- # Builds a newly configured Logger object, for a given Suite and
255
- # Platform.
256
- #
257
- # @param suite [Suite,#name] a Suite
258
- # @param platform [Platform,#name] a Platform
259
- # @param index [Integer] an index used for colorizing output
260
- # @return [Logger] a new Logger object
261
- # @api private
262
- def new_instance_logger(suite, platform, index)
263
- name = instance_name(suite, platform)
264
- log_location = File.join(log_root, "#{name}.log").to_s
265
- Logger.new(
266
- :stdout => STDOUT,
267
- :color => Color::COLORS[index % Color::COLORS.size].to_sym,
268
- :logdev => log_location,
269
- :level => Util.to_logger_level(log_level),
270
- :log_overwrite => log_overwrite,
271
- :progname => name
272
- )
273
- end
274
-
275
- # Builds a newly configured Provisioner object, for a given Suite and
276
- # Platform.
277
- #
278
- # @param suite [Suite,#name] a Suite
279
- # @param platform [Platform,#name] a Platform
280
- # @return [Provisioner] a new Provisioner object
281
- # @api private
282
- def new_provisioner(suite, platform)
283
- pdata = data.provisioner_data_for(suite.name, platform.name)
284
- Provisioner.for_plugin(pdata[:name], pdata)
285
- end
286
-
287
- # Builds a newly configured StateFile object, for a given Suite and
288
- # Platform.
289
- #
290
- # @param suite [Suite,#name] a Suite
291
- # @param platform [Platform,#name] a Platform
292
- # @return [StateFile] a new StateFile object
293
- # @api private
294
- def new_state_file(suite, platform)
295
- StateFile.new(kitchen_root, instance_name(suite, platform))
296
- end
297
-
298
- # Builds a newly configured Transport object, for a given Suite and
299
- # Platform.
300
- #
301
- # @param suite [Suite,#name] a Suite
302
- # @param platform [Platform,#name] a Platform
303
- # @return [Transport] a new Transport object
304
- # @api private
305
- def new_transport(suite, platform)
306
- tdata = data.transport_data_for(suite.name, platform.name)
307
- Transport.for_plugin(tdata[:name], tdata)
308
- end
309
-
310
- # Builds a newly configured Verifier object, for a given a Suite and
311
- # Platform.
312
- #
313
- # @param suite [Suite,#name] a Suite
314
- # @param platform [Platform,#name] a Platform
315
- # @return [Verifier] a new Verifier object
316
- # @api private
317
- def new_verifier(suite, platform)
318
- vdata = data.verifier_data_for(suite.name, platform.name)
319
- Verifier.for_plugin(vdata[:name], vdata)
320
- end
321
- end
322
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, 2013, 2014, 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
+ module Kitchen
20
+
21
+ # Base configuration class for Kitchen. This class exposes configuration such
22
+ # as the location of the Kitchen config file, instances, log_levels, etc.
23
+ # This object is a factory object, meaning that it is responsible for
24
+ # consuming the desired testing configuration in and returning Ruby objects
25
+ # which are used to perfom the work.
26
+ #
27
+ # Most internal objects are created with the expectation of being
28
+ # *immutable*, meaning that internal state cannot be modified after creation.
29
+ # Any data manipulation or thread-unsafe activity is performed in this object
30
+ # so that the subsequently created objects (such as Instances, Platforms,
31
+ # Drivers, etc.) can safely run in concurrent threads of execution. To
32
+ # prevent the re-creation of duplicate objects, most created objects are
33
+ # memoized. The consequence of this is that once the Instance Array has
34
+ # been requested (with the `#instances` message), you will always be returned
35
+ # the same Instance objects.
36
+ #
37
+ # @example fetching all instances
38
+ #
39
+ # Kitchen::Config.new.instances
40
+ #
41
+ # @example fetching an instance by name
42
+ #
43
+ # Kitchen::Config.new.instances.get("default-ubuntu-12.04")
44
+ #
45
+ # @example fetching all instances matching a regular expression
46
+ #
47
+ # Kitchen::Config.new.instances.get_all(/ubuntu/)
48
+ #
49
+ # @author Fletcher Nichol <fnichol@nichol.ca>
50
+ class Config
51
+
52
+ # @return [String] the absolute path to the root of a Test Kitchen project
53
+ # @api private
54
+ attr_reader :kitchen_root
55
+
56
+ # @return [String] the absolute path to the directory into which all Test
57
+ # Kitchen log files will be written
58
+ # @api private
59
+ attr_reader :log_root
60
+
61
+ # @return [String] the absolute path to the directory containing test
62
+ # suites and other testing-related file and directories
63
+ # @api private
64
+ attr_reader :test_base_path
65
+
66
+ # @return [#read] the data loader that responds to a `#read` message,
67
+ # returning a Hash data structure
68
+ # @api private
69
+ attr_reader :loader
70
+
71
+ # @return [Symbol] the logging verbosity level
72
+ # @api private
73
+ attr_accessor :log_level
74
+
75
+ # @return [Boolean] whether to overwrite the log file when
76
+ # Test Kitchen runs
77
+ # @api private
78
+ attr_accessor :log_overwrite
79
+
80
+ # @return [String] an absolute path to the directory containing test suites
81
+ # @api private
82
+ attr_accessor :test_base_path
83
+
84
+ # Creates a new configuration, representing a particular testing
85
+ # configuration for a project.
86
+ #
87
+ # @param [Hash] options configuration
88
+ # @option options [#read] :loader an object that responds to `#read` with
89
+ # a Hash structure suitable for manipulating
90
+ # (default: `Kitchen::Loader::YAML.new`)
91
+ # @option options [String] :kitchen_root an absolute path to the root of a
92
+ # Test Kitchen project, usually containing a `.kitchen.yml` file
93
+ # (default `Dir.pwd`)
94
+ # @option options [String] :log_root an absolute path to the directory
95
+ # into which all Test Kitchen log files will be written
96
+ # (default: `"#{kitchen_root}/.kitchen/logs"`)
97
+ # @option options [String] :test_base_path an absolute path to the
98
+ # directory containing test suites and other testing-related files and
99
+ # directories (default: `"#{kitchen_root}/test/integration"`)
100
+ # @option options [Symbol] :log_level the log level verbosity that the
101
+ # loggers will use when outputing information (default: `:info`)
102
+ def initialize(options = {})
103
+ @loader = options.fetch(:loader) { Kitchen::Loader::YAML.new }
104
+ @kitchen_root = options.fetch(:kitchen_root) { Dir.pwd }
105
+ @log_level = options.fetch(:log_level) { Kitchen::DEFAULT_LOG_LEVEL }
106
+ @log_overwrite = options.fetch(:log_overwrite) { Kitchen::DEFAULT_LOG_OVERWRITE }
107
+ @log_root = options.fetch(:log_root) { default_log_root }
108
+ @test_base_path = options.fetch(:test_base_path) { default_test_base_path }
109
+ end
110
+
111
+ # @return [Collection<Instance>] all instances, resulting from all
112
+ # platform and suite combinations
113
+ def instances
114
+ @instances ||= Collection.new(build_instances)
115
+ end
116
+
117
+ # @return [Collection<Platform>] all defined platforms which will be used
118
+ # in convergence integration
119
+ def platforms
120
+ @platforms ||= Collection.new(
121
+ data.platform_data.map { |pdata| Platform.new(pdata) })
122
+ end
123
+
124
+ # @return [Collection<Suite>] all defined suites which will be used in
125
+ # convergence integration
126
+ def suites
127
+ @suites ||= Collection.new(
128
+ data.suite_data.map { |sdata| Suite.new(sdata) })
129
+ end
130
+
131
+ private
132
+
133
+ # Builds the filtered list of Instance objects.
134
+ #
135
+ # @return [Array<Instance] an array of Instances
136
+ # @api private
137
+ def build_instances
138
+ filter_instances.map.with_index do |(suite, platform), index|
139
+ new_instance(suite, platform, index)
140
+ end
141
+ end
142
+
143
+ # Returns an object which can generate configuration hashes for all the
144
+ # primary Test Kitchen objects such as Drivers, Provisioners, etc.
145
+ #
146
+ # @return [DataMunger] a data manipulator
147
+ # @api private
148
+ def data
149
+ @data ||= DataMunger.new(loader.read, kitchen_config)
150
+ end
151
+
152
+ # Determines the default absolute path to a log directory, based on the
153
+ # value of `#kitchen_root`.
154
+ #
155
+ # @return [String] an absolute path to the log directory
156
+ # @api private
157
+ def default_log_root
158
+ File.join(kitchen_root, Kitchen::DEFAULT_LOG_DIR)
159
+ end
160
+
161
+ # Determines the default absolute path to the testing files directory,
162
+ # based on the the value of `#kitchen_root`.
163
+ #
164
+ # @return [String] an absolute path to the testing files directory
165
+ # @api private
166
+ def default_test_base_path
167
+ File.join(kitchen_root, Kitchen::DEFAULT_TEST_DIR)
168
+ end
169
+
170
+ # Generates a filtered Array of tuples (Suite/Platform pairs) which is the
171
+ # cartesian product of suites and platforms. A Suite has two optional
172
+ # arrays (`#includes` and `#excludes`) which can be used to drop or
173
+ # select certain Platforms with which to join.
174
+ #
175
+ # @return [Array<Array<Suite, Platform>>] an Array of Suite/Platform
176
+ # tuples
177
+ # @api private
178
+ def filter_instances
179
+ suites.product(platforms).select do |suite, platform|
180
+ if !suite.includes.empty?
181
+ suite.includes.include?(platform.name)
182
+ elsif !suite.excludes.empty?
183
+ !suite.excludes.include?(platform.name)
184
+ else
185
+ true
186
+ end
187
+ end
188
+ end
189
+
190
+ # Determines the String name for an Instance, given a Suite and a Platform.
191
+ #
192
+ # @param suite [Suite,#name] a Suite
193
+ # @param platform [Platform,#name] a Platform
194
+ # @return [String] an Instance name
195
+ # @api private
196
+ def instance_name(suite, platform)
197
+ Instance.name_for(suite, platform)
198
+ end
199
+
200
+ # Generates the immutable Test Kitchen configuration and reasonable
201
+ # defaults for Drivers, Provisioners and Transports.
202
+ #
203
+ # @return [Hash] a configuration Hash
204
+ # @api private
205
+ def kitchen_config
206
+ @kitchen_config ||= {
207
+ :defaults => {
208
+ :driver => Driver::DEFAULT_PLUGIN,
209
+ :provisioner => Provisioner::DEFAULT_PLUGIN,
210
+ :verifier => Verifier::DEFAULT_PLUGIN,
211
+ :transport => lambda { |_suite, platform|
212
+ platform =~ /^win/i ? "winrm" : Transport::DEFAULT_PLUGIN
213
+ }
214
+ },
215
+ :kitchen_root => kitchen_root,
216
+ :test_base_path => test_base_path,
217
+ :log_level => log_level,
218
+ :log_overwrite => log_overwrite
219
+ }
220
+ end
221
+
222
+ # Builds a newly configured Driver object, for a given Suite and Platform.
223
+ #
224
+ # @param suite [Suite,#name] a Suite
225
+ # @param platform [Platform,#name] a Platform
226
+ # @return [Driver] a new Driver object
227
+ # @api private
228
+ def new_driver(suite, platform)
229
+ ddata = data.driver_data_for(suite.name, platform.name)
230
+ Driver.for_plugin(ddata[:name], ddata)
231
+ end
232
+
233
+ # Builds a newly configured Instance object, for a given Suite and
234
+ # Platform.
235
+ #
236
+ # @param suite [Suite,#name] a Suite
237
+ # @param platform [Platform,#name] a Platform
238
+ # @param index [Integer] an index used for colorizing output
239
+ # @return [Instance] a new Instance object
240
+ # @api private
241
+ def new_instance(suite, platform, index)
242
+ Instance.new(
243
+ :driver => new_driver(suite, platform),
244
+ :logger => new_instance_logger(suite, platform, index),
245
+ :suite => suite,
246
+ :platform => platform,
247
+ :provisioner => new_provisioner(suite, platform),
248
+ :transport => new_transport(suite, platform),
249
+ :verifier => new_verifier(suite, platform),
250
+ :state_file => new_state_file(suite, platform)
251
+ )
252
+ end
253
+
254
+ # Builds a newly configured Logger object, for a given Suite and
255
+ # Platform.
256
+ #
257
+ # @param suite [Suite,#name] a Suite
258
+ # @param platform [Platform,#name] a Platform
259
+ # @param index [Integer] an index used for colorizing output
260
+ # @return [Logger] a new Logger object
261
+ # @api private
262
+ def new_instance_logger(suite, platform, index)
263
+ name = instance_name(suite, platform)
264
+ log_location = File.join(log_root, "#{name}.log").to_s
265
+ Logger.new(
266
+ :stdout => STDOUT,
267
+ :color => Color::COLORS[index % Color::COLORS.size].to_sym,
268
+ :logdev => log_location,
269
+ :level => Util.to_logger_level(log_level),
270
+ :log_overwrite => log_overwrite,
271
+ :progname => name
272
+ )
273
+ end
274
+
275
+ # Builds a newly configured Provisioner object, for a given Suite and
276
+ # Platform.
277
+ #
278
+ # @param suite [Suite,#name] a Suite
279
+ # @param platform [Platform,#name] a Platform
280
+ # @return [Provisioner] a new Provisioner object
281
+ # @api private
282
+ def new_provisioner(suite, platform)
283
+ pdata = data.provisioner_data_for(suite.name, platform.name)
284
+ Provisioner.for_plugin(pdata[:name], pdata)
285
+ end
286
+
287
+ # Builds a newly configured StateFile object, for a given Suite and
288
+ # Platform.
289
+ #
290
+ # @param suite [Suite,#name] a Suite
291
+ # @param platform [Platform,#name] a Platform
292
+ # @return [StateFile] a new StateFile object
293
+ # @api private
294
+ def new_state_file(suite, platform)
295
+ StateFile.new(kitchen_root, instance_name(suite, platform))
296
+ end
297
+
298
+ # Builds a newly configured Transport object, for a given Suite and
299
+ # Platform.
300
+ #
301
+ # @param suite [Suite,#name] a Suite
302
+ # @param platform [Platform,#name] a Platform
303
+ # @return [Transport] a new Transport object
304
+ # @api private
305
+ def new_transport(suite, platform)
306
+ tdata = data.transport_data_for(suite.name, platform.name)
307
+ Transport.for_plugin(tdata[:name], tdata)
308
+ end
309
+
310
+ # Builds a newly configured Verifier object, for a given a Suite and
311
+ # Platform.
312
+ #
313
+ # @param suite [Suite,#name] a Suite
314
+ # @param platform [Platform,#name] a Platform
315
+ # @return [Verifier] a new Verifier object
316
+ # @api private
317
+ def new_verifier(suite, platform)
318
+ vdata = data.verifier_data_for(suite.name, platform.name)
319
+ Verifier.for_plugin(vdata[:name], vdata)
320
+ end
321
+ end
322
+ end