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.
Files changed (95) hide show
  1. data/.gitignore +20 -0
  2. data/.travis.yml +11 -0
  3. data/.yardopts +3 -0
  4. data/Gemfile +13 -0
  5. data/Guardfile +11 -0
  6. data/LICENSE +15 -0
  7. data/README.md +131 -0
  8. data/Rakefile +69 -0
  9. data/bin/kitchen +9 -4
  10. data/features/cli.feature +17 -0
  11. data/features/cli_init.feature +156 -0
  12. data/features/support/env.rb +14 -0
  13. data/lib/kitchen/busser.rb +166 -0
  14. data/lib/kitchen/chef_data_uploader.rb +156 -0
  15. data/lib/kitchen/cli.rb +540 -0
  16. data/lib/kitchen/collection.rb +55 -0
  17. data/lib/kitchen/color.rb +46 -0
  18. data/lib/kitchen/config.rb +223 -0
  19. data/lib/kitchen/driver/base.rb +180 -0
  20. data/lib/kitchen/driver/dummy.rb +81 -0
  21. data/lib/kitchen/driver/ssh_base.rb +192 -0
  22. data/lib/kitchen/driver.rb +42 -0
  23. data/lib/kitchen/errors.rb +52 -0
  24. data/lib/kitchen/instance.rb +327 -0
  25. data/lib/kitchen/instance_actor.rb +42 -0
  26. data/lib/kitchen/loader/yaml.rb +105 -0
  27. data/lib/kitchen/logger.rb +145 -0
  28. data/{cookbooks/test-kitchen/libraries/helpers.rb → lib/kitchen/logging.rb} +13 -9
  29. data/lib/kitchen/manager.rb +45 -0
  30. data/lib/kitchen/metadata_chopper.rb +52 -0
  31. data/lib/kitchen/platform.rb +61 -0
  32. data/lib/kitchen/rake_tasks.rb +59 -0
  33. data/lib/kitchen/shell_out.rb +65 -0
  34. data/lib/kitchen/state_file.rb +88 -0
  35. data/lib/kitchen/suite.rb +76 -0
  36. data/lib/kitchen/thor_tasks.rb +62 -0
  37. data/lib/kitchen/util.rb +79 -0
  38. data/{cookbooks/test-kitchen/recipes/erlang.rb → lib/kitchen/version.rb} +9 -6
  39. data/lib/kitchen.rb +98 -0
  40. data/lib/vendor/hash_recursive_merge.rb +74 -0
  41. data/spec/kitchen/collection_spec.rb +80 -0
  42. data/spec/kitchen/color_spec.rb +54 -0
  43. data/spec/kitchen/config_spec.rb +201 -0
  44. data/spec/kitchen/driver/dummy_spec.rb +191 -0
  45. data/spec/kitchen/instance_spec.rb +162 -0
  46. data/spec/kitchen/loader/yaml_spec.rb +243 -0
  47. data/spec/kitchen/platform_spec.rb +48 -0
  48. data/spec/kitchen/state_file_spec.rb +122 -0
  49. data/spec/kitchen/suite_spec.rb +64 -0
  50. data/spec/spec_helper.rb +47 -0
  51. data/templates/plugin/driver.rb.erb +23 -0
  52. data/templates/plugin/license_apachev2.erb +15 -0
  53. data/templates/plugin/license_gplv2.erb +18 -0
  54. data/templates/plugin/license_gplv3.erb +16 -0
  55. data/templates/plugin/license_mit.erb +22 -0
  56. data/templates/plugin/license_reserved.erb +5 -0
  57. data/templates/plugin/version.rb.erb +12 -0
  58. data/test-kitchen.gemspec +44 -0
  59. metadata +290 -82
  60. data/config/Cheffile +0 -47
  61. data/config/Kitchenfile +0 -39
  62. data/config/Vagrantfile +0 -114
  63. data/cookbooks/test-kitchen/attributes/default.rb +0 -25
  64. data/cookbooks/test-kitchen/metadata.rb +0 -27
  65. data/cookbooks/test-kitchen/recipes/chef.rb +0 -19
  66. data/cookbooks/test-kitchen/recipes/compat.rb +0 -39
  67. data/cookbooks/test-kitchen/recipes/default.rb +0 -51
  68. data/cookbooks/test-kitchen/recipes/ruby.rb +0 -29
  69. data/lib/test-kitchen/cli/destroy.rb +0 -36
  70. data/lib/test-kitchen/cli/init.rb +0 -37
  71. data/lib/test-kitchen/cli/platform_list.rb +0 -37
  72. data/lib/test-kitchen/cli/project_info.rb +0 -44
  73. data/lib/test-kitchen/cli/ssh.rb +0 -36
  74. data/lib/test-kitchen/cli/status.rb +0 -36
  75. data/lib/test-kitchen/cli/test.rb +0 -68
  76. data/lib/test-kitchen/cli.rb +0 -282
  77. data/lib/test-kitchen/dsl.rb +0 -63
  78. data/lib/test-kitchen/environment.rb +0 -166
  79. data/lib/test-kitchen/platform.rb +0 -79
  80. data/lib/test-kitchen/project/base.rb +0 -159
  81. data/lib/test-kitchen/project/cookbook.rb +0 -97
  82. data/lib/test-kitchen/project/cookbook_copy.rb +0 -58
  83. data/lib/test-kitchen/project/ruby.rb +0 -37
  84. data/lib/test-kitchen/project/supported_platforms.rb +0 -75
  85. data/lib/test-kitchen/project.rb +0 -23
  86. data/lib/test-kitchen/runner/base.rb +0 -154
  87. data/lib/test-kitchen/runner/openstack/dsl.rb +0 -39
  88. data/lib/test-kitchen/runner/openstack/environment.rb +0 -141
  89. data/lib/test-kitchen/runner/openstack.rb +0 -147
  90. data/lib/test-kitchen/runner/vagrant.rb +0 -95
  91. data/lib/test-kitchen/runner.rb +0 -21
  92. data/lib/test-kitchen/scaffold.rb +0 -88
  93. data/lib/test-kitchen/ui.rb +0 -73
  94. data/lib/test-kitchen/version.rb +0 -21
  95. data/lib/test-kitchen.rb +0 -34
