test-kitchen 4.1.1 → 4.1.3

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/Rakefile +10 -0
  4. data/lib/kitchen/base64_stream.rb +2 -2
  5. data/lib/kitchen/cli.rb +60 -5
  6. data/lib/kitchen/color.rb +7 -0
  7. data/lib/kitchen/command/action.rb +1 -1
  8. data/lib/kitchen/command/diagnose.rb +1 -1
  9. data/lib/kitchen/command/login.rb +1 -1
  10. data/lib/kitchen/command/logs.rb +4 -0
  11. data/lib/kitchen/command/package.rb +1 -1
  12. data/lib/kitchen/command.rb +25 -2
  13. data/lib/kitchen/config.rb +5 -5
  14. data/lib/kitchen/configurable.rb +18 -5
  15. data/lib/kitchen/data_munger.rb +19 -0
  16. data/lib/kitchen/driver/base.rb +2 -2
  17. data/lib/kitchen/driver/dummy.rb +8 -2
  18. data/lib/kitchen/errors.rb +7 -1
  19. data/lib/kitchen/generator/init.rb +4 -0
  20. data/lib/kitchen/instance.rb +28 -11
  21. data/lib/kitchen/lazy_hash.rb +2 -2
  22. data/lib/kitchen/lifecycle_hook/base.rb +14 -4
  23. data/lib/kitchen/lifecycle_hook/local.rb +2 -0
  24. data/lib/kitchen/lifecycle_hook/remote.rb +3 -1
  25. data/lib/kitchen/loader/yaml.rb +8 -4
  26. data/lib/kitchen/logger.rb +141 -7
  27. data/lib/kitchen/logging.rb +1 -1
  28. data/lib/kitchen/login_command.rb +3 -0
  29. data/lib/kitchen/metadata_chopper.rb +8 -1
  30. data/lib/kitchen/platform_filter.rb +4 -4
  31. data/lib/kitchen/plugin.rb +4 -1
  32. data/lib/kitchen/plugin_base.rb +5 -0
  33. data/lib/kitchen/provisioner/base.rb +5 -5
  34. data/lib/kitchen/provisioner/dummy.rb +1 -1
  35. data/lib/kitchen/provisioner/external.rb +22 -0
  36. data/lib/kitchen/provisioner/shell.rb +1 -1
  37. data/lib/kitchen/provisioner.rb +1 -1
  38. data/lib/kitchen/shell_out.rb +2 -0
  39. data/lib/kitchen/state_file.rb +1 -1
  40. data/lib/kitchen/suite.rb +1 -1
  41. data/lib/kitchen/transport/base.rb +1 -1
  42. data/lib/kitchen/transport/dummy.rb +21 -3
  43. data/lib/kitchen/transport/exec.rb +1 -1
  44. data/lib/kitchen/transport/ssh.rb +13 -6
  45. data/lib/kitchen/transport/winrm.rb +13 -7
  46. data/lib/kitchen/util.rb +41 -6
  47. data/lib/kitchen/verifier/base.rb +5 -5
  48. data/lib/kitchen/verifier/busser.rb +3 -3
  49. data/lib/kitchen/verifier/shell.rb +1 -1
  50. data/lib/kitchen/version.rb +4 -1
  51. data/lib/kitchen/which.rb +2 -0
  52. data/lib/kitchen.rb +18 -6
  53. data/lib/vendor/hash_recursive_merge.rb +5 -0
  54. data/templates/driver/README.md.erb +1 -1
  55. data/test-kitchen.gemspec +2 -2
  56. metadata +2 -2
@@ -18,8 +18,8 @@
18
18
  module Kitchen
19
19
  # A wrapper on Regexp and strings to mix them in platform filters.
20
20
  #
21
- # This should handle backward compatibility in most cases were
22
- # platform are matched against a filters array using Array.include?
21
+ # This should handle backward compatibility in most cases where
22
+ # platforms are matched against a filter array using Array.include?
23
23
  #
24
24
  # This wrapper does not work if filters arrays are converted to Set.
25
25
  #
@@ -29,7 +29,7 @@ module Kitchen
29
29
  REGEXP_LIKE_PATTERN = %r{^/(?<pattern>.*)/(?<options>[ix]*)$}
