chef 10.28.2 → 10.30.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/lib/chef.rb +1 -0
  2. data/lib/chef/application/knife.rb +2 -0
  3. data/lib/chef/client.rb +1 -1
  4. data/lib/chef/config.rb +5 -1
  5. data/lib/chef/cookbook_uploader.rb +7 -14
  6. data/lib/chef/data_bag.rb +2 -3
  7. data/lib/chef/exceptions.rb +9 -1
  8. data/lib/chef/formatters/error_inspectors/registration_error_inspector.rb +4 -0
  9. data/lib/chef/knife.rb +3 -0
  10. data/lib/chef/mixin/deep_merge.rb +53 -21
  11. data/lib/chef/monkey_patches/net_http.rb +34 -0
  12. data/lib/chef/monkey_patches/uri.rb +70 -0
  13. data/lib/chef/node.rb +5 -5
  14. data/lib/chef/platform.rb +1 -0
  15. data/lib/chef/provider/cookbook_file.rb +14 -6
  16. data/lib/chef/provider/directory.rb +16 -10
  17. data/lib/chef/provider/file.rb +23 -17
  18. data/lib/chef/provider/group.rb +50 -31
  19. data/lib/chef/provider/group/dscl.rb +26 -4
  20. data/lib/chef/provider/group/gpasswd.rb +14 -19
  21. data/lib/chef/provider/group/groupadd.rb +41 -1
  22. data/lib/chef/provider/group/groupmod.rb +46 -36
  23. data/lib/chef/provider/group/pw.rb +59 -16
  24. data/lib/chef/provider/group/suse.rb +16 -13
  25. data/lib/chef/provider/group/usermod.rb +40 -18
  26. data/lib/chef/provider/group/windows.rb +13 -6
  27. data/lib/chef/provider/package/yum.rb +1 -0
  28. data/lib/chef/provider/remote_file.rb +8 -2
  29. data/lib/chef/provider/ruby_block.rb +1 -1
  30. data/lib/chef/provider/template.rb +11 -5
  31. data/lib/chef/provider/user/useradd.rb +9 -1
  32. data/lib/chef/provider/whyrun_safe_ruby_block.rb +30 -0
  33. data/lib/chef/providers.rb +1 -0
  34. data/lib/chef/resource/group.rb +11 -1
  35. data/lib/chef/resource/whyrun_safe_ruby_block.rb +31 -0
  36. data/lib/chef/resources.rb +1 -0
  37. data/lib/chef/rest.rb +6 -2
  38. data/lib/chef/rest/rest_request.rb +6 -2
  39. data/lib/chef/util/windows/net_group.rb +5 -1
  40. data/lib/chef/version.rb +1 -1
  41. data/spec/functional/resource/base.rb +40 -0
  42. data/spec/functional/resource/group_spec.rb +343 -0
  43. data/spec/spec_helper.rb +4 -0
  44. data/spec/support/platform_helpers.rb +17 -0
  45. data/spec/unit/client_spec.rb +1 -1
  46. data/spec/unit/data_bag_spec.rb +4 -6
  47. data/spec/unit/mixin/deep_merge_spec.rb +416 -190
  48. data/spec/unit/monkey_patches/uri_spec.rb +34 -0
  49. data/spec/unit/node/attribute_spec.rb +49 -14
  50. data/spec/unit/node_spec.rb +31 -0
  51. data/spec/unit/provider/file_spec.rb +27 -27
  52. data/spec/unit/provider/group/dscl_spec.rb +1 -0
  53. data/spec/unit/provider/group/gpasswd_spec.rb +16 -9
  54. data/spec/unit/provider/group/groupadd_spec.rb +3 -4
  55. data/spec/unit/provider/group/groupmod_spec.rb +0 -1
  56. data/spec/unit/provider/group/pw_spec.rb +12 -15
  57. data/spec/unit/provider/group/usermod_spec.rb +21 -6
  58. data/spec/unit/provider/group/windows_spec.rb +0 -8
  59. data/spec/unit/provider/group_spec.rb +26 -4
  60. data/spec/unit/provider/user/useradd_spec.rb +21 -0
  61. data/spec/unit/provider/whyrun_safe_ruby_block_spec.rb +47 -0
  62. data/spec/unit/rest_spec.rb +55 -22
  63. metadata +119 -44
  64. checksums.yaml +0 -7
data/spec/spec_helper.rb CHANGED
@@ -69,11 +69,15 @@ RSpec.configure do |config|
69
69
 
70
70
  # Add jruby filters here
71
71
  config.filter_run_excluding :windows_only => true unless windows?
72
+ config.filter_run_excluding :not_supported_on_mac_osx_106 => true if mac_osx_106?
73
+ config.filter_run_excluding :solaris_only => true unless solaris?
72
74
  config.filter_run_excluding :not_supported_on_win2k3 => true if windows_win2k3?
75
+ config.filter_run_excluding :not_supported_on_solaris => true if solaris?
73
76
  config.filter_run_excluding :unix_only => true unless unix?
74
77
  config.filter_run_excluding :ruby_18_only => true unless ruby_18?
75
78
  config.filter_run_excluding :ruby_19_only => true unless ruby_19?
76
79
  config.filter_run_excluding :requires_root => true unless ENV['USER'] == 'root'
80
+ config.filter_run_excluding :requires_root_or_running_windows => true unless (ENV['USER'] == 'root' || windows?)
77
81
  config.filter_run_excluding :requires_unprivileged_user => true if ENV['USER'] == 'root'