@@ -0,0 +1,201 @@
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
+
21
+ require 'kitchen'
22
+ require 'kitchen/logging'
23
+ require 'kitchen/collection'
24
+ require 'kitchen/config'
25
+ require 'kitchen/driver'
26
+ require 'kitchen/instance'
27
+ require 'kitchen/platform'
28
+ require 'kitchen/suite'
29
+ require 'kitchen/util'
30
+
31
+ module Kitchen
32
+
33
+ class DummyLoader
34
+
35
+ def read
36
+ @data || Hash.new
37
+ end
38
+
39
+ def data=(hash)
40
+ @data = hash
41
+ end
42
+ end
43
+ end
44
+
45
+ describe Kitchen::Config do
46
+
47
+ let(:loader) { Kitchen::DummyLoader.new }
48
+ let(:config) { Kitchen::Config.new(:loader => loader) }
49
+
50
+ before do
51
+ FakeFS.activate!
52
+ FileUtils.mkdir_p("/tmp")
53
+ end
54
+
55
+ after do
56
+ FakeFS.deactivate!
57
+ FakeFS::FileSystem.clear
58
+ end
59
+
60
+ describe "#platforms" do
61
+
62
+ it "returns platforms loaded from a kitchen.yml" do
63
+ stub_data!({ :platforms => [{ :name => 'one' }, { :name => 'two' }] })
64
+
65
+ config.platforms.size.must_equal 2
66
+ config.platforms[0].name.must_equal 'one'
67
+ config.platforms[1].name.must_equal 'two'
68
+ end
69
+
70
+ it "returns an empty Array if no platforms are given" do
71
+ stub_data!({})
72
+
73
+ config.platforms.must_equal []
74
+ end
75
+ end
76
+
77
+ describe "#suites" do
78
+
79
+ it "returns suites loaded from a kitchen.yml" do
80
+ stub_data!({ :suites => [
81
+ { :name => 'one', :run_list => [] },
82
+ { :name => 'two', :run_list => [] },
83
+ ] })
84
+
85
+ config.suites.size.must_equal 2
86
+ config.suites[0].name.must_equal 'one'
87
+ config.suites[1].name.must_equal 'two'
88
+ end
89
+
90
+ it "returns an empty Array if no suites are given" do
91
+ stub_data!({})
92
+
93
+ config.suites.must_equal []
94
+ end
95
+
96
+ it "returns a suite with nil for data_bags_path by default" do
97
+ stub_data!({ :suites => [{ :name => 'one', :run_list => [] }] })
98
+ config.suites.first.data_bags_path.must_be_nil
99
+ end
100
+
101
+ it "retuns a suite with a common data_bags_path set" do
102
+ stub_data!({ :suites => [{ :name => 'one', :run_list => [] }] })
103
+ config.test_base_path = "/tmp/base"
104
+ FileUtils.mkdir_p "/tmp/base/data_bags"
105
+
106
+ config.suites.first.data_bags_path.must_equal "/tmp/base/data_bags"
107
+ end
108
+
109
+ it "retuns a suite with a suite-specific data_bags_path set" do
110
+ stub_data!({ :suites => [{ :name => 'cool', :run_list => [] }] })
111
+ config.test_base_path = "/tmp/base"
112
+ FileUtils.mkdir_p "/tmp/base/cool/data_bags"
113
+ config.suites.first.data_bags_path.must_equal "/tmp/base/cool/data_bags"
114
+ end
115
+
116
+ it "returns a suite with nil for roles_path by default" do
117
+ stub_data!({ :suites => [{ :name => 'one', :run_list => [] }] })
118
+ config.suites.first.roles_path.must_be_nil
119
+ end
120
+
121
+ it "returns a suite with a common roles_path set" do
122
+ stub_data!({ :suites => [{ :name => 'one', :run_list => [] }] })
123
+ config.test_base_path = "/tmp/base"
124
+ FileUtils.mkdir_p "/tmp/base/roles"
125
+ config.suites.first.roles_path.must_equal "/tmp/base/roles"
126
+ end
127
+
128
+ it "returns a suite with a suite-specific roles_path set" do
129
+ stub_data!({ :suites => [{ :name => 'mysuite', :run_list => [] }] })
130
+ config.test_base_path = "/tmp/base"
131
+ FileUtils.mkdir_p "/tmp/base/mysuite/roles"
132
+ config.suites.first.roles_path.must_equal "/tmp/base/mysuite/roles"
133
+ end
134
+ end
135
+
136
+ describe "#instances" do
137
+
138
+ it "returns instances loaded from a kitchen.yml" do
139
+ stub_data!({
140
+ :platforms => [
141
+ { :name => 'p1' },
142
+ { :name => 'p2' },
143
+ ],
144
+ :suites => [
145
+ { :name => 's1', :run_list => [] },
146
+ { :name => 's2', :run_list => [] },
147
+ { :name => 's3', :run_list => [], :excludes => ['p1'] }
148
+ ]
149
+ })
150
+ config.instances.size.must_equal 5
151
+ config.instances.map { |i| i.name }.must_equal %w{s1-p1 s1-p2 s2-p1 s2-p2 s3-p2}
152
+ end
153
+
154
+ it "returns an instance containing a driver instance" do
155
+ stub_data!({
156
+ :platforms => [{ :name => 'platform', :driver_plugin => 'dummy' }],
157
+ :suites => [{ :name => 'suite', :run_list => [] }]
158
+ })
159
+ config.instances.first.driver.must_be_instance_of Kitchen::Driver::Dummy
160
+ end
161
+
162
+ it "returns an instance with a driver initialized with kitchen_root" do
163
+ config.kitchen_root = "/tmp"
164
+ stub_data!({
165
+ :platforms => [{ :name => 'platform', :driver_plugin => 'dummy' }],
166
+ :suites => [{ :name => 'suite', :run_list => [] }]
167
+ })
168
+ config.instances.first.driver[:kitchen_root].must_equal "/tmp"
169
+ end
170
+
171
+ it "returns an instance with a driver initialized with passed in config" do
172
+ stub_data!({
173
+ :platforms => [
174
+ { :name => 'platform', :driver_plugin => 'dummy',
175
+ :driver_config => { :foo => 'bar' }
176
+ }
177
+ ],
178
+ :suites => [{ :name => 'suite', :run_list => [] }]
179
+ })
180
+ config.instances.first.driver[:foo].must_equal "bar"
181
+ end
182
+ end
183
+
184
+ describe "#log_level" do
185
+
186
+ it "returns a default log_level of info" do
187
+ config.log_level.must_equal :info
188
+ end
189
+
190
+ it "returns an overridden log_level" do
191
+ config.log_level = :error
192
+ config.log_level.must_equal :error
193
+ end
194
+ end
195
+
196
+ private
197
+
198
+ def stub_data!(hash)
199
+ loader.data = hash
200
+ end
201
+ end
@@ -0,0 +1,191 @@
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 'logger'
21
+ require 'stringio'
22
+
23
+ require 'kitchen/driver/dummy'
24
+
25
+ describe Kitchen::Driver::Dummy do
26
+
27
+ let(:logged_output) { StringIO.new }
28
+ let(:logger) { Logger.new(logged_output) }
29
+ let(:config) { Hash.new }
30
+ let(:state) { Hash.new }
31
+
32
+ let(:instance) do
33
+ stub(:name => "coolbeans", :logger => logger, :to_str => "instance")
34
+ end
35
+
36
+ let(:driver) do
37
+ d = Kitchen::Driver::Dummy.new(config)
38
+ d.instance = instance
39
+ d
40
+ end
41
+
42
+ describe "default_config" do
43
+
44
+ it "sets :sleep to 0 by default" do
45
+ driver[:sleep].must_equal 0
46
+ end
47
+
48
+ it "sets :random_failure to false by default" do
49
+ driver[:random_failure].must_equal false
50
+ end
51
+ end
52
+
53
+ describe "#create" do
54
+
55
+ it "sets :my_id to a unique value as an example" do
56
+ driver.create(state)
57
+
58
+ state[:my_id].must_match /^coolbeans-/
59
+ end
60
+
61
+ it "calls sleep if :sleep value is greater than 0" do
62
+ config[:sleep] = 12.5
63
+ driver.expects(:sleep).with(12.5).returns(true)
64
+
65
+ driver.create(state)
66
+ end
67
+
68
+ it "randomly raises ActionFailed if :random_failure is set" do
69
+ config[:random_failure] = true
70
+ driver.stubs(:randomly_fail?).returns(true)
71
+
72
+ proc { driver.create(state) }.must_raise Kitchen::ActionFailed
73
+ end
74
+
75
+ it "will only raise ActionFailed if :random_failure is set" do
76
+ config[:random_failure] = true
77
+
78
+ begin
79
+ driver.create(state)
80
+ rescue Kitchen::ActionFailed => ex
81
+ # If exception is anything other than Kitchen::ActionFailed, this spec
82
+ # will fail
83
+ end
84
+ end
85
+
86
+ it "logs a create event to INFO" do
87
+ driver.create(state)
88
+
89
+ logged_output.string.must_match /^.+ INFO .+ \[Dummy\] Create on .+$/
90
+ end
91
+ end
92
+
93
+ describe "#converge" do
94
+
95
+ it "calls sleep if :sleep value is greater than 0" do
96
+ config[:sleep] = 12.5
97
+ driver.expects(:sleep).with(12.5).returns(true)
98
+
99
+ driver.create(state)
100
+ end
101
+
102
+ it "randomly raises ActionFailed if :random_failure is set" do
103
+ config[:random_failure] = true
104
+ driver.stubs(:randomly_fail?).returns(true)
105
+
106
+ proc { driver.converge(state) }.must_raise Kitchen::ActionFailed
107
+ end
108
+
109
+ it "logs a converge event to INFO" do
110
+ driver.converge(state)
111
+
112
+ logged_output.string.must_match /^.+ INFO .+ \[Dummy\] Converge on .+$/
113
+ end
114
+ end
115
+
116
+ describe "#setup" do
117
+
118
+ it "calls sleep if :sleep value is greater than 0" do
119
+ config[:sleep] = 12.5
120
+ driver.expects(:sleep).with(12.5).returns(true)
121
+
122
+ driver.setup(state)
123
+ end
124
+
125
+ it "randomly raises ActionFailed if :random_failure is set" do
126
+ config[:random_failure] = true
127
+ driver.stubs(:randomly_fail?).returns(true)
128
+
129
+ proc { driver.setup(state) }.must_raise Kitchen::ActionFailed
130
+ end
131
+
132
+ it "logs a setup event to INFO" do
133
+ driver.setup(state)
134
+
135
+ logged_output.string.must_match /^.+ INFO .+ \[Dummy\] Setup on .+$/
136
+ end
137
+ end
138
+
139
+ describe "#verify" do
140
+
141
+ it "calls sleep if :sleep value is greater than 0" do
142
+ config[:sleep] = 12.5
143
+ driver.expects(:sleep).with(12.5).returns(true)
144
+
145
+ driver.verify(state)
146
+ end
147
+
148
+ it "randomly raises ActionFailed if :random_failure is set" do
149
+ config[:random_failure] = true
150
+ driver.stubs(:randomly_fail?).returns(true)
151
+
152
+ proc { driver.verify(state) }.must_raise Kitchen::ActionFailed
153
+ end
154
+
155
+ it "logs a verify event to INFO" do
156
+ driver.verify(state)
157
+
158
+ logged_output.string.must_match /^.+ INFO .+ \[Dummy\] Verify on .+$/
159
+ end
160
+ end
161
+
162
+ describe "#destroy" do
163
+
164
+ it "removes :my_id from the state hash" do
165
+ state[:my_id] = "90210"
166
+ driver.destroy(state)
167
+
168
+ state[:my_id].must_be_nil
169
+ end
170
+
171
+ it "calls sleep if :sleep value is greater than 0" do
172
+ config[:sleep] = 12.5
173
+ driver.expects(:sleep).with(12.5).returns(true)
174
+
175
+ driver.verify(state)
176
+ end
177
+
178
+ it "randomly raises ActionFailed if :random_failure is set" do
179
+ config[:random_failure] = true
180
+ driver.stubs(:randomly_fail?).returns(true)
181
+
182
+ proc { driver.destroy(state) }.must_raise Kitchen::ActionFailed
183
+ end
184
+
185
+ it "logs a destroy event to INFO" do
186
+ driver.destroy(state)
187
+
188
+ logged_output.string.must_match /^.+ INFO .+ \[Dummy\] Destroy on .+$/
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,162 @@
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 'logger'
21
+ require 'stringio'
22
+
23
+ require 'kitchen/logging'
24
+ require 'kitchen/instance'
25
+ require 'kitchen/driver'
26
+ require 'kitchen/driver/dummy'
27
+ require 'kitchen/platform'
28
+ require 'kitchen/suite'
29
+
30
+ describe Kitchen::Instance do
31
+
32
+ let(:suite) do
33
+ Kitchen::Suite.new({ :name => 'suite',
34
+ :run_list => 'suite_list', :attributes => { :s => 'ss' } })
35
+ end
36
+
37
+ let(:platform) do
38
+ Kitchen::Platform.new({ :name => 'platform',
39
+ :run_list => 'platform_list', :attributes => { :p => 'pp' } })
40
+ end
41
+
42
+ let(:driver) { Kitchen::Driver::Dummy.new({}) }
43
+
44
+ let(:opts) do
45
+ { :suite => suite, :platform => platform, :driver => driver }
46
+ end
47
+
48
+ let(:instance) { Kitchen::Instance.new(opts) }
49
+
50
+ before do
51
+ Celluloid.logger = Logger.new(StringIO.new)
52
+ end
53
+
54
+ it "raises an ArgumentError if suite is missing" do
55
+ opts.delete(:suite)
56
+ proc { Kitchen::Instance.new(opts) }.must_raise Kitchen::ClientError
57
+ end
58
+
59
+ it "raises an ArgumentError if platform is missing" do
60
+ opts.delete(:platform)
61
+ proc { Kitchen::Instance.new(opts) }.must_raise Kitchen::ClientError
62
+ end
63
+
64
+ it "returns suite" do
65
+ instance.suite.must_equal suite
66
+ end
67
+
68
+ it "returns platform" do
69
+ instance.platform.must_equal platform
70
+ end
71
+
72
+ describe "#name" do
73
+
74
+ def combo(suite_name, platform_name)
75
+ opts[:suite] = Kitchen::Suite.new(
76
+ :name => suite_name, :run_list => []
77
+ )
78
+ opts[:platform] = Kitchen::Platform.new(
79
+ :name => platform_name
80
+ )
81
+ Kitchen::Instance.new(opts)
82
+ end
83
+
84
+ it "combines the suite and platform names with a dash" do
85
+ combo('suite', 'platform').name.must_equal "suite-platform"
86
+ end
87
+
88
+ it "squashes periods" do
89
+ combo('suite.ness', 'platform').name.must_equal "suiteness-platform"
90
+ combo('suite', 'platform.s').name.must_equal "suite-platforms"
91
+ combo('s.s.', '.p.p').name.must_equal "ss-pp"
92
+ end
93
+
94
+ it "transforms underscores to dashes" do
95
+ combo('suite_ness', 'platform').name.must_equal "suite-ness-platform"
96
+ combo('suite', 'platform-s').name.must_equal "suite-platform-s"
97
+ combo('_s__s_', 'pp_').name.must_equal "-s--s--pp-"
98
+ end
99
+ end
100
+
101
+ describe "#run_list" do
102
+
103
+ def combo(suite_list, platform_list)
104
+ opts[:suite] = Kitchen::Suite.new(
105
+ :name => 'suite', :run_list => suite_list
106
+ )
107
+ opts[:platform] = Kitchen::Platform.new(
108
+ :name => 'platform', :run_list => platform_list
109
+ )
110
+ Kitchen::Instance.new(opts)
111
+ end
112
+
113
+ it "combines the platform then suite run_lists" do
114
+ combo(%w{s1 s2}, %w{p1 p2}).run_list.must_equal %w{p1 p2 s1 s2}
115
+ end
116
+
117
+ it "uses the suite run_list only when platform run_list is empty" do
118
+ combo(%w{sa sb}, nil).run_list.must_equal %w{sa sb}
119
+ end
120
+
121
+ it "returns an emtpy Array if both run_lists are empty" do
122
+ combo([], nil).run_list.must_equal []
123
+ end
124
+ end
125
+
126
+ describe "#attributes" do
127
+
128
+ def combo(suite_attrs, platform_attrs)
129
+ opts[:suite] = Kitchen::Suite.new(
130
+ :name => 'suite', :run_list => [], :attributes => suite_attrs
131
+ )
132
+ opts[:platform] = Kitchen::Platform.new(
133
+ :name => 'platform', :attributes => platform_attrs
134
+ )
135
+ Kitchen::Instance.new(opts)
136
+ end
137
+
138
+ it "merges suite and platform hashes together" do
139
+ combo(
140
+ { :suite => { :s1 => 'sv1' } },
141
+ { :suite => { :p1 => 'pv1' }, :platform => 'pp' }
142
+ ).attributes.must_equal({
143
+ :suite => { :s1 => 'sv1', :p1 => 'pv1' },
144
+ :platform => 'pp'
145
+ })
146
+ end
147
+
148
+ it "merges suite values over platform values" do
149
+ combo(
150
+ { :common => { :c1 => 'xxx' } },
151
+ { :common => { :c1 => 'cv1', :c2 => 'cv2' } },
152
+ ).attributes.must_equal({
153
+ :common => { :c1 => 'xxx', :c2 => 'cv2' }
154
+ })
155
+ end
156
+ end
157
+
158
+ it "#dna combines attributes with the run_list" do
159
+ instance.dna.must_equal({ :s => 'ss', :p => 'pp',
160
+ :run_list => ['platform_list', 'suite_list'] })
161
+ end
162
+ end