30
30
 
31
31
  # Converts platform filters into an array of PlatformFilter handling both strings and Regexp.
32
- # A string "looks-like" a regexp if it starts by / and end by / + Regexp options i or x
32
+ # A string "looks-like" a regexp if it starts with / and ends with / + Regexp options i or x
33
33
  #
34
34
  # @return [Array] filters with regexp-like string converted to PlatformRegexpFilter
35
35
  def self.convert(filters)
@@ -57,7 +57,7 @@ module Kitchen
57
57
  @value = value
58
58
  end
59
59
 
60
- # Override of the equality operator to check whether the wrapped Regexp match the given object.
60
+ # Override of the equality operator to check whether the wrapped Regexp matches the given object.
61
61
  #
62
62
  # @param [Object] other object to compare to
63
63
  # @return [Boolean] whether the objects are equal or the wrapped Regexp matches the given string or symbol
@@ -20,10 +20,13 @@ require_relative "errors"
20
20
  require_relative "util"
21
21
 
22
22
  module Kitchen
23
+ # Namespace for plugin loading and the shared plugin base class.
24
+ #
25
+ # @author Fletcher Nichol <fnichol@nichol.ca>
23
26
  module Plugin
24
27
  # Returns an instance of a plugin given a type, name, and config.
25
28
  #
26
- # @param type [Module] a Kitchen::<Module> of one of the plugin types
29
+ # @param type [Module] a `Kitchen::<Module>` of one of the plugin types
27
30
  # (Driver, Provisioner, Transport, Verifier)
28
31
  # @param plugin [String] a plugin name, which will be constantized
29
32
  # @param config [Hash] a configuration hash to initialize the plugin
@@ -17,6 +17,11 @@
17
17
 
18
18
  module Kitchen
19
19
  module Plugin
20
+ # Common base class for every plugin type (Driver, Provisioner, Transport,
21
+ # and Verifier), providing the shared plugin lifecycle and the
22
+ # serial-action registry.
23
+ #
24
+ # @author Fletcher Nichol <fnichol@nichol.ca>
20
25
  class Base
21
26
  class << self
22
27
  # @return [Array<Symbol>] an array of action method names that cannot
@@ -142,7 +142,7 @@ module Kitchen
142
142
  # Check system and configuration for common errors.
143
143
  #
144
144
  # @param state [Hash] mutable instance state
145
- # @returns [Boolean] Return true if a problem is found.
145
+ # @return [Boolean] Return true if a problem is found.
146
146
  def doctor(state)
147
147
  false
148
148
  end
@@ -211,11 +211,11 @@ module Kitchen
211
211
  # exception if `#create_sandbox` has not yet been called.
212
212
  #
213
213
  # @return [String] the absolute path to the sandbox directory
214
- # @raise [ClientError] if the sandbox directory has no yet been created
214
+ # @raise [ClientError] if the sandbox directory has not yet been created
215
215
  # by calling `#create_sandbox`
216
216
  def sandbox_path
217
217
  @sandbox_path ||= raise ClientError, "Sandbox directory has not yet " \
218
- "been created. Please run #{self.class}#create_sandox before " \
218
+ "been created. Please run #{self.class}#create_sandbox before " \
219
219
  "trying to access the path."
220
220
  end
221
221
 
@@ -264,7 +264,7 @@ module Kitchen
264
264
 
265
265
  # Conditionally prefixes a command with a sudo command.
266
266
  #
267
- # @param command [String] command to be prefixed
267
+ # @param script [String] command to be prefixed
268
268
  # @return [String] the command, conditionally prefixed with sudo
269
269
  # @api private
270
270
  def sudo(script)
@@ -285,7 +285,7 @@ module Kitchen
285
285
  # Cisco Nexus, require all commands to be run with a prefix to
286
286
  # obtain outbound network access.
287
287
  #
288
- # @param command [String] command to be prefixed
288
+ # @param script [String] command to be prefixed
289
289
  # @return [String] the command, conditionally prefixed with the configured prefix
290
290
  # @api private
291
291
  def prefix_command(script)
@@ -19,7 +19,7 @@ require_relative "../../kitchen"
19
19
 
20
20
  module Kitchen
21
21
  module Provisioner