78
82
  config.filter_run_excluding :uses_diff => true unless has_diff?
79
83
 
@@ -1,3 +1,7 @@
1
+ require 'chef/mixin/shell_out'
2
+
3
+ include Chef::Mixin::ShellOut
4
+
1
5
  def ruby_19?
2
6
  !!(RUBY_VERSION =~ /^1.9/)
3
7
  end
@@ -18,6 +22,19 @@ def windows_win2k3?
18
22
  (host.version && host.version.start_with?("5.2"))
19
23
  end
20
24
 
25
+ def mac_osx_106?
26
+ if File.exists? "/usr/bin/sw_vers"
27
+ result = shell_out("/usr/bin/sw_vers")
28
+ result.stdout.each_line do |line|
29
+ if line =~ /^ProductVersion:\s10.6.*$/
30
+ return true
31
+ end
32
+ end
33
+ end
34
+
35
+ false
36
+ end
37
+
21
38
  # def jruby?
22
39
 
23
40
  def unix?
@@ -128,7 +128,7 @@ shared_examples_for Chef::Client do
128
128
  @client.should_receive(:run_started)
129
129
  @client.should_receive(:run_completed_successfully)
130
130
 
131
- if(Chef::Config[:client_fork])
131
+ if(Chef::Config[:client_fork] && !windows?)
132
132
  require 'stringio'
133
133
  if(Chef::Config[:pipe_node])
134
134
  pipe_sim = StringIO.new
@@ -76,14 +76,13 @@ describe Chef::DataBag do
76
76
  Chef::REST.stub!(:new).and_return(@rest)
77
77
  end
78
78
 
79
- it "should update the data bag when it already exists" do
80
- @rest.should_receive(:put_rest).with("data/piggly_wiggly", @data_bag)
79
+ it "should silently proceed when the data bag already exists" do
80
+ exception = mock("409 error", :code => "409")
81
+ @rest.should_receive(:post_rest).and_raise(Net::HTTPServerException.new("foo", exception))
81
82
  @data_bag.save
82
83
  end
83
84
 
84
- it "should create the data bag when it is not found" do
85
- exception = mock("404 error", :code => "404")
86
- @rest.should_receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception))
85
+ it "should create the data bag" do
87
86
  @rest.should_receive(:post_rest).with("data", @data_bag)
88
87
  @data_bag.save
89
88
  end
@@ -96,7 +95,6 @@ describe Chef::DataBag do
96
95
  Chef::Config[:why_run] = false
97
96
  end
98
97
  it "should not save" do
99
- @rest.should_not_receive(:put_rest)
100
98
  @rest.should_not_receive(:post_rest)
101
99
  @data_bag.save
102
100
  end
@@ -75,81 +75,290 @@ describe Chef::Mixin::DeepMerge, "deep_merge!" do
75
75
  hash_dst.should == hash_src
76
76
  end
77
77
 
78
- it "tests hashes holding array" do
79
- hash_src = {"property" => ["1","3"]}
80
- hash_dst = {"property" => ["2","4"]}
81
- @dm.deep_merge!(hash_src, hash_dst)
82
- hash_dst.should == {"property" => ["2","4","1","3"]}
83
- end
84
-
85
- it "tests hashes holding array (sorted)" do
86
- hash_src = {"property" => ["1","3"]}
87
- hash_dst = {"property" => ["2","4"]}
88
- @dm.deep_merge!(hash_src, hash_dst, {:sort_merged_arrays => true})
89
- hash_dst.should == {"property" => ["1","2","3","4"]}
90
- end
91
-
92
- it "tests hashes holding hashes holding arrays (array with duplicate elements is merged with dest then src" do
93
- hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
94
- hash_dst = {"property" => {"bedroom_count" => ["3", "2"], "bathroom_count" => ["2"]}}
95
- @dm.deep_merge!(hash_src, hash_dst)
96
- hash_dst.should == {"property" => {"bedroom_count" => ["3","2","1"], "bathroom_count" => ["2", "1", "4+"]}}
97
- end
98
-
99
- it "tests hash holding hash holding array v string (string is overwritten by array)" do
100
- hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
101
- hash_dst = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2"]}}
102
- @dm.deep_merge!(hash_src, hash_dst)
103
- hash_dst.should == {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}}
104
- end
105
-
106
- it "tests hash holding hash holding array v string (string is NOT overwritten by array)" do
107
- hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
108
- hash_dst = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2"]}}
109
- @dm.deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
110
- hash_dst.should == {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2","1","4+"]}}
111
- end
112
-
113
- it "tests hash holding hash holding string v array (array is overwritten by string)" do
114
- hash_src = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["1", "4+"]}}
115
- hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
116
- @dm.deep_merge!(hash_src, hash_dst)
117
- hash_dst.should == {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2","1","4+"]}}
118
- end
119
-
120
- it "tests hash holding hash holding string v array (array does NOT overwrite string)" do
121
- hash_src = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["1", "4+"]}}
122
- hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
123
- @dm.deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
124
- hash_dst.should == {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}}
125
- end
126
-
127
- it "tests hash holding hash holding hash v array (array is overwritten by hash)" do
128
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
129
- hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
130
- @dm.deep_merge!(hash_src, hash_dst)
131
- hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}}
132
- end
78
+ context "while merging arrays" do
79
+ it ":deep_merge_array_concat should be set by default" do
80
+ Chef::Config[:deep_merge_array_concat].should == true
81
+ end
133
82
 
