test-kitchen 0.7.0 → 1.0.0.alpha.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.
- data/.gitignore +20 -0
- data/.travis.yml +11 -0
- data/.yardopts +3 -0
- data/Gemfile +13 -0
- data/Guardfile +11 -0
- data/LICENSE +15 -0
- data/README.md +131 -0
- data/Rakefile +69 -0
- data/bin/kitchen +9 -4
- data/features/cli.feature +17 -0
- data/features/cli_init.feature +156 -0
- data/features/support/env.rb +14 -0
- data/lib/kitchen/busser.rb +166 -0
- data/lib/kitchen/chef_data_uploader.rb +156 -0
- data/lib/kitchen/cli.rb +540 -0
- data/lib/kitchen/collection.rb +55 -0
- data/lib/kitchen/color.rb +46 -0
- data/lib/kitchen/config.rb +223 -0
- data/lib/kitchen/driver/base.rb +180 -0
- data/lib/kitchen/driver/dummy.rb +81 -0
- data/lib/kitchen/driver/ssh_base.rb +192 -0
- data/lib/kitchen/driver.rb +42 -0
- data/lib/kitchen/errors.rb +52 -0
- data/lib/kitchen/instance.rb +327 -0
- data/lib/kitchen/instance_actor.rb +42 -0
- data/lib/kitchen/loader/yaml.rb +105 -0
- data/lib/kitchen/logger.rb +145 -0
- data/{cookbooks/test-kitchen/libraries/helpers.rb → lib/kitchen/logging.rb} +13 -9
- data/lib/kitchen/manager.rb +45 -0
- data/lib/kitchen/metadata_chopper.rb +52 -0
- data/lib/kitchen/platform.rb +61 -0
- data/lib/kitchen/rake_tasks.rb +59 -0
- data/lib/kitchen/shell_out.rb +65 -0
- data/lib/kitchen/state_file.rb +88 -0
- data/lib/kitchen/suite.rb +76 -0
- data/lib/kitchen/thor_tasks.rb +62 -0
- data/lib/kitchen/util.rb +79 -0
- data/{cookbooks/test-kitchen/recipes/erlang.rb → lib/kitchen/version.rb} +9 -6
- data/lib/kitchen.rb +98 -0
- data/lib/vendor/hash_recursive_merge.rb +74 -0
- data/spec/kitchen/collection_spec.rb +80 -0
- data/spec/kitchen/color_spec.rb +54 -0
- data/spec/kitchen/config_spec.rb +201 -0
- data/spec/kitchen/driver/dummy_spec.rb +191 -0
- data/spec/kitchen/instance_spec.rb +162 -0
- data/spec/kitchen/loader/yaml_spec.rb +243 -0
- data/spec/kitchen/platform_spec.rb +48 -0
- data/spec/kitchen/state_file_spec.rb +122 -0
- data/spec/kitchen/suite_spec.rb +64 -0
- data/spec/spec_helper.rb +47 -0
- data/templates/plugin/driver.rb.erb +23 -0
- data/templates/plugin/license_apachev2.erb +15 -0
- data/templates/plugin/license_gplv2.erb +18 -0
- data/templates/plugin/license_gplv3.erb +16 -0
- data/templates/plugin/license_mit.erb +22 -0
- data/templates/plugin/license_reserved.erb +5 -0
- data/templates/plugin/version.rb.erb +12 -0
- data/test-kitchen.gemspec +44 -0
- metadata +290 -82
- data/config/Cheffile +0 -47
- data/config/Kitchenfile +0 -39
- data/config/Vagrantfile +0 -114
- data/cookbooks/test-kitchen/attributes/default.rb +0 -25
- data/cookbooks/test-kitchen/metadata.rb +0 -27
- data/cookbooks/test-kitchen/recipes/chef.rb +0 -19
- data/cookbooks/test-kitchen/recipes/compat.rb +0 -39
- data/cookbooks/test-kitchen/recipes/default.rb +0 -51
- data/cookbooks/test-kitchen/recipes/ruby.rb +0 -29
- data/lib/test-kitchen/cli/destroy.rb +0 -36
- data/lib/test-kitchen/cli/init.rb +0 -37
- data/lib/test-kitchen/cli/platform_list.rb +0 -37
- data/lib/test-kitchen/cli/project_info.rb +0 -44
- data/lib/test-kitchen/cli/ssh.rb +0 -36
- data/lib/test-kitchen/cli/status.rb +0 -36
- data/lib/test-kitchen/cli/test.rb +0 -68
- data/lib/test-kitchen/cli.rb +0 -282
- data/lib/test-kitchen/dsl.rb +0 -63
- data/lib/test-kitchen/environment.rb +0 -166
- data/lib/test-kitchen/platform.rb +0 -79
- data/lib/test-kitchen/project/base.rb +0 -159
- data/lib/test-kitchen/project/cookbook.rb +0 -97
- data/lib/test-kitchen/project/cookbook_copy.rb +0 -58
- data/lib/test-kitchen/project/ruby.rb +0 -37
- data/lib/test-kitchen/project/supported_platforms.rb +0 -75
- data/lib/test-kitchen/project.rb +0 -23
- data/lib/test-kitchen/runner/base.rb +0 -154
- data/lib/test-kitchen/runner/openstack/dsl.rb +0 -39
- data/lib/test-kitchen/runner/openstack/environment.rb +0 -141
- data/lib/test-kitchen/runner/openstack.rb +0 -147
- data/lib/test-kitchen/runner/vagrant.rb +0 -95
- data/lib/test-kitchen/runner.rb +0 -21
- data/lib/test-kitchen/scaffold.rb +0 -88
- data/lib/test-kitchen/ui.rb +0 -73
- data/lib/test-kitchen/version.rb +0 -21
- data/lib/test-kitchen.rb +0 -34
@@ -0,0 +1,76 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
module Kitchen
|
20
|
+
|
21
|
+
# A Chef run_list and attribute hash that will be used in a convergence
|
22
|
+
# integration.
|
23
|
+
#
|
24
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
25
|
+
class Suite
|
26
|
+
|
27
|
+
# @return [String] logical name of this suite
|
28
|
+
attr_reader :name
|
29
|
+
|
30
|
+
# @return [Array] Array of Chef run_list items
|
31
|
+
attr_reader :run_list
|
32
|
+
|
33
|
+
# @return [Hash] Hash of Chef node attributes
|
34
|
+
attr_reader :attributes
|
35
|
+
|
36
|
+
# @return [Array] Array of names of excluded platforms
|
37
|
+
attr_reader :excludes
|
38
|
+
|
39
|
+
# @return [String] local path to the suite's data bags, or nil if one does
|
40
|
+
# not exist
|
41
|
+
attr_reader :data_bags_path
|
42
|
+
|
43
|
+
# @return [String] local path to the suite's roles, or nil if one does
|
44
|
+
# not exist
|
45
|
+
attr_reader :roles_path
|
46
|
+
|
47
|
+
# Constructs a new suite.
|
48
|
+
#
|
49
|
+
# @param [Hash] options configuration for a new suite
|
50
|
+
# @option options [String] :name logical name of this suit (**Required**)
|
51
|
+
# @option options [String] :run_list Array of Chef run_list items
|
52
|
+
# (**Required**)
|
53
|
+
# @option options [Hash] :attributes Hash of Chef node attributes
|
54
|
+
# @option options [String] :excludes Array of names of excluded platforms
|
55
|
+
# @option options [String] :data_bags_path path to data bags
|
56
|
+
# @option options [String] :roles_path path to roles
|
57
|
+
def initialize(options = {})
|
58
|
+
validate_options(options)
|
59
|
+
|
60
|
+
@name = options[:name]
|
61
|
+
@run_list = options[:run_list]
|
62
|
+
@attributes = options[:attributes] || Hash.new
|
63
|
+
@excludes = options[:excludes] || Array.new
|
64
|
+
@data_bags_path = options[:data_bags_path]
|
65
|
+
@roles_path = options[:roles_path]
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def validate_options(opts)
|
71
|
+
[:name, :run_list].each do |k|
|
72
|
+
raise ClientError, "Suite#new requires option :#{k}" if opts[k].nil?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require 'thor'
|
20
|
+
|
21
|
+
require 'kitchen'
|
22
|
+
|
23
|
+
module Kitchen
|
24
|
+
|
25
|
+
# Kitchen Thor task generator.
|
26
|
+
#
|
27
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
28
|
+
class ThorTasks < Thor
|
29
|
+
|
30
|
+
namespace :kitchen
|
31
|
+
|
32
|
+
# Creates Kitchen Thor tasks and allows the callee to configure it.
|
33
|
+
#
|
34
|
+
# @yield [self] gives itself to the block
|
35
|
+
def initialize(*args)
|
36
|
+
super
|
37
|
+
@config = Kitchen::Config.new
|
38
|
+
@config.supervised = false
|
39
|
+
Kitchen.logger = Kitchen.default_file_logger
|
40
|
+
yield self if block_given?
|
41
|
+
define
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
attr_reader :config
|
47
|
+
|
48
|
+
def define
|
49
|
+
config.instances.each do |instance|
|
50
|
+
self.class.desc instance.name, "Run #{instance.name} test instance"
|
51
|
+
self.class.send(:define_method, instance.name.gsub(/-/, '_')) do
|
52
|
+
instance.test(:always)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
self.class.desc "all", "Run all test instances"
|
57
|
+
self.class.send(:define_method, :all) do
|
58
|
+
config.instances.each { |i| invoke i.name.gsub(/-/, '_') }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/kitchen/util.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
module Kitchen
|
20
|
+
|
21
|
+
# Stateless utility methods used in different contexts. Essentially a mini
|
22
|
+
# PassiveSupport library.
|
23
|
+
module Util
|
24
|
+
|
25
|
+
def self.to_camel_case(str)
|
26
|
+
str.split('_').map { |w| w.capitalize }.join
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.to_snake_case(str)
|
30
|
+
str.split('::').
|
31
|
+
last.
|
32
|
+
gsub(/([A-Z+])([A-Z][a-z])/, '\1_\2').
|
33
|
+
gsub(/([a-z\d])([A-Z])/, '\1_\2').
|
34
|
+
downcase
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.to_logger_level(symbol)
|
38
|
+
return nil unless [:debug, :info, :warn, :error, :fatal].include?(symbol)
|
39
|
+
|
40
|
+
Logger.const_get(symbol.to_s.upcase)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.from_logger_level(const)
|
44
|
+
case const
|
45
|
+
when Logger::DEBUG then :debug
|
46
|
+
when Logger::INFO then :info
|
47
|
+
when Logger::WARN then :warn
|
48
|
+
when Logger::ERROR then :error
|
49
|
+
else :fatal
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.symbolized_hash(obj)
|
54
|
+
if obj.is_a?(Hash)
|
55
|
+
obj.inject({}) { |h, (k, v)| h[k.to_sym] = symbolized_hash(v) ; h }
|
56
|
+
elsif obj.is_a?(Array)
|
57
|
+
obj.inject([]) { |a, v| a << symbolized_hash(v) ; a }
|
58
|
+
else
|
59
|
+
obj
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.stringified_hash(obj)
|
64
|
+
if obj.is_a?(Hash)
|
65
|
+
obj.inject({}) { |h, (k, v)| h[k.to_s] = symbolized_hash(v) ; h }
|
66
|
+
elsif obj.is_a?(Array)
|
67
|
+
obj.inject([]) { |a, v| a << symbolized_hash(v) ; a }
|
68
|
+
else
|
69
|
+
obj
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.duration(total)
|
74
|
+
minutes = (total / 60).to_i
|
75
|
+
seconds = (total - (minutes * 60))
|
76
|
+
"(%dm%.2fs)" % [minutes, seconds]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -1,19 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
#
|
2
|
-
# Author::
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
5
6
|
#
|
6
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
8
|
# you may not use this file except in compliance with the License.
|
8
9
|
# You may obtain a copy of the License at
|
9
10
|
#
|
10
|
-
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
12
|
#
|
12
13
|
# Unless required by applicable law or agreed to in writing, software
|
13
14
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
15
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
16
|
# See the License for the specific language governing permissions and
|
16
17
|
# limitations under the License.
|
17
|
-
#
|
18
18
|
|
19
|
-
|
19
|
+
module Kitchen
|
20
|
+
|
21
|
+
VERSION = "1.0.0.alpha.0"
|
22
|
+
end
|
data/lib/kitchen.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require 'celluloid'
|
20
|
+
require 'pathname'
|
21
|
+
require 'thread'
|
22
|
+
|
23
|
+
require 'kitchen/errors'
|
24
|
+
require 'kitchen/logger'
|
25
|
+
require 'kitchen/logging'
|
26
|
+
require 'kitchen/shell_out'
|
27
|
+
require 'kitchen/util'
|
28
|
+
|
29
|
+
require 'kitchen/busser'
|
30
|
+
require 'kitchen/chef_data_uploader'
|
31
|
+
require 'kitchen/color'
|
32
|
+
require 'kitchen/collection'
|
33
|
+
require 'kitchen/config'
|
34
|
+
require 'kitchen/driver'
|
35
|
+
require 'kitchen/driver/base'
|
36
|
+
require 'kitchen/driver/ssh_base'
|
37
|
+
require 'kitchen/instance'
|
38
|
+
require 'kitchen/instance_actor'
|
39
|
+
require 'kitchen/loader/yaml'
|
40
|
+
require 'kitchen/manager'
|
41
|
+
require 'kitchen/metadata_chopper'
|
42
|
+
require 'kitchen/platform'
|
43
|
+
require 'kitchen/state_file'
|
44
|
+
require 'kitchen/suite'
|
45
|
+
require 'kitchen/version'
|
46
|
+
|
47
|
+
module Kitchen
|
48
|
+
|
49
|
+
class << self
|
50
|
+
|
51
|
+
attr_accessor :logger
|
52
|
+
attr_accessor :crashes
|
53
|
+
attr_accessor :mutex
|
54
|
+
|
55
|
+
# Returns the root path of the Kitchen gem source code.
|
56
|
+
#
|
57
|
+
# @return [Pathname] root path of gem
|
58
|
+
def source_root
|
59
|
+
@source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
|
60
|
+
end
|
61
|
+
|
62
|
+
def crashes?
|
63
|
+
! crashes.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_logger
|
67
|
+
Logger.new(:stdout => STDOUT, :level => env_log)
|
68
|
+
end
|
69
|
+
|
70
|
+
def default_file_logger
|
71
|
+
logfile = File.expand_path(File.join(".kitchen", "logs", "kitchen.log"))
|
72
|
+
Logger.new(:stdout => STDOUT, :logdev => logfile, :level => env_log)
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def env_log
|
78
|
+
level = ENV['KITCHEN_LOG'] && ENV['KITCHEN_LOG'].downcase.to_sym
|
79
|
+
level = Util.to_logger_level(level) unless level.nil?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Default log level verbosity
|
84
|
+
DEFAULT_LOG_LEVEL = :info
|
85
|
+
end
|
86
|
+
|
87
|
+
# Initialize the base logger and use that for Celluloid's logger
|
88
|
+
Kitchen.logger = Kitchen.default_logger
|
89
|
+
Celluloid.logger = Kitchen.logger
|
90
|
+
|
91
|
+
# Setup a collection of instance crash exceptions for error reporting
|
92
|
+
Kitchen.crashes = []
|
93
|
+
Celluloid.exception_handler do |exception|
|
94
|
+
Kitchen.logger.debug("An instance crashed because of #{exception.inspect}")
|
95
|
+
Kitchen.mutex.synchronize { Kitchen.crashes << exception }
|
96
|
+
end
|
97
|
+
|
98
|
+
Kitchen.mutex = Mutex.new
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#
|
2
|
+
# = Hash Recursive Merge
|
3
|
+
#
|
4
|
+
# Merges a Ruby Hash recursively, Also known as deep merge.
|
5
|
+
# Recursive version of Hash#merge and Hash#merge!.
|
6
|
+
#
|
7
|
+
# Category:: Ruby
|
8
|
+
# Package:: Hash
|
9
|
+
# Author:: Simone Carletti <weppos@weppos.net>
|
10
|
+
# Copyright:: 2007-2008 The Authors
|
11
|
+
# License:: MIT License
|
12
|
+
# Link:: http://www.simonecarletti.com/
|
13
|
+
# Source:: http://gist.github.com/gists/6391/
|
14
|
+
#
|
15
|
+
module HashRecursiveMerge
|
16
|
+
|
17
|
+
#
|
18
|
+
# Recursive version of Hash#merge!
|
19
|
+
#
|
20
|
+
# Adds the contents of +other_hash+ to +hsh+,
|
21
|
+
# merging entries in +hsh+ with duplicate keys with those from +other_hash+.
|
22
|
+
#
|
23
|
+
# Compared with Hash#merge!, this method supports nested hashes.
|
24
|
+
# When both +hsh+ and +other_hash+ contains an entry with the same key,
|
25
|
+
# it merges and returns the values from both arrays.
|
26
|
+
#
|
27
|
+
# h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
|
28
|
+
# h2 = {"b" => 254, "c" => {"c1" => 16, "c3" => 94}}
|
29
|
+
# h1.rmerge!(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
|
30
|
+
#
|
31
|
+
# Simply using Hash#merge! would return
|
32
|
+
#
|
33
|
+
# h1.merge!(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
|
34
|
+
#
|
35
|
+
def rmerge!(other_hash)
|
36
|
+
merge!(other_hash) do |key, oldval, newval|
|
37
|
+
oldval.class == self.class ? oldval.rmerge!(newval) : newval
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Recursive version of Hash#merge
|
43
|
+
#
|
44
|
+
# Compared with Hash#merge!, this method supports nested hashes.
|
45
|
+
# When both +hsh+ and +other_hash+ contains an entry with the same key,
|
46
|
+
# it merges and returns the values from both arrays.
|
47
|
+
#
|
48
|
+
# Compared with Hash#merge, this method provides a different approch
|
49
|
+
# for merging nasted hashes.
|
50
|
+
# If the value of a given key is an Hash and both +other_hash+ abd +hsh
|
51
|
+
# includes the same key, the value is merged instead replaced with
|
52
|
+
# +other_hash+ value.
|
53
|
+
#
|
54
|
+
# h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
|
55
|
+
# h2 = {"b" => 254, "c" => {"c1" => 16, "c3" => 94}}
|
56
|
+
# h1.rmerge(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
|
57
|
+
#
|
58
|
+
# Simply using Hash#merge would return
|
59
|
+
#
|
60
|
+
# h1.merge(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
|
61
|
+
#
|
62
|
+
def rmerge(other_hash)
|
63
|
+
r = {}
|
64
|
+
merge(other_hash) do |key, oldval, newval|
|
65
|
+
r[key] = oldval.class == self.class ? oldval.rmerge(newval) : newval
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
class Hash
|
73
|
+
include HashRecursiveMerge
|
74
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require_relative '../spec_helper'
|
20
|
+
require 'ostruct'
|
21
|
+
|
22
|
+
require 'kitchen/collection'
|
23
|
+
|
24
|
+
describe Kitchen::Collection do
|
25
|
+
|
26
|
+
let(:collection) do
|
27
|
+
Kitchen::Collection.new([
|
28
|
+
obj('one'), obj('two', 'a'), obj('two', 'b'), obj('three')
|
29
|
+
])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "transparently wraps an Array" do
|
33
|
+
collection.must_be_instance_of Array
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#get" do
|
37
|
+
|
38
|
+
it "returns a single object by its name" do
|
39
|
+
collection.get('three').must_equal obj('three')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns the first occurance of an object by its name" do
|
43
|
+
collection.get('two').must_equal obj('two', 'a')
|
44
|
+
end
|
45
|
+
|
46
|
+
it "returns nil if an object cannot be found by its name" do
|
47
|
+
collection.get('nope').must_be_nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#get_all" do
|
52
|
+
|
53
|
+
it "returns a Collection of objects whose name matches the regex" do
|
54
|
+
result = collection.get_all(/(one|three)/)
|
55
|
+
result.size.must_equal 2
|
56
|
+
result[0].must_equal obj('one')
|
57
|
+
result[1].must_equal obj('three')
|
58
|
+
result.get_all(/one/).size.must_equal 1
|
59
|
+
end
|
60
|
+
|
61
|
+
it "returns an empty Collection if on matches are found" do
|
62
|
+
result = collection.get_all(/noppa/)
|
63
|
+
result.must_equal []
|
64
|
+
result.get("nahuh").must_be_nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#as_name" do
|
69
|
+
|
70
|
+
it "returns an Array of names as strings" do
|
71
|
+
collection.as_names.must_equal %w{one two two three}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def obj(name, extra = nil)
|
78
|
+
OpenStruct.new(:name => name, :extra => extra)
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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_relative '../spec_helper'
|
20
|
+
|
21
|
+
require 'kitchen/color'
|
22
|
+
|
23
|
+
describe Kitchen::Color do
|
24
|
+
|
25
|
+
describe ".escape" do
|
26
|
+
|
27
|
+
it "returns an empty string if name is nil" do
|
28
|
+
Kitchen::Color.escape(nil).must_equal ""
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns an empty string if name is not in the ANSI hash" do
|
32
|
+
Kitchen::Color.escape(:puce).must_equal ""
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns an ansi escape sequence string for cyan" do
|
36
|
+
Kitchen::Color.escape(:cyan).must_equal "\e[36m"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns an ansi escape sequence string for reset" do
|
40
|
+
Kitchen::Color.escape(:reset).must_equal "\e[0m"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".colorize" do
|
45
|
+
|
46
|
+
it "returns an ansi escaped string colored yellow" do
|
47
|
+
Kitchen::Color.colorize("hello", :yellow).must_equal "\e[33mhello\e[0m"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "returns an unescaped string if color is not in the ANSI hash" do
|
51
|
+
Kitchen::Color.colorize("double", :rainbow).must_equal "double"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|