22
- # Dummy provisioner for Kitchen. This driver does nothing but report what
22
+ # Dummy provisioner for Kitchen. This provisioner does nothing but report what
23
23
  # would happen if this provisioner did anything of consequence. As a result
24
24
  # it may be a useful provisioner to use when debugging or developing new
25
25
  # features or plugins.
@@ -25,12 +25,30 @@ module Kitchen
25
25
  module Provisioner
26
26
  # Executes an external provisioner provider over the v1 stdio protocol.
27
27
  class External < Base
28
+ # The provider protocol version this provisioner speaks. A provider
29
+ # reporting any other version is rejected during capability negotiation.
30
+ #
31
+ # @return [String] a protocol version string
28
32
  PROTOCOL_VERSION = "1.0".freeze
33
+ # The result statuses a provider may report for an action.
34
+ #
35
+ # @return [Array<String>] valid result statuses
29
36
  RESULT_STATUSES = %w{passed failed skipped}.freeze
37
+ # The log levels a provider may attach to a log message.
38
+ #
39
+ # @return [Array<String>] valid log levels
30
40
  LOG_LEVELS = %w{debug info warn error}.freeze
41
+ # Configuration keys consumed by this provisioner itself, and so withheld
42
+ # from the configuration passed out to the provider.
43
+ #
44
+ # @return [Array<Symbol>] internal-only configuration keys
31
45
  INTERNAL_CONFIG_KEYS = %i{
32
46
  command provider pass_env kitchen_root test_base_path
33
47
  }.freeze
48
+ # Configuration keys whose values are redacted before configuration is
49
+ # logged or handed to a provider.
50
+ #
51
+ # @return [Array<String>] keys to redact
34
52
  REDACTED_KEYS = %w{password ssh_http_proxy_password}.freeze
35
53
 
36
54
  kitchen_provisioner_api_version 2
@@ -50,6 +68,10 @@ module Kitchen
50
68
  persist_provider_state(state, result)
51
69
  end
52
70
 
71
+ # Derives the provider's name from the configured command, stripping any
72
+ # directory portion and the conventional `kitchen-provider-` prefix.
73
+ #
74
+ # @return [String] the provider name
53
75
  def provider_name_from_command
54
76
  first_part = Shellwords.split(config[:command].to_s).first.to_s
55
77
  File.basename(first_part).sub(/^kitchen-provider-/, "")
@@ -62,7 +62,7 @@ module Kitchen
62
62
  data = remote_path_join(root, "data")
63
63
 
64
64
  code = if powershell_shell?
65
- Util.outdent!(<<-POWERSHELL)
65
+ Util.outdent(<<-POWERSHELL)
66
66
  if (Test-Path "#{data}") {
67
67
  Remove-Item "#{data}" -Recurse -Force
68
68
  }
@@ -20,7 +20,7 @@ require_relative "plugin"
20
20
 
21
21
  module Kitchen
22
22
  # A provisioner is responsible for generating the commands necessary to
23
- # install set up and use a configuration management tool such as Chef and
23
+ # install, set up, and use a configuration management tool such as Chef and
24
24
  # Puppet.
25
25
  #
26
26
  # @author Fletcher Nichol <fnichol@nichol.ca>
@@ -17,6 +17,8 @@
17
17
 
18
18
  require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
19
19
 
20
+ require_relative "errors" # for TransientFailure
21
+
20
22
  module Kitchen
21
23
  # Mixin that wraps a command shell out invocation, providing a #run_command
22
24
  # method.
@@ -26,7 +26,7 @@ module Kitchen
26
26
  #
27
27
  # @author Fletcher Nichol <fnichol@nichol.ca>
28
28
  class StateFile
29
- # Constructs an new instance taking the kitchen root and instance name.
29
+ # Constructs a new instance taking the kitchen root and instance name.
30
30
  #
31
31
  # @param kitchen_root [String] path to the Kitchen project's root directory
32
32
  # @param name [String] name of the instance representing this state
data/lib/kitchen/suite.rb CHANGED
@@ -35,7 +35,7 @@ module Kitchen
35
35
  # Constructs a new suite.
36
36
  #
37
37
  # @param [Hash] options configuration for a new suite