134
- it "tests hash holding hash holding hash v array (array is NOT overwritten by hash)" do
135
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
136
- hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
137
- @dm.deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
138
- hash_dst.should == {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}}
139
- end
83
+ context "when :deep_merge_array_concat is set" do
84
+ before do
85
+ Chef::Config.stub!(:[]).with(:deep_merge_array_concat).and_return(true)
86
+ end
87
+
88
+ it "tests hashes holding array" do
89
+ hash_src = {"property" => ["1","3"]}
90
+ hash_dst = {"property" => ["2","4"]}
91
+ @dm.deep_merge!(hash_src, hash_dst)
92
+ hash_dst.should == {"property" => ["1","3"]}
93
+ end
94
+
95
+ it "tests hashes holding array (sorted)" do
96
+ hash_src = {"property" => ["3","1"]}
97
+ hash_dst = {"property" => ["2","4"]}
98
+ @dm.deep_merge!(hash_src, hash_dst, {:sort_merged_arrays => true})
99
+ hash_dst.should == {"property" => ["1","3"]}
100
+ end
101
+
102
+ it "tests hashes holding hashes holding arrays (array with duplicate elements are preserved)" do
103
+ hash_src = {"property" => {"bedroom_count" => ["1", "2", "2"], "bathroom_count" => ["1", "4+"]}}
104
+ hash_dst = {"property" => {"bedroom_count" => ["3", "2"], "bathroom_count" => ["2"]}}
105
+ @dm.deep_merge!(hash_src, hash_dst)
106
+ hash_dst.should == {"property" => {"bedroom_count" => ["1","2","2"], "bathroom_count" => ["1", "4+"]}}
107
+ end
108
+
109
+ it "tests 3 hash layers holding arrays of int (src arrays are picked)" do
110
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["1", "4+"]}}
111
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
112
+ @dm.deep_merge!(hash_src, hash_dst)
113
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["1","4+"]}}
114
+ end
115
+
116
+ it "tests 3 hash layers holding arrays of int (src arrays are picked) but second hash's array is overwritten" do
117
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
118
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
119
+ @dm.deep_merge!(hash_src, hash_dst)
120
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
121
+ end
122
+
123
+ it "tests 3 hash layers holding arrays of int (src arrays are picked) but second hash's array is NOT overwritten" do
124
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
125
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
126
+ @dm.deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
127
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["2"]}}
128
+ end
129
+
130
+ it "tests 3 hash layers holding arrays of int, but one holds int. This one overwrites, but src are picked for the rest" do
131
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [1]}, "bathroom_count" => ["1"]}}
132
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
133
+ @dm.deep_merge!(hash_src, hash_dst)
134
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [1]}, "bathroom_count" => ["1"]}}
135
+ end
136
+
137
+ it "tests 3 hash layers holding arrays of int, but source is incomplete." do
138
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3]}, "bathroom_count" => ["1"]}}
139
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
140
+ @dm.deep_merge!(hash_src, hash_dst)
141
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [4]}, "bathroom_count" => ["1"]}}
142
+ end
143
+
144
+ it "tests 3 hash layers holding arrays of int, but source is shorter and has new 2nd level ints." do
145
+ hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
146
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
147
+ @dm.deep_merge!(hash_src, hash_dst)
148
+ hash_dst.should == {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3], "queen_bed" => [4]}, "bathroom_count" => ["1"]}}
149
+ end
150
+
151
+ # KNOCKOUT_PREFIX testing
152
+ # the next few tests are looking for correct behavior from specific real-world params/session merges
153
+ # using the custom modifiers built for param/session merges
154
+
155
+ [nil, ","].each do |ko_split|
156
+ it "tests typical params/session style hash with knockout_merge elements" do
157
+ hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
158
+ hash_dst = {"property"=>{"bedroom_count"=>["1", "2", "3"]}}
159
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
160
+ hash_dst.should == {"property"=>{"bedroom_count"=>["2", "3"]}}
161
+ end
162
+
163
+ it "tests typical params/session style hash with knockout_merge elements" do
164
+ hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
165
+ hash_dst = {"property"=>{"bedroom_count"=>["3"]}}
166
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
167
+ hash_dst.should == {"property"=>{"bedroom_count"=>["2","3"]}}
168
+ end
169
+
170
+ it "tests typical params/session style hash with knockout_merge elements" do
171
+ hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
172
+ hash_dst = {"property"=>{"bedroom_count"=>["4"]}}
173
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
174
+ hash_dst.should == {"property"=>{"bedroom_count"=>["2","3"]}}
175
+ end
176
+
177
+ it "tests typical params/session style hash with knockout_merge elements" do
178
+ hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
179
+ hash_dst = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "4"]}}
180
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
181
+ hash_dst.should == {"property"=>{"bedroom_count"=>["2","3"]}}
182
+ end
183
+
184
+ it "tests typical params/session style hash with knockout_merge elements" do
185
+ hash_src = {"amenity"=>{"id"=>[@field_ko_prefix+":1", @field_ko_prefix+":2", "3", "4"]}}
186
+ hash_dst = {"amenity"=>{"id"=>["1", "2"]}}
187
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
188
+ hash_dst.should == {"amenity"=>{"id"=>["3","4"]}}
189
+ end
190
+ end
191
+
192
+ it "tests same as previous but without ko_split value, this merge should fail" do
193
+ hash_src = {"amenity"=>{"id"=>[@field_ko_prefix+":1,"+@field_ko_prefix+":2", "3,4"]}}
194
+ hash_dst = {"amenity"=>{"id"=>["1", "2"]}}
195
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix})
196
+ hash_dst.should == {"amenity"=>{"id"=>["3,4"]}}
197
+ end
198
+
199
+ it "tests edge test: make sure that when we turn off knockout_prefix that all values are processed correctly" do
200
+ hash_src = {"region" => {'ids' => ["7", @field_ko_prefix, "2", "6,8"]}}
201
+ hash_dst = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
202
+ @dm.deep_merge!(hash_src, hash_dst, {:unpack_arrays => ","})
203
+ hash_dst.should == {'region' => {'ids' => ["7", @field_ko_prefix, "2", "6", "8"], 'id'=>'11'}}
204
+ end
205
+
206
+ it "tests edge test 2: make sure that when we turn off source array split that all values are processed correctly" do
207
+ hash_src = {"region" => {'ids' => ["7", "3", @field_ko_prefix, "6,8"]}}
208
+ hash_dst = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
209
+ @dm.deep_merge!(hash_src, hash_dst)
210
+ hash_dst.should == {'region' => {'ids' => ["7", "3", @field_ko_prefix, "6,8"], 'id'=>'11'}}
211
+ end
212
+
213
+ it "tests hash of array of hashes" do
214
+ hash_src = {"item" => [{"1" => "3"}, {"2" => "4"}]}
215
+ hash_dst = {"item" => [{"3" => "5"}]}
216
+ @dm.deep_merge!(hash_src, hash_dst)
217
+ hash_dst.should == {"item" => [{"1" => "3"}, {"2" => "4"}]}
218
+ end
140
219
 