38
- # @option options [String] :name logical name of this suit (**Required**)
38
+ # @option options [String] :name logical name of this suite (**Required**)
39
39
  # @option options [String] :excludes Array of names of excluded platforms
40
40
  # @option options [String] :includes Array of names of only included
41
41
  # platforms
@@ -69,7 +69,7 @@ module Kitchen
69
69
  # Check system and configuration for common errors.
70
70
  #
71
71
  # @param state [Hash] mutable instance state
72
- # @returns [Boolean] Return true if a problem is found.
72
+ # @return [Boolean] Return true if a problem is found.
73
73
  def doctor(state)
74
74
  false
75
75
  end
@@ -31,14 +31,21 @@ module Kitchen
31
31
  default_config :sleep, 1
32
32
  default_config :random_exit_code, 0
33
33
 
34
+ # Creates a new dummy connection, merging the instance state into the
35
+ # transport's configuration.
36
+ #
37
+ # @param state [Hash] the instance state hash
38
+ # @yield [Connection] yields the connection for block-style invocation
39
+ # @return [Connection] a new connection
34
40
  def connection(state, &block)
35
41
  options = config.to_hash.merge(state)
36
42
  Kitchen::Transport::Dummy::Connection.new(options, &block)
37
43
  end
38
44
 
39
- # TODO: comment
45
+ # A connection that reports the actions it would have carried out
46
+ # rather than contacting any remote host.
40
47
  class Connection < Kitchen::Transport::Base::Connection
41
- # (see Base#execute)
48
+ # (see Base::Connection#execute)
42
49
  def execute(command)
43
50
  report(:execute, command)
44
51
  if options[:random_exit_code] != 0
@@ -46,10 +53,20 @@ module Kitchen
46
53
  end
47
54
  end
48
55
 
56
+ # Reports that the given files would have been uploaded.
57
+ #
58
+ # @param locals [Array<String>] local paths that would be uploaded
59
+ # @param remote [String] the remote destination path
60
+ # @return [void]
49
61
  def upload(locals, remote)
50
62
  report(:upload, "#{locals.inspect} => #{remote}")
51
63
  end
52
64
 
65
+ # Reports that the given files would have been downloaded.
66
+ #
67
+ # @param remotes [Array<String>] remote paths that would be downloaded
68
+ # @param local [String] the local destination path
69
+ # @return [void]
53
70
  def download(remotes, local)
54
71
  report(:download, "#{remotes.inspect} => #{local}")
55
72
  end
@@ -60,7 +77,8 @@ module Kitchen
60
77
  # possibly fail randomly.
61
78
  #
62
79
  # @param action [Symbol] the action currently taking place
63
- # @param state [Hash] the state hash
80
+ # @param msg [String] an optional message describing the action's
81
+ # subject, appended to the log output
64
82
  # @api private
65
83
  def report(action, msg = "")
66
84
  what = action.capitalize
@@ -66,7 +66,7 @@ module Kitchen
66
66
  end
67
67
  end
68
68
 
69
- # (see Base#init_options)
69
+ # (see Base::Connection#init_options)
70
70
  def init_options(options)
71
71
  super
72
72
  @instance_name = @options.delete(:instance_name)
@@ -77,6 +77,10 @@ module Kitchen
77
77
  transport[:compression] == false ? 0 : 6
78
78
  end
79
79
 
80
+ # (see Base#finalize_config!)
81
+ #
82
+ # Casts legacy `:compression` values to what net-ssh 2.10 and later
83
+ # expect.
80
84
  def finalize_config!(instance)
81
85
  super
82
86
 
@@ -106,7 +110,7 @@ module Kitchen
106
110
  # (see Base#cleanup!)
107
111
  def cleanup!
108
112
  if @connection
109
- string_to_mask = "[SSH] shutting previous connection #{@connection}"
113
+ string_to_mask = "[SSH] shutting down previous connection #{@connection}"
110
114
  masked_string = Util.mask_values(string_to_mask, %w{password ssh_http_proxy_password})
111
115
  logger.debug(masked_string)
112
116
  @connection.close
@@ -121,7 +125,10 @@ module Kitchen
121
125
  #
122
126
  # @author Fletcher Nichol <fnichol@nichol.ca>
123
127
  class Connection < Kitchen::Transport::Base::Connection