141
- it "tests 3 hash layers holding integers (integers are overwritten by source)" do
142
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
143
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => 2, "queen_bed" => 4}, "bathroom_count" => ["2"]}}
144
- @dm.deep_merge!(hash_src, hash_dst)
145
- hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}}
146
- end
220
+ end
147
221
 
148
- it "tests 3 hash layers holding arrays of int (arrays are merged)" do
149
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["1", "4+"]}}
150
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
151
- @dm.deep_merge!(hash_src, hash_dst)
152
- hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2","1","4+"]}}
222
+ # These tests ensure that deep_merge behavior didn't change when
223
+ # the config option disables the array merging during deep merge
224
+ # while fixing CHEF-4631.
225
+ context "when :deep_merge_array_concat is not set" do
226
+ before do
227
+ Chef::Config.stub!(:[]).with(:deep_merge_array_concat).and_return(false)
228
+ end
229
+
230
+ it "tests hashes holding array" do
231
+ hash_src = {"property" => ["1","3"]}
232
+ hash_dst = {"property" => ["2","4"]}
233
+ @dm.deep_merge!(hash_src, hash_dst)
234
+ hash_dst.should == {"property" => ["2","4","1","3"]}
235
+ end
236
+
237
+ it "tests hashes holding array (sorted)" do
238
+ hash_src = {"property" => ["1","3"]}
239
+ hash_dst = {"property" => ["2","4"]}
240
+ @dm.deep_merge!(hash_src, hash_dst, {:sort_merged_arrays => true})
241
+ hash_dst.should == {"property" => ["1","2","3","4"]}
242
+ end
243
+
244
+ it "tests hashes holding hashes holding arrays (array with duplicate elements is merged with dest then src" do
245
+ hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
246
+ hash_dst = {"property" => {"bedroom_count" => ["3", "2"], "bathroom_count" => ["2"]}}
247
+ @dm.deep_merge!(hash_src, hash_dst)
248
+ hash_dst.should == {"property" => {"bedroom_count" => ["3","2","1"], "bathroom_count" => ["2", "1", "4+"]}}
249
+ end
250
+
251
+ it "tests 3 hash layers holding arrays of int (arrays are merged)" do
252
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["1", "4+"]}}
253
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
254
+ @dm.deep_merge!(hash_src, hash_dst)
255
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2","1","4+"]}}
256
+ end
257
+
258
+ it "tests 3 hash layers holding arrays of int (arrays are merged) but second hash's array is overwritten" do
259
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
260
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
261
+ @dm.deep_merge!(hash_src, hash_dst)
262
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => "1"}}
263
+ end
264
+
265
+ it "tests 3 hash layers holding arrays of int (arrays are merged) but second hash's array is NOT overwritten" do
266
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
267
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
268
+ @dm.deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
269
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2"]}}
270
+ end
271
+
272
+ it "tests 3 hash layers holding arrays of int, but one holds int. This one overwrites, but the rest merge" do
273
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [1]}, "bathroom_count" => ["1"]}}
274
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
275
+ @dm.deep_merge!(hash_src, hash_dst)
276
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [4,1]}, "bathroom_count" => ["2","1"]}}
277
+ end
278
+
279
+ it "tests 3 hash layers holding arrays of int, but source is incomplete." do
280
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3]}, "bathroom_count" => ["1"]}}
281
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
282
+ @dm.deep_merge!(hash_src, hash_dst)
283
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}}
284
+ end
285
+
286
+ it "tests 3 hash layers holding arrays of int, but source is shorter and has new 2nd level ints." do
287
+ hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
288
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
289
+ @dm.deep_merge!(hash_src, hash_dst)
290
+ hash_dst.should == {"property" => {"bedroom_count" => {2=>3, "king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}}
291
+ end
292
+
293
+ # KNOCKOUT_PREFIX testing
294
+ # the next few tests are looking for correct behavior from specific real-world params/session merges
295
+ # using the custom modifiers built for param/session merges
296
+
297
+ [nil, ","].each do |ko_split|
298
+ it "tests typical params/session style hash with knockout_merge elements" do
299
+ hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
300
+ hash_dst = {"property"=>{"bedroom_count"=>["1", "2", "3"]}}
301
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
302
+ hash_dst.should == {"property"=>{"bedroom_count"=>["2", "3"]}}
303
+ end
304
+
305
+ it "tests typical params/session style hash with knockout_merge elements" do
306
+ hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
307
+ hash_dst = {"property"=>{"bedroom_count"=>["3"]}}
308
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
309
+ hash_dst.should == {"property"=>{"bedroom_count"=>["3","2"]}}
310
+ end
311
+
312
+ it "tests typical params/session style hash with knockout_merge elements" do
313
+ hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
314
+ hash_dst = {"property"=>{"bedroom_count"=>["4"]}}
315
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
316
+ hash_dst.should == {"property"=>{"bedroom_count"=>["4","2","3"]}}
317
+ end
318
+
319
+ it "tests typical params/session style hash with knockout_merge elements" do
320
+ hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
321
+ hash_dst = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "4"]}}
322
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
323
+ hash_dst.should == {"property"=>{"bedroom_count"=>["4","2","3"]}}
324
+ end
325
+
326
+ it "tests typical params/session style hash with knockout_merge elements" do
327
+ hash_src = {"amenity"=>{"id"=>[@field_ko_prefix+":1", @field_ko_prefix+":2", "3", "4"]}}
328
+ hash_dst = {"amenity"=>{"id"=>["1", "2"]}}
329
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
330
+ hash_dst.should == {"amenity"=>{"id"=>["3","4"]}}
331
+ end
332
+ end
333
+
334
+ it "tests same as previous but without ko_split value, this merge should fail" do
335
+ hash_src = {"amenity"=>{"id"=>[@field_ko_prefix+":1,"+@field_ko_prefix+":2", "3,4"]}}
336
+ hash_dst = {"amenity"=>{"id"=>["1", "2"]}}
337
+ @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix})
338
+ hash_dst.should == {"amenity"=>{"id"=>["1","2","3,4"]}}
339
+ end
340
+
341
+ it "tests edge test: make sure that when we turn off knockout_prefix that all values are processed correctly" do
342
+ hash_src = {"region" => {'ids' => ["7", @field_ko_prefix, "2", "6,8"]}}
343
+ hash_dst = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
344
+ @dm.deep_merge!(hash_src, hash_dst, {:unpack_arrays => ","})
345
+ hash_dst.should == {'region' => {'ids' => ["1", "2", "3", "4", "7", @field_ko_prefix, "6", "8"], 'id'=>'11'}}
346
+ end
347
+
348
+ it "tests edge test 2: make sure that when we turn off source array split that all values are processed correctly" do
349
+ hash_src = {"region" => {'ids' => ["7", "3", @field_ko_prefix, "6,8"]}}
350
+ hash_dst = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
351
+ @dm.deep_merge!(hash_src, hash_dst)
352
+ hash_dst.should == {'region' => {'ids' => ["1", "2", "3", "4", "7", @field_ko_prefix, "6,8"], 'id'=>'11'}}
353
+ end
354
+
355
+ it "tests hash of array of hashes" do
356
+ hash_src = {"item" => [{"1" => "3"}, {"2" => "4"}]}
357
+ hash_dst = {"item" => [{"3" => "5"}]}
358
+ @dm.deep_merge!(hash_src, hash_dst)
359
+ hash_dst.should == {"item" => [{"3" => "5"}, {"1" => "3"}, {"2" => "4"}]}
360
+ end
361
+ end
153
362
  end
154
363
 
155
364
  it "tests 1 hash overwriting 3 hash layers holding arrays of int" do
@@ -166,53 +375,67 @@ describe Chef::Mixin::DeepMerge, "deep_merge!" do
166
375
  hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
167
376
  end
168
377
 
169
- it "tests 3 hash layers holding arrays of int (arrays are merged) but second hash's array is overwritten" do
170
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
378
+ it "tests 3 hash layers holding arrays of int, but source is empty" do
379
+ hash_src = {}
171
380
  hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
172
381
  @dm.deep_merge!(hash_src, hash_dst)
173
- hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => "1"}}
382
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
174
383
  end
175
384
 
176
- it "tests 3 hash layers holding arrays of int (arrays are merged) but second hash's array is NOT overwritten" do
177
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
178
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
179
- @dm.deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
180
- hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2"]}}
385
+ it "tests 3 hash layers holding arrays of int, but dest is empty" do
386
+ hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
387
+ hash_dst = {}
388
+ @dm.deep_merge!(hash_src, hash_dst)
389
+ hash_dst.should == {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
181
390
  end
182
391
 
183
- it "tests 3 hash layers holding arrays of int, but one holds int. This one overwrites, but the rest merge" do
184
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [1]}, "bathroom_count" => ["1"]}}
185
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
392
+ it "tests hash holding hash holding array v string (string is overwritten by array)" do
393
+ hash_src = {"property" => {"bedroom_count" => ["1", "2"]}}
394
+ hash_dst = {"property" => {"bedroom_count" => "3"}}
186
395
  @dm.deep_merge!(hash_src, hash_dst)
187
- hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [4,1]}, "bathroom_count" => ["2","1"]}}
396
+ hash_dst.should == {"property" => {"bedroom_count" => ["1", "2"]}}
188
397
  end