124
- # (see Base::Connection#initialize)
128
+ # Create a new Connection instance.
129
+ #
130
+ # @param config [Hash] connection options
131
+ # @yield [self] yields itself for block-style invocation
125
132
  def initialize(config = {})
126
133
  super(config)
127
134
  @session = nil
@@ -299,17 +306,17 @@ module Kitchen
299
306
  # @api private
300
307
  attr_reader :ssh_http_proxy
301
308
 
302
- # @return [Integer] The port to use when using an kitchen ssh proxy
309
+ # @return [Integer] The port to use when using a kitchen ssh proxy
303
310
  # remote SSH host via http proxy
304
311
  # @api private
305
312
  attr_reader :ssh_http_proxy_port
306
313
 
307
- # @return [String] The username to use when using an kitchen ssh proxy
314
+ # @return [String] The username to use when using a kitchen ssh proxy
308
315
  # remote SSH host via http proxy
309
316
  # @api private
310
317
  attr_reader :ssh_http_proxy_user
311
318
 
312
- # @return [String] The password to use when using an kitchen ssh proxy
319
+ # @return [String] The password to use when using a kitchen ssh proxy
313
320
  # remote SSH host via http proxy
314
321
  # @api private
315
322
  attr_reader :ssh_http_proxy_password
@@ -570,7 +577,7 @@ module Kitchen
570
577
  current_net_ssh >= new_option_version ? :never : false
571
578
  end
572
579
 
573
- # Creates a new SSH Connection instance and save it for potential future
580
+ # Creates a new SSH Connection instance and saves it for potential future
574
581
  # reuse.
575
582
  #
576
583
  # @param options [Hash] connection options
@@ -58,6 +58,9 @@ module Kitchen
58
58
  transport[:winrm_transport] == :ssl ? 5986 : 5985
59
59
  end
60
60
 
61
+ # (see Base#finalize_config!)
62
+ #
63
+ # Coerces `:winrm_transport` to a Symbol.
61
64
  def finalize_config!(instance)
62
65
  super
63
66
 
@@ -84,7 +87,10 @@ module Kitchen
84
87
  #
85
88
  # @author Fletcher Nichol <fnichol@nichol.ca>
86
89
  class Connection < Kitchen::Transport::Base::Connection
87
- # (see Base::Connection#initialize)
90
+ # Create a new Connection instance.
91
+ #
92
+ # @param config [Hash] connection options
93
+ # @yield [self] yields itself for block-style invocation
88
94
  def initialize(config = {})
89
95
  super(config)
90
96
  @unelevated_session = nil
@@ -225,7 +231,7 @@ module Kitchen
225
231
  # @api private
226
232
  attr_reader :max_wait_until_ready
227
233
 
228
- # @return [Integer] the TCP port number to use when connection to the
234
+ # @return [Integer] the TCP port number to use when connecting to the
229
235
  # remote WinRM host
230
236
  # @api private
231
237
  attr_reader :rdp_port
@@ -241,7 +247,7 @@ module Kitchen
241
247
  # Mac system
242
248
  # @api private
243
249
  def create_rdp_doc(opts = {})
244
- content = Util.outdent!(<<-RDP)
250
+ content = Util.outdent(<<-RDP)
245
251
  full address:s:#{URI.parse(options[:endpoint]).host}:#{rdp_port}
246
252
  prompt for credentials:i:1
247
253
  username:s:#{options[:user]}
@@ -293,7 +299,7 @@ module Kitchen
293
299
  @file_transporter ||= WinRM::FS::Core::FileTransporter.new(unelevated_session)
294
300
  end
295
301
 
296
- # (see Base#init_options)
302
+ # (see Base::Connection#init_options)
297
303
  def init_options(options)
298
304
  super
299
305
  @instance_name = @options.delete(:instance_name)
@@ -494,15 +500,15 @@ module Kitchen
494
500
  end
495
501
  end
496
502
 
497
- # Creates a new WinRM Connection instance and save it for potential
503
+ # Creates a new WinRM Connection instance and saves it for potential
498
504
  # future reuse.
499
505
  #
500
506
  # @param options [Hash] connection options