189
398
 
190
- it "tests 3 hash layers holding arrays of int, but source is incomplete." do
191
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3]}, "bathroom_count" => ["1"]}}
192
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
193
- @dm.deep_merge!(hash_src, hash_dst)
194
- hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}}
399
+ it "tests hash holding hash holding array v string (string is NOT overwritten by array)" do
400
+ hash_src = {"property" => {"bedroom_count" => ["1", "2"]}}
401
+ hash_dst = {"property" => {"bedroom_count" => "3"}}
402
+ @dm.deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
403
+ hash_dst.should == {"property" => {"bedroom_count" => "3"}}
195
404
  end
196
405
 
197
- it "tests 3 hash layers holding arrays of int, but source is shorter and has new 2nd level ints." do
198
- hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
199
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
406
+ it "tests hash holding hash holding string v array (array is overwritten by string)" do
407
+ hash_src = {"property" => {"bedroom_count" => "3"}}
408
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"]}}
200
409
  @dm.deep_merge!(hash_src, hash_dst)
201
- hash_dst.should == {"property" => {"bedroom_count" => {2=>3, "king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}}
410
+ hash_dst.should == {"property" => {"bedroom_count" => "3"}}
202
411
  end
203
412
 
204
- it "tests 3 hash layers holding arrays of int, but source is empty" do
205
- hash_src = {}
206
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
413
+ it "tests hash holding hash holding string v array (array does NOT overwrite string)" do
414
+ hash_src = {"property" => {"bedroom_count" => "3"}}
415
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"]}}
416
+ @dm.deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
417
+ hash_dst.should == {"property" => {"bedroom_count" => ["1", "2"]}}
418
+ end
419
+
420
+ it "tests hash holding hash holding hash v array (array is overwritten by hash)" do
421
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}}}
422
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"]}}
207
423
  @dm.deep_merge!(hash_src, hash_dst)
208
- hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
424
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}}}
209
425
  end
210
426
 
211
- it "tests 3 hash layers holding arrays of int, but dest is empty" do
212
- hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
213
- hash_dst = {}
427
+ it "tests hash holding hash holding hash v array (array is NOT overwritten by hash)" do
428
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}}}
429
+ hash_dst = {"property" => {"bedroom_count" => ["1", "2"]}}
430
+ @dm.deep_merge!(hash_src, hash_dst, {:preserve_unmergeables => true})
431
+ hash_dst.should == {"property" => {"bedroom_count" => ["1", "2"]}}
432
+ end
433
+
434
+ it "tests 3 hash layers holding integers (integers are overwritten by source)" do
435
+ hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}}}
436
+ hash_dst = {"property" => {"bedroom_count" => {"king_bed" => 2, "queen_bed" => 4}}}
214
437
  @dm.deep_merge!(hash_src, hash_dst)
215
- hash_dst.should == {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
438
+ hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}}}
216
439
  end
217
440
 
218
441
  it "tests parameter management for knockout_prefix and overwrite unmergable" do
@@ -268,47 +491,6 @@ describe Chef::Mixin::DeepMerge, "deep_merge!" do
268
491
  hash_dst.should == hash_src
269
492
  end
270
493
 
271
- # KNOCKOUT_PREFIX testing
272
- # the next few tests are looking for correct behavior from specific real-world params/session merges
273
- # using the custom modifiers built for param/session merges
274
-
275
- [nil, ","].each do |ko_split|
276
- it "tests typical params/session style hash with knockout_merge elements" do
277
- hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
278
- hash_dst = {"property"=>{"bedroom_count"=>["1", "2", "3"]}}
279
- @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
280
- hash_dst.should == {"property"=>{"bedroom_count"=>["2", "3"]}}
281
- end
282
-
283
- it "tests typical params/session style hash with knockout_merge elements" do
284
- hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
285
- hash_dst = {"property"=>{"bedroom_count"=>["3"]}}
286
- @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
287
- hash_dst.should == {"property"=>{"bedroom_count"=>["3","2"]}}
288
- end
289
-
290
- it "tests typical params/session style hash with knockout_merge elements" do
291
- hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
292
- hash_dst = {"property"=>{"bedroom_count"=>["4"]}}
293
- @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
294
- hash_dst.should == {"property"=>{"bedroom_count"=>["4","2","3"]}}
295
- end
296
-
297
- it "tests typical params/session style hash with knockout_merge elements" do
298
- hash_src = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "2", "3"]}}
299
- hash_dst = {"property"=>{"bedroom_count"=>[@field_ko_prefix+":1", "4"]}}
300
- @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
301
- hash_dst.should == {"property"=>{"bedroom_count"=>["4","2","3"]}}
302
- end
303
-
304
- it "tests typical params/session style hash with knockout_merge elements" do
305
- hash_src = {"amenity"=>{"id"=>[@field_ko_prefix+":1", @field_ko_prefix+":2", "3", "4"]}}
306
- hash_dst = {"amenity"=>{"id"=>["1", "2"]}}
307
- @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix, :unpack_arrays => ko_split})
308
- hash_dst.should == {"amenity"=>{"id"=>["3","4"]}}
309
- end
310
- end
311
-
312
494
  it "tests special params/session style hash with knockout_merge elements in form src: [\"1\",\"2\"] dest:[\"@ko:1,@ko:2\", \"3,4\"]" do
313
495
  hash_src = {"amenity"=>{"id"=>[@field_ko_prefix+":1,"+@field_ko_prefix+":2", "3,4"]}}
314
496
  hash_dst = {"amenity"=>{"id"=>["1", "2"]}}
@@ -316,13 +498,6 @@ describe Chef::Mixin::DeepMerge, "deep_merge!" do
316
498
  hash_dst.should == {"amenity"=>{"id"=>["3","4"]}}
317
499
  end
318
500
 
319
- it "tests same as previous but without ko_split value, this merge should fail" do
320
- hash_src = {"amenity"=>{"id"=>[@field_ko_prefix+":1,"+@field_ko_prefix+":2", "3,4"]}}
321
- hash_dst = {"amenity"=>{"id"=>["1", "2"]}}
322
- @dm.deep_merge!(hash_src, hash_dst, {:knockout_prefix => @field_ko_prefix})
323
- hash_dst.should == {"amenity"=>{"id"=>["1","2","3,4"]}}
324
- end
325
-
326
501
  it "tests special params/session style hash with knockout_merge elements in form src: [\"1\",\"2\"] dest:[\"@ko:1,@ko:2\", \"3,4\"]" do
327
502
  hash_src = {"amenity"=>{"id"=>[@field_ko_prefix+":1,2", "3,4", @field_ko_prefix+":5", "6"]}}
328
503
  hash_dst = {"amenity"=>{"id"=>["1", "2"]}}
@@ -501,20 +676,6 @@ describe Chef::Mixin::DeepMerge, "deep_merge!" do
501
676
  hash_dst.should == {'region' => {'ids' => ["7", "6"], 'id'=>'11'}}
502
677
  end
503
678
 
504
- it "tests edge test: make sure that when we turn off knockout_prefix that all values are processed correctly" do
505
- hash_src = {"region" => {'ids' => ["7", @field_ko_prefix, "2", "6,8"]}}
506
- hash_dst = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
507
- @dm.deep_merge!(hash_src, hash_dst, {:unpack_arrays => ","})
508
- hash_dst.should == {'region' => {'ids' => ["1", "2", "3", "4", "7", @field_ko_prefix, "6", "8"], 'id'=>'11'}}
509
- end
510
-
511
- it "tests edge test 2: make sure that when we turn off source array split that all values are processed correctly" do
512
- hash_src = {"region" => {'ids' => ["7", "3", @field_ko_prefix, "6,8"]}}
513
- hash_dst = {"region"=>{"ids"=>["1", "2", "3", "4"], 'id'=>'11'}}
514
- @dm.deep_merge!(hash_src, hash_dst)
515
- hash_dst.should == {'region' => {'ids' => ["1", "2", "3", "4", "7", @field_ko_prefix, "6,8"], 'id'=>'11'}}
516
- end
517
-
518
679
  it "tests Example: src = {'key' => \"@ko:1\"}, dst = {'key' => \"1\"} -> merges to {'key' => \"\"}" do
519
680
  hash_src = {"amenity"=>@field_ko_prefix+":1"}
520
681
  hash_dst = {"amenity"=>"1"}
@@ -662,13 +823,6 @@ describe Chef::Mixin::DeepMerge, "deep_merge!" do
662
823
  hash_dst.should == {"query_uuid"=>"a0dc3c84-ec7f-6756-bdb0-fff9157438ab", "url_regions"=>[], "region"=>{"muni_city_id"=>"", "id"=>""}, "property"=>{"property_type_id"=>"", "search_rate_min"=>"", "search_rate_max"=>""}, "task"=>"search", "run_query"=>"Search"}
663
824
  end
664
825
 
665
- it "tests hash of array of hashes" do
666
- hash_src = {"item" => [{"1" => "3"}, {"2" => "4"}]}
667
- hash_dst = {"item" => [{"3" => "5"}]}
668
- @dm.deep_merge!(hash_src, hash_dst)
669
- hash_dst.should == {"item" => [{"3" => "5"}, {"1" => "3"}, {"2" => "4"}]}
670
- end
671
-
672
826
  # Additions since import
673
827
  it "should overwrite true with false when merging boolean values" do
674
828
  hash_src = {"valid" => false}
@@ -724,10 +878,66 @@ describe Chef::Mixin::DeepMerge do
724
878
  @dm.merge(hash_dst, hash_src).should == {"name" => "value"}
725
879
  end
726
880
 