501
- # @return [Ssh::Connection] a WinRM Connection instance
507
+ # @return [Winrm::Connection] a WinRM Connection instance
502
508
  # @api private
503
509
  def create_new_connection(options, &block)
504
510
  if @connection
505
- string_to_mask = "[WinRM] shutting previous connection #{@connection}"
511
+ string_to_mask = "[WinRM] shutting down previous connection #{@connection}"
506
512
  masked_string = Util.mask_values(string_to_mask, %w{password ssh_http_proxy_password})
507
513
  logger.debug(masked_string)
508
514
  @connection.close
data/lib/kitchen/util.rb CHANGED
@@ -24,6 +24,17 @@ module Kitchen
24
24
  #
25
25
  # @author Fletcher Nichol <fnichol@nichol.ca>
26
26
  module Util
27
+ class << self
28
+ # @return [Mutex] a mutex used to serialize the process-global Dir.chdir
29
+ attr_accessor :mutex_chdir
30
+ end
31
+
32
+ # Dir.chdir mutates process-global state, so every call has to be
33
+ # serialized. The mutex is owned here rather than in lib/kitchen.rb
34
+ # because Util is its only consumer and has to keep working when
35
+ # "kitchen/util" is required on its own.
36
+ @mutex_chdir = Mutex.new
37
+
27
38
  # Returns the standard library Logger level constants for a given symbol
28
39
  # representation.
29
40
  #
@@ -37,7 +48,7 @@ module Kitchen
37
48
  Logger.const_get(symbol.to_s.upcase)
38
49
  end
39
50
 
40
- # Returns the symbol representation of a logging levels for a given
51
+ # Returns the symbol representation of a logging level for a given
41
52
  # standard library Logger::Severity constant.
42
53
  #
43
54
  # @param const [Integer] Logger::Severity constant value for a logging
@@ -91,7 +102,7 @@ module Kitchen
91
102
  # Returns a string with masked values for specified parameters.
92
103
  #
93
104
  # @param string_to_mask [String] the object whose string representation is parsed
94
- # @param [Array] the list of keys whose values should be masked
105
+ # @param keys [Array] the list of keys whose values should be masked
95
106
  # @return [String] the string representation of passed object with masked values
96
107
  def self.mask_values(string_to_mask, keys)
97
108
  masked_string = string_to_mask
@@ -118,7 +129,7 @@ module Kitchen
118
129
  # This method uses the Bourne shell (/bin/sh) to maximize the chance of
119
130
  # cross platform portability on Unixlike systems.
120
131
  #
121
- # @param [String] the command
132
+ # @param cmd [String] the command
122
133
  # @return [String] a wrapped command string
123
134
  def self.wrap_command(cmd)
124
135
  cmd = "false" if cmd.nil?