727
- it "should merge arrays within hashes" do
728
- hash_dst = {"property" => ["2","4"]}
729
- hash_src = {"property" => ["1","3"]}
730
- @dm.merge(hash_dst, hash_src).should == {"property" => ["2","4","1","3"]}
881
+ context "when :deep_merge_array_concat is set" do
882
+ before do
883
+ Chef::Config.stub!(:[]).with(:deep_merge_array_concat).and_return(true)
884
+ end
885
+
886
+ it "should pick src arrays within hashes" do
887
+ hash_dst = {"property" => ["2","4"]}
888
+ hash_src = {"property" => ["1","3"]}
889
+ @dm.merge(hash_dst, hash_src).should == {"property" => ["1","3"]}
890
+ end
891
+
892
+ it "should not modify the source or destination during the merge" do
893
+ hash_dst = {"property" => ["1","2","3"]}
894
+ hash_src = {"property" => ["4","5","6"]}
895
+ ret = @dm.merge(hash_dst, hash_src)
896
+ hash_dst.should == {"property" => ["1","2","3"]}
897
+ hash_src.should == {"property" => ["4","5","6"]}
898
+ ret.should == {"property" => ["4","5","6"]}
899
+ end
900
+
901
+ it "should not knockout matching array value when merging arrays within hashes" do
902
+ hash_dst = {"property" => ["2","4"]}
903
+ hash_src = {"property" => ["1","!merge:4"]}
904
+ hash_src_no_colon = {"property" => ["1","!merge"]}
905
+ @dm.merge(hash_dst, hash_src).should == {"property" => ["1", "!merge:4"]}
906
+ @dm.merge(hash_dst, hash_src_no_colon).should == {"property" => ["1", "!merge"]}
907
+ end
908
+ end
909
+
910
+ # These tests ensure that deep_merge behavior didn't change when
911
+ # the config option disables the array merging during deep merge
912
+ # while fixing CHEF-4631.
913
+ context "when :deep_merge_array_concat is not set" do
914
+ before do
915
+ Chef::Config.stub!(:[]).with(:deep_merge_array_concat).and_return(false)
916
+ end
917
+
918
+ it "should merge arrays within hashes" do
919
+ hash_dst = {"property" => ["2","4"]}
920
+ hash_src = {"property" => ["1","3"]}
921
+ @dm.merge(hash_dst, hash_src).should == {"property" => ["2","4","1","3"]}
922
+ end
923
+
924
+ it "should not modify the source or destination during the merge" do
925
+ hash_dst = {"property" => ["1","2","3"]}
926
+ hash_src = {"property" => ["4","5","6"]}
927
+ ret = @dm.merge(hash_dst, hash_src)
928
+ hash_dst.should == {"property" => ["1","2","3"]}
929
+ hash_src.should == {"property" => ["4","5","6"]}
930
+ ret.should == {"property" => ["1","2","3","4","5","6"]}
931
+ end
932
+
933
+ it "should not knockout matching array value when merging arrays within hashes" do
934
+ hash_dst = {"property" => ["2","4"]}
935
+ hash_src = {"property" => ["1","!merge:4"]}
936
+ hash_src_no_colon = {"property" => ["1","!merge"]}
937
+ @dm.merge(hash_dst, hash_src).should == {"property" => ["2", "4", "1", "!merge:4"]}
938
+ @dm.merge(hash_dst, hash_src_no_colon).should == {"property" => ["2", "4", "1", "!merge"]}
939
+ end
940
+
731
941
  end
732
942
 
733
943
  it "should merge deeply nested hashes" do
@@ -736,22 +946,6 @@ describe Chef::Mixin::DeepMerge do
736
946
  @dm.merge(hash_dst, hash_src).should == {"property" => {"values" => {"are" => "stable", "can" => "change", "may" => "rise"}}}
737
947
  end
738
948
 
739
- it "should not modify the source or destination during the merge" do
740
- hash_dst = {"property" => ["1","2","3"]}
741
- hash_src = {"property" => ["4","5","6"]}
742
- ret = @dm.merge(hash_dst, hash_src)
743
- hash_dst.should == {"property" => ["1","2","3"]}
744
- hash_src.should == {"property" => ["4","5","6"]}
745
- ret.should == {"property" => ["1","2","3","4","5","6"]}
746
- end
747
-
748
- it "should not knockout matching array value when merging arrays within hashes" do
749
- hash_dst = {"property" => ["2","4"]}
750
- hash_src = {"property" => ["1","!merge:4"]}
751
- hash_src_no_colon = {"property" => ["1","!merge"]}
752
- @dm.merge(hash_dst, hash_src).should == {"property" => ["2", "4", "1", "!merge:4"]}
753
- @dm.merge(hash_dst, hash_src_no_colon).should == {"property" => ["2", "4", "1", "!merge"]}
754
- end
755
949
  end
756
950
 
757
951
  describe "role_merge" do
@@ -782,5 +976,37 @@ describe Chef::Mixin::DeepMerge do
782
976
  hash_src = {"property" => ["1","!merge:4"]}
783
977
  @dm.role_merge(hash_dst, hash_src).should == {"property" => ["2","1"]}
784
978
  end
979
+
980
+ it "should concat arrays" do
981
+ hash_dst = {"property" => ["2","4"]}
982
+ hash_src = {"property" => ["1","4"]}
983
+ @dm.role_merge(hash_dst, hash_src).should == {"property" => ["2","4", "1","4"]}
984
+ end
985
+ end
986
+
987
+ describe "horizontal_merge" do
988
+ it "should concat arrays" do
989
+ hash_dst = {"property" => ["2","4"]}
990
+ hash_src = {"property" => ["1","3"]}
991
+ @dm.horizontal_merge(hash_dst, hash_src).should == {"property" => ["2","4", "1","3"]}
992
+ end
993
+
994
+ it "should concat arrays without removing same elements" do
995
+ hash_dst = {"property" => ["2","4"]}
996
+ hash_src = {"property" => ["1","2"]}
997
+ @dm.horizontal_merge(hash_dst, hash_src).should == {"property" => ["2","4", "1","2"]}
998
+ end
999
+
1000
+ it "should be able to merge array values with an empty hash as source" do
1001
+ hash_dst = {"property" => ["2","4"]}
1002
+ hash_src = {}
1003
+ @dm.horizontal_merge(hash_dst, hash_src).should == {"property" => ["2","4"]}
1004
+ end
1005
+
1006
+ it "should be able to merge array values with an empty hash as dest" do
1007
+ hash_dst = {}
1008
+ hash_src = {"property" => ["2","4"]}
1009
+ @dm.horizontal_merge(hash_dst, hash_src).should == {"property" => ["2","4"]}
1010
+ end
785
1011
  end
786
1012
  end