@@ -146,6 +157,22 @@ module Kitchen
146
157
  string.gsub!(/^ {#{string.index(/[^ ]/)}}/, "")
147
158
  end
148
159
 
160
+ # Returns a copy of a string with each line outdented by the indentation
161
+ # level of its first line.
162
+ #
163
+ # Prefer this over {.outdent!} when the input may be a string literal:
164
+ # Ruby 4 freezes literals, and mutating one raises a FrozenError.
165
+ #
166
+ # @param string [String] the string to outdent
167
+ # @return [String] a new, outdented string
168
+ # @example
169
+ #
170
+ # string = " a\n b\n c\n"
171
+ # Util.outdent(string) # => "a\n b\nc\n"
172
+ def self.outdent(string)
173
+ string.gsub(/^ {#{string.index(/[^ ]/)}}/, "")
174
+ end
175
+
149
176
  # Returns a set of Bourne Shell (AKA /bin/sh) compatible helper
150
177
  # functions. This function is usually called inline in a string that
151
178
  # will be executed remotely on a test instance.
@@ -166,7 +193,7 @@ module Kitchen
166
193
  # @return A listing of the specified path
167
194
  #
168
195
  # @note You should prefer this method to using Dir.glob directly. The reason is
169
- # because Dir.glob behaves strangely on Windows. It wont accept '\'
196
+ # because Dir.glob behaves strangely on Windows. It won't accept '\'
170
197
  # and doesn't like fake directories (C:\Documents and Settings)
171
198
  # It also does not do any sort of error checking, so things one would
172
199
  # expect to fail just return an empty list
@@ -178,7 +205,7 @@ module Kitchen
178
205
  # the directory does not exist
179
206
  return [] unless Dir.exist?(path)
180
207
 
181
- Kitchen.mutex_chdir.synchronize do
208
+ mutex_chdir.synchronize do
182
209
  Dir.chdir(path) do
183
210
  glob_pattern = if recurse
184
211
  "**/*"
@@ -214,17 +241,25 @@ module Kitchen
214
241
  def self.safe_glob(path, pattern, *flags)
215
242
  return [] unless Dir.exist?(path)
216
243
 
217
- Kitchen.mutex_chdir.synchronize do
244
+ mutex_chdir.synchronize do
218
245
  Dir.chdir(path) do
219
246
  Dir.glob(pattern, *flags).map { |f| File.join(path, f) }
220
247
  end
221
248
  end
222
249
  end
223
250
 
251
+ # Returns a CamelCase version of a snake_case string.
252
+ #
253
+ # @param a_string [String] a snake_case string
254
+ # @return [String] a CamelCase string
224
255
  def self.camel_case(a_string)
225
256
  Thor::Util.camel_case(a_string)
226
257
  end
227
258
 
259
+ # Returns a snake_case version of a CamelCase string.
260
+ #
261
+ # @param a_string [String] a CamelCase string
262
+ # @return [String] a snake_case string
228
263
  def self.snake_case(a_string)
229
264
  Thor::Util.snake_case(a_string)
230
265
  end
@@ -106,7 +106,7 @@ module Kitchen
106
106
  # Check system and configuration for common errors.
107
107
  #
108
108
  # @param state [Hash] mutable instance state
109
- # @returns [Boolean] Return true if a problem is found.
109
+ # @return [Boolean] Return true if a problem is found.
110
110
  def doctor(state)
111
111
  false
112
112
  end
@@ -180,11 +180,11 @@ module Kitchen
180
180
  # exception if `#create_sandbox` has not yet been called.
181
181
  #
182
182
  # @return [String] the absolute path to the sandbox directory
183
- # @raise [ClientError] if the sandbox directory has no yet been created
183
+ # @raise [ClientError] if the sandbox directory has not yet been created
184
184
  # by calling `#create_sandbox`
185
185
  def sandbox_path
186
186
  @sandbox_path ||= raise ClientError, "Sandbox directory has not yet " \
187
- "been created. Please run #{self.class}#create_sandox before " \
187
+ "been created. Please run #{self.class}#create_sandbox before " \
188
188
  "trying to access the path."
189
189
  end
190
190
 
@@ -240,7 +240,7 @@ module Kitchen
240
240
 
241
241
  # Conditionally prefixes a command with a sudo command.
242
242
  #
243
- # @param command [String] command to be prefixed
243
+ # @param script [String] command to be prefixed
244
244
  # @return [String] the command, conditionally prefixed with sudo
245
245
  # @api private
246
246
  def sudo(script)
@@ -253,7 +253,7 @@ module Kitchen
253
253
  # Cisco Nexus, require all commands to be run with a prefix to
254
254
  # obtain outbound network access.
255
255
  #
256
- # @param command [String] command to be prefixed
256
+ # @param script [String] command to be prefixed
257
257
  # @return [String] the command, conditionally prefixed with the configured prefix
258
258
  # @api private
259
259
  def prefix_command(script)
@@ -23,7 +23,7 @@ require_relative "base"
23
23
  module Kitchen
24
24
  module Verifier
25
25
  # Command string generator to interface with Busser. The commands that are
26
- # generated are safe to pass to an SSH command or as an unix command
26
+ # generated are safe to pass to an SSH command or as a Unix command
27
27
  # argument (escaped in single quotes).
28
28
  #
29
29
  # @author Fletcher Nichol <fnichol@nichol.ca>
@@ -72,7 +72,7 @@ module Kitchen
72
72
  cmd = sudo(config[:busser_bin]).dup
73
73
  .tap { |str| str.insert(0, "& ") if powershell_shell? }
74
74
 
75
- prefix_command(wrap_shell_code(Util.outdent!(<<-CMD)))
75
+ prefix_command(wrap_shell_code(Util.outdent(<<-CMD)))
76
76
  #{busser_env}
77
77
 
78
78
  #{cmd} suite cleanup
@@ -95,7 +95,7 @@ module Kitchen
95
95
  cmd = sudo(config[:busser_bin]).dup
96
96
  .tap { |str| str.insert(0, "& ") if powershell_shell? }
97
97
 
98
- prefix_command(wrap_shell_code(Util.outdent!(<<-CMD)))
98
+ prefix_command(wrap_shell_code(Util.outdent(<<-CMD)))
99
99
  #{busser_env}
100
100
 
101
101
  #{cmd} test #{plugins.join(" ").gsub!("busser-", "")}
@@ -19,7 +19,7 @@ require_relative "base"
19
19
 
20
20
  module Kitchen
21
21
  module Verifier
22
- # Shell verifier for Kitchen. This verifier just execute shell command from local.
22
+ # Shell verifier for Kitchen. This verifier just executes a shell command locally.
23
23
  #
24
24
  # @author SAWANOBORI Yukihiko (<sawanoboriyu@higanworks.com>)
25
25
  class Shell < Kitchen::Verifier::Base
@@ -16,5 +16,8 @@
16
16
  # limitations under the License.
17
17
 
18
18
  module Kitchen
19
- VERSION = "4.1.1".freeze
19
+ # The currently released version of Test Kitchen.
20
+ #
21
+ # @return [String] a semantic version string
22
+ VERSION = "4.1.3".freeze
20
23
  end
data/lib/kitchen/which.rb CHANGED
@@ -19,6 +19,8 @@ require "chef-utils/dsl/which" unless defined?(ChefUtils::DSL::Which)
19
19
  require_relative "chef_utils_wiring" unless defined?(Kitchen::ChefUtilsWiring)
20
20
 
21
21
  module Kitchen
22
+ # Mixin providing a `which` helper for locating executables on the PATH,
23
+ # wired up to Test Kitchen's chef-utils configuration.
22
24
  module Which
23
25
  include ChefUtils::DSL::Which
24
26
  include ChefUtilsWiring
data/lib/kitchen.rb CHANGED
@@ -57,8 +57,23 @@ module Kitchen
57
57
  # @return [Mutex] a common mutex for global coordination
58
58
  attr_accessor :mutex
59
59
 
60
+ # Returns the mutex used for Dir.chdir coordination.
61
+ #
60
62
  # @return [Mutex] a mutex used for Dir.chdir coordination
61
- attr_accessor :mutex_chdir
63
+ # @deprecated Use {Kitchen::Util.mutex_chdir}, which owns the mutex and is
64
+ # available without loading all of Test Kitchen.
65
+ def mutex_chdir
66
+ Kitchen::Util.mutex_chdir
67
+ end
68
+
69
+ # Sets the mutex used for Dir.chdir coordination.
70
+ #
71
+ # @param mutex [Mutex] the mutex to use for Dir.chdir coordination
72
+ # @return [Mutex] the newly set mutex
73
+ # @deprecated Use {Kitchen::Util.mutex_chdir=}.
74
+ def mutex_chdir=(mutex)
75
+ Kitchen::Util.mutex_chdir = mutex
76
+ end
62
77
 
63
78
  # @return [String] identifier for the current Kitchen process invocation
64
79
  attr_writer :run_id
@@ -85,7 +100,7 @@ module Kitchen
85
100
  # log file.
86
101
  #
87
102
  # @param [Symbol] level logging level
88
- # @param [Boolean] log_overwrite logging level
103
+ # @param [Boolean] log_overwrite whether to overwrite the log file
89
104
  # @return [Logger] a logger
90
105
  def default_file_logger(level = nil, log_overwrite = nil)
91
106
  level ||= env_log
@@ -162,8 +177,5 @@ end
162
177
  # Initialize the base logger
163
178
  Kitchen.logger = Kitchen.default_logger
164
179
 
165
- # Setup a collection of instance crash exceptions for error reporting
180
+ # Set up a collection of instance crash exceptions for error reporting
166
181
  Kitchen.mutex = Mutex.new
167
-
168
- # Initialize the mutex for Dir.chdir coordination
169
- Kitchen.mutex_chdir = Mutex.new