microwave 1.0.4 → 11.400.2

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 (249) hide show
  1. data/CONTRIBUTING.md +155 -0
  2. data/README.md +89 -0
  3. data/Rakefile +2 -2
  4. data/bin/chef-apply +25 -0
  5. data/bin/chef-shell +34 -0
  6. data/bin/chef-solo +0 -2
  7. data/bin/shef +6 -5
  8. data/lib/chef.rb +2 -4
  9. data/spec/data/big_json.json +2 -1
  10. data/spec/data/big_json_plus_one.json +2 -1
  11. data/spec/data/cookbooks/chefignore +2 -0
  12. data/spec/data/cookbooks/openldap/attributes/default.rb +10 -9
  13. data/spec/data/cookbooks/openldap/attributes/smokey.rb +1 -1
  14. data/spec/data/git_bundles/sinatra-test-app-with-callback-files.gitbundle +0 -0
  15. data/spec/data/git_bundles/sinatra-test-app-with-symlinks.gitbundle +0 -0
  16. data/spec/data/git_bundles/sinatra-test-app.gitbundle +0 -0
  17. data/spec/data/lwrp/providers/inline_compiler.rb +26 -0
  18. data/spec/data/nodes/default.rb +3 -3
  19. data/spec/data/nodes/test.example.com.rb +3 -3
  20. data/spec/data/nodes/test.rb +3 -3
  21. data/spec/data/partial_one.erb +1 -0
  22. data/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb +4 -0
  23. data/spec/data/run_context/cookbooks/circular-dep1/definitions/circular_dep1_res.rb +1 -0
  24. data/spec/data/run_context/cookbooks/circular-dep1/libraries/lib.rb +2 -0
  25. data/spec/data/run_context/cookbooks/circular-dep1/metadata.rb +2 -0
  26. data/spec/data/run_context/cookbooks/circular-dep1/providers/provider.rb +1 -0
  27. data/spec/data/run_context/cookbooks/circular-dep1/recipes/default.rb +0 -0
  28. data/spec/data/run_context/cookbooks/circular-dep1/resources/resource.rb +1 -0
  29. data/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb +3 -0
  30. data/spec/data/run_context/cookbooks/circular-dep2/definitions/circular_dep2_res.rb +1 -0
  31. data/spec/data/run_context/cookbooks/circular-dep2/libraries/lib.rb +2 -0
  32. data/spec/data/run_context/cookbooks/circular-dep2/metadata.rb +2 -0
  33. data/spec/data/run_context/cookbooks/circular-dep2/providers/provider.rb +1 -0
  34. data/spec/data/run_context/cookbooks/circular-dep2/recipes/default.rb +0 -0
  35. data/spec/data/run_context/cookbooks/circular-dep2/resources/resource.rb +1 -0
  36. data/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb +2 -0
  37. data/spec/data/run_context/cookbooks/dependency1/attributes/default.rb +2 -0
  38. data/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb +3 -0
  39. data/spec/data/run_context/cookbooks/dependency1/definitions/dependency1_res.rb +1 -0
  40. data/spec/data/run_context/cookbooks/dependency1/libraries/lib.rb +2 -0
  41. data/spec/data/run_context/cookbooks/dependency1/providers/provider.rb +1 -0
  42. data/spec/data/run_context/cookbooks/dependency1/recipes/default.rb +0 -0
  43. data/spec/data/run_context/cookbooks/dependency1/resources/resource.rb +1 -0
  44. data/spec/data/run_context/cookbooks/dependency2/attributes/default.rb +3 -0
  45. data/spec/data/run_context/cookbooks/dependency2/definitions/dependency2_res.rb +1 -0
  46. data/spec/data/run_context/cookbooks/dependency2/libraries/lib.rb +2 -0
  47. data/spec/data/run_context/cookbooks/dependency2/providers/provider.rb +1 -0
  48. data/spec/data/run_context/cookbooks/dependency2/recipes/default.rb +0 -0
  49. data/spec/data/run_context/cookbooks/dependency2/resources/resource.rb +1 -0
  50. data/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb +3 -0
  51. data/spec/data/run_context/cookbooks/no-default-attr/definitions/no_default-attr_res.rb +1 -0
  52. data/spec/data/run_context/cookbooks/no-default-attr/providers/provider.rb +1 -0
  53. data/spec/data/run_context/cookbooks/no-default-attr/recipes/default.rb +0 -0
  54. data/spec/data/run_context/cookbooks/no-default-attr/resources/resource.rb +1 -0
  55. data/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb +3 -0
  56. data/spec/data/run_context/cookbooks/test-with-circular-deps/definitions/test_with-circular-deps_res.rb +1 -0
  57. data/spec/data/run_context/cookbooks/test-with-circular-deps/libraries/lib.rb +2 -0
  58. data/spec/data/run_context/cookbooks/test-with-circular-deps/metadata.rb +2 -0
  59. data/spec/data/run_context/cookbooks/test-with-circular-deps/providers/provider.rb +1 -0
  60. data/spec/data/run_context/cookbooks/test-with-circular-deps/recipes/default.rb +0 -0
  61. data/spec/data/run_context/cookbooks/test-with-circular-deps/resources/resource.rb +1 -0
  62. data/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb +3 -0
  63. data/spec/data/run_context/cookbooks/test-with-deps/definitions/test_with-deps_res.rb +1 -0
  64. data/spec/data/run_context/cookbooks/test-with-deps/libraries/lib.rb +1 -0
  65. data/spec/data/run_context/cookbooks/test-with-deps/metadata.rb +3 -0
  66. data/spec/data/run_context/cookbooks/test-with-deps/providers/provider.rb +1 -0
  67. data/spec/data/run_context/cookbooks/test-with-deps/recipes/default.rb +0 -0
  68. data/spec/data/run_context/cookbooks/test-with-deps/recipes/server.rb +0 -0
  69. data/spec/data/run_context/cookbooks/test-with-deps/resources/resource.rb +1 -0
  70. data/spec/data/run_context/cookbooks/test/attributes/default.rb +0 -0
  71. data/spec/data/run_context/cookbooks/test/attributes/george.rb +1 -1
  72. data/spec/data/run_context/cookbooks/test/definitions/test_res.rb +1 -0
  73. data/spec/data/run_context/cookbooks/test/providers/provider.rb +1 -0
  74. data/spec/data/run_context/cookbooks/test/resources/resource.rb +1 -0
  75. data/spec/data/shef-config.rb +10 -0
  76. data/spec/functional/dsl/registry_helper_spec.rb +63 -0
  77. data/spec/functional/knife/cookbook_delete_spec.rb +0 -2
  78. data/spec/functional/knife/exec_spec.rb +4 -6
  79. data/spec/functional/knife/smoke_test.rb +34 -0
  80. data/spec/functional/knife/ssh_spec.rb +64 -3
  81. data/spec/functional/resource/cookbook_file_spec.rb +33 -2
  82. data/spec/functional/resource/deploy_revision_spec.rb +515 -0
  83. data/spec/functional/resource/directory_spec.rb +4 -0
  84. data/spec/functional/resource/file_spec.rb +56 -22
  85. data/spec/functional/resource/link_spec.rb +12 -10
  86. data/spec/functional/resource/registry_spec.rb +572 -0
  87. data/spec/functional/resource/remote_directory_spec.rb +142 -36
  88. data/spec/functional/resource/remote_file_spec.rb +28 -3
  89. data/spec/functional/resource/template_spec.rb +23 -2
  90. data/spec/functional/run_lock_spec.rb +238 -0
  91. data/spec/functional/shell_spec.rb +101 -0
  92. data/spec/functional/tiny_server_spec.rb +5 -4
  93. data/spec/functional/win32/registry_helper_spec.rb +632 -0
  94. data/spec/functional/win32/security_spec.rb +37 -0
  95. data/spec/spec_helper.rb +15 -3
  96. data/spec/stress/win32/security_spec.rb +5 -5
  97. data/spec/support/chef_helpers.rb +14 -3
  98. data/spec/support/lib/chef/resource/cat.rb +3 -5
  99. data/spec/support/lib/chef/resource/one_two_three_four.rb +8 -10
  100. data/spec/support/lib/chef/resource/zen_master.rb +8 -10
  101. data/spec/support/matchers/leak.rb +1 -1
  102. data/spec/support/platform_helpers.rb +18 -0
  103. data/spec/support/shared/functional/directory_resource.rb +85 -23
  104. data/spec/support/shared/functional/file_resource.rb +198 -53
  105. data/spec/support/shared/functional/securable_resource.rb +140 -105
  106. data/spec/support/shared/functional/securable_resource_with_reporting.rb +375 -0
  107. data/spec/support/shared/unit/file_system_support.rb +110 -0
  108. data/spec/support/shared/unit/platform_introspector.rb +162 -0
  109. data/spec/tiny_server.rb +29 -10
  110. data/spec/unit/api_client/registration_spec.rb +172 -0
  111. data/spec/unit/api_client_spec.rb +156 -103
  112. data/spec/unit/application/apply.rb +84 -0
  113. data/spec/unit/application/knife_spec.rb +5 -0
  114. data/spec/unit/application_spec.rb +57 -2
  115. data/spec/unit/chef_fs/diff_spec.rb +329 -0
  116. data/spec/unit/chef_fs/file_pattern_spec.rb +526 -0
  117. data/spec/unit/chef_fs/file_system/chef_server_root_dir_spec.rb +237 -0
  118. data/spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb +568 -0
  119. data/spec/unit/chef_fs/file_system/data_bags_dir_spec.rb +220 -0
  120. data/spec/unit/chef_fs/file_system_spec.rb +136 -0
  121. data/spec/unit/client_spec.rb +188 -16
  122. data/spec/unit/config_spec.rb +54 -4
  123. data/spec/unit/cookbook/chefignore_spec.rb +2 -1
  124. data/spec/unit/cookbook/syntax_check_spec.rb +48 -109
  125. data/spec/unit/cookbook_loader_spec.rb +153 -91
  126. data/spec/unit/cookbook_manifest_spec.rb +81 -81
  127. data/spec/unit/cookbook_spec.rb +3 -20
  128. data/spec/unit/cookbook_version_spec.rb +23 -122
  129. data/spec/unit/digester_spec.rb +50 -0
  130. data/spec/unit/dsl/data_query_spec.rb +66 -0
  131. data/spec/unit/dsl/platform_introspection_spec.rb +130 -0
  132. data/spec/unit/dsl/regsitry_helper_spec.rb +55 -0
  133. data/spec/unit/encrypted_data_bag_item_spec.rb +126 -10
  134. data/spec/unit/environment_spec.rb +0 -130
  135. data/spec/unit/exceptions_spec.rb +2 -3
  136. data/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb +23 -3
  137. data/spec/unit/json_compat_spec.rb +69 -0
  138. data/spec/unit/knife/bootstrap_spec.rb +81 -28
  139. data/spec/unit/knife/client_reregister_spec.rb +23 -22
  140. data/spec/unit/knife/configure_spec.rb +29 -26
  141. data/spec/unit/knife/cookbook_metadata_spec.rb +11 -4
  142. data/spec/unit/knife/cookbook_site_install_spec.rb +12 -2
  143. data/spec/unit/knife/cookbook_test_spec.rb +1 -0
  144. data/spec/unit/knife/cookbook_upload_spec.rb +41 -2
  145. data/spec/unit/knife/core/bootstrap_context_spec.rb +8 -1
  146. data/spec/unit/knife/core/ui_spec.rb +156 -7
  147. data/spec/unit/knife/data_bag_create_spec.rb +14 -0
  148. data/spec/unit/knife/data_bag_edit_spec.rb +14 -4
  149. data/spec/unit/knife/data_bag_from_file_spec.rb +17 -5
  150. data/spec/unit/knife/data_bag_show_spec.rb +11 -4
  151. data/spec/unit/knife/index_rebuild_spec.rb +96 -33
  152. data/spec/unit/knife/knife_help.rb +7 -7
  153. data/spec/unit/knife/node_run_list_remove_spec.rb +2 -1
  154. data/spec/unit/knife/ssh_spec.rb +121 -15
  155. data/spec/unit/knife/status_spec.rb +2 -2
  156. data/spec/unit/knife/user_create_spec.rb +86 -0
  157. data/spec/unit/knife/user_delete_spec.rb +39 -0
  158. data/spec/unit/knife/user_edit_spec.rb +42 -0
  159. data/spec/unit/knife/user_list_spec.rb +32 -0
  160. data/spec/unit/knife/user_reregister_spec.rb +53 -0
  161. data/spec/unit/knife/user_show_spec.rb +41 -0
  162. data/spec/unit/knife_spec.rb +53 -0
  163. data/spec/unit/lwrp_spec.rb +59 -17
  164. data/spec/unit/mixin/checksum_spec.rb +2 -2
  165. data/spec/unit/mixin/deep_merge_spec.rb +56 -491
  166. data/spec/unit/mixin/deprecation_spec.rb +23 -0
  167. data/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb +6 -1
  168. data/spec/unit/mixin/params_validate_spec.rb +4 -2
  169. data/spec/unit/mixin/securable_spec.rb +5 -3
  170. data/spec/unit/mixin/template_spec.rb +119 -0
  171. data/spec/unit/node/attribute_spec.rb +272 -137
  172. data/spec/unit/node/immutable_collections_spec.rb +139 -0
  173. data/spec/unit/node_spec.rb +411 -339
  174. data/spec/unit/platform_spec.rb +8 -8
  175. data/spec/unit/provider/breakpoint_spec.rb +8 -8
  176. data/spec/unit/provider/cookbook_file_spec.rb +4 -8
  177. data/spec/unit/provider/deploy/revision_spec.rb +2 -8
  178. data/spec/unit/provider/deploy_spec.rb +6 -40
  179. data/spec/unit/provider/directory_spec.rb +103 -68
  180. data/spec/unit/provider/erl_call_spec.rb +0 -2
  181. data/spec/unit/provider/file_spec.rb +69 -59
  182. data/spec/unit/provider/git_spec.rb +0 -10
  183. data/spec/unit/provider/group/groupadd_spec.rb +1 -1
  184. data/spec/unit/provider/group/usermod_spec.rb +2 -2
  185. data/spec/unit/provider/http_request_spec.rb +28 -69
  186. data/spec/unit/provider/ifconfig_spec.rb +2 -2
  187. data/spec/unit/provider/link_spec.rb +1 -1
  188. data/spec/unit/provider/ohai_spec.rb +4 -4
  189. data/spec/unit/provider/package/apt_spec.rb +0 -1
  190. data/spec/unit/provider/package/ips_spec.rb +0 -1
  191. data/spec/unit/provider/package/rubygems_spec.rb +0 -18
  192. data/spec/unit/provider/package/yum_spec.rb +79 -15
  193. data/spec/unit/provider/package_spec.rb +7 -5
  194. data/spec/unit/provider/registry_key_spec.rb +269 -0
  195. data/spec/unit/provider/remote_directory_spec.rb +24 -7
  196. data/spec/unit/provider/remote_file_spec.rb +36 -0
  197. data/spec/unit/provider/route_spec.rb +3 -6
  198. data/spec/unit/provider/ruby_block_spec.rb +8 -0
  199. data/spec/unit/provider/service/arch_service_spec.rb +4 -4
  200. data/spec/unit/provider/service/debian_service_spec.rb +1 -1
  201. data/spec/unit/provider/service/freebsd_service_spec.rb +4 -4
  202. data/spec/unit/provider/service/init_service_spec.rb +26 -3
  203. data/spec/unit/provider/service/insserv_service_spec.rb +1 -1
  204. data/spec/unit/provider/service/invokercd_service_spec.rb +3 -3
  205. data/spec/unit/provider/service/redhat_spec.rb +1 -1
  206. data/spec/unit/provider/service/simple_service_spec.rb +3 -3
  207. data/spec/unit/provider/service/upstart_service_spec.rb +7 -7
  208. data/spec/unit/provider/service_spec.rb +2 -2
  209. data/spec/unit/provider/subversion_spec.rb +1 -1
  210. data/spec/unit/provider/template_spec.rb +35 -11
  211. data/spec/unit/provider/user/dscl_spec.rb +57 -31
  212. data/spec/unit/provider/user_spec.rb +7 -16
  213. data/spec/unit/provider_spec.rb +4 -3
  214. data/spec/unit/recipe_spec.rb +10 -8
  215. data/spec/unit/registry_helper_spec.rb +376 -0
  216. data/spec/unit/resource/log_spec.rb +9 -0
  217. data/spec/unit/resource/registry_key_spec.rb +171 -0
  218. data/spec/unit/resource/remote_file_spec.rb +21 -23
  219. data/spec/unit/resource/ruby_block_spec.rb +7 -3
  220. data/spec/unit/resource/service_spec.rb +11 -0
  221. data/spec/unit/resource_spec.rb +27 -4
  222. data/spec/unit/rest/auth_credentials_spec.rb +2 -14
  223. data/spec/unit/rest_spec.rb +122 -187
  224. data/spec/unit/run_context/cookbook_compiler_spec.rb +181 -0
  225. data/spec/unit/run_context_spec.rb +18 -4
  226. data/spec/unit/run_list_spec.rb +0 -209
  227. data/spec/unit/run_lock_spec.rb +37 -0
  228. data/spec/unit/runner_spec.rb +101 -2
  229. data/spec/unit/scan_access_control_spec.rb +4 -4
  230. data/spec/unit/{shef → shell}/model_wrapper_spec.rb +5 -5
  231. data/spec/unit/{shef/shef_ext_spec.rb → shell/shell_ext_spec.rb} +21 -21
  232. data/spec/unit/{shef/shef_session_spec.rb → shell/shell_session_spec.rb} +12 -12
  233. data/spec/unit/shell_out_spec.rb +18 -0
  234. data/spec/unit/{shef_spec.rb → shell_spec.rb} +20 -20
  235. data/spec/unit/user_spec.rb +255 -0
  236. metadata +162 -157
  237. data/README.rdoc +0 -177
  238. data/spec/unit/certificate_spec.rb +0 -76
  239. data/spec/unit/checksum_cache_spec.rb +0 -209
  240. data/spec/unit/checksum_spec.rb +0 -94
  241. data/spec/unit/couchdb_spec.rb +0 -274
  242. data/spec/unit/index_queue_spec.rb +0 -391
  243. data/spec/unit/json_compat_spect.rb +0 -53
  244. data/spec/unit/mixin/language_spec.rb +0 -305
  245. data/spec/unit/openid_registration_spec.rb +0 -153
  246. data/spec/unit/solr_query/query_transform_spec.rb +0 -454
  247. data/spec/unit/solr_query/solr_http_request_spec.rb +0 -244
  248. data/spec/unit/solr_query_spec.rb +0 -203
  249. data/spec/unit/webui_user_spec.rb +0 -238
@@ -0,0 +1,139 @@
1
+ #
2
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
3
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'spec_helper'
20
+ require "chef/node/immutable_collections"
21
+
22
+ describe Chef::Node::ImmutableMash do
23
+ before do
24
+ @data_in = {:top => {:second_level => "some value"},
25
+ "top_level_2" => %w[array of values],
26
+ :top_level_3 => [{:hash_array => 1, :hash_array_b => 2}],
27
+ :top_level_4 => {:level2 => {:key => "value"}}
28
+ }
29
+ @immutable_mash = Chef::Node::ImmutableMash.new(@data_in)
30
+ end
31
+
32
+ it "element references like regular hash" do
33
+ @immutable_mash[:top][:second_level].should == "some value"
34
+ end
35
+
36
+ it "elelment references like a regular Mash" do
37
+ @immutable_mash[:top_level_2].should == %w[array of values]
38
+ end
39
+
40
+ it "converts Hash-like inputs into ImmutableMash's" do
41
+ @immutable_mash[:top].should be_a(Chef::Node::ImmutableMash)
42
+ end
43
+
44
+ it "converts array inputs into ImmutableArray's" do
45
+ @immutable_mash[:top_level_2].should be_a(Chef::Node::ImmutableArray)
46
+ end
47
+
48
+ it "converts arrays of hashes to ImmutableArray's of ImmutableMashes" do
49
+ @immutable_mash[:top_level_3].first.should be_a(Chef::Node::ImmutableMash)
50
+ end
51
+
52
+ it "converts nested hashes to ImmutableMashes" do
53
+ @immutable_mash[:top_level_4].should be_a(Chef::Node::ImmutableMash)
54
+ @immutable_mash[:top_level_4][:level2].should be_a(Chef::Node::ImmutableMash)
55
+ end
56
+
57
+
58
+ [
59
+ :[]=,
60
+ :clear,
61
+ :default=,
62
+ :default_proc=,
63
+ :delete,
64
+ :delete_if,
65
+ :keep_if,
66
+ :merge!,
67
+ :update,
68
+ :reject!,
69
+ :replace,
70
+ :select!,
71
+ :shift
72
+ ].each do |mutator|
73
+ it "doesn't allow mutation via `#{mutator}'" do
74
+ lambda { @immutable_mash.send(mutator) }.should raise_error(Chef::Exceptions::ImmutableAttributeModification)
75
+ end
76
+ end
77
+
78
+ it "returns a mutable version of itself when duped" do
79
+ mutable = @immutable_mash.dup
80
+ mutable[:new_key] = :value
81
+ mutable[:new_key].should == :value
82
+ end
83
+
84
+ end
85
+
86
+ describe Chef::Node::ImmutableArray do
87
+
88
+ before do
89
+ @immutable_array = Chef::Node::ImmutableArray.new(%w[foo bar baz])
90
+ end
91
+
92
+ ##
93
+ # Note: other behaviors, such as immutibilizing input data, are tested along
94
+ # with ImmutableMash, above
95
+ ###
96
+
97
+ [
98
+ :<<,
99
+ :[]=,
100
+ :clear,
101
+ :collect!,
102
+ :compact!,
103
+ :default=,
104
+ :default_proc=,
105
+ :delete,
106
+ :delete_at,
107
+ :delete_if,
108
+ :fill,
109
+ :flatten!,
110
+ :insert,
111
+ :keep_if,
112
+ :map!,
113
+ :merge!,
114
+ :pop,
115
+ :push,
116
+ :update,
117
+ :reject!,
118
+ :reverse!,
119
+ :replace,
120
+ :select!,
121
+ :shift,
122
+ :slice!,
123
+ :sort!,
124
+ :sort_by!,
125
+ :uniq!,
126
+ :unshift
127
+ ].each do |mutator|
128
+ it "does not allow mutation via `#{mutator}" do
129
+ lambda { @immutable_array.send(mutator)}.should raise_error(Chef::Exceptions::ImmutableAttributeModification)
130
+ end
131
+ end
132
+
133
+ it "returns a mutable version of itself when duped" do
134
+ mutable = @immutable_array.dup
135
+ mutable[0] = :value
136
+ mutable[0].should == :value
137
+ end
138
+ end
139
+
@@ -20,10 +20,11 @@ require 'spec_helper'
20
20
  require 'ostruct'
21
21
 
22
22
  describe Chef::Node do
23
- before(:each) do
24
- Chef::Config.node_path(File.expand_path(File.join(CHEF_SPEC_DATA, "nodes")))
25
- @node = Chef::Node.new()
26
- end
23
+
24
+ let(:node) { Chef::Node.new() }
25
+ let(:platform_introspector) { node }
26
+
27
+ it_behaves_like "a platform introspector"
27
28
 
28
29
  it "creates a node and assigns it a name" do
29
30
  node = Chef::Node.build('solo-node')
@@ -39,36 +40,33 @@ describe Chef::Node do
39
40
  response = OpenStruct.new(:code => '404')
40
41
  exception = Net::HTTPServerException.new("404 not found", response)
41
42
  Chef::Node.stub!(:load).and_raise(exception)
42
- @node.name("created-node")
43
+ node.name("created-node")
43
44
  end
44
45
 
45
46
  it "creates a new node for find_or_create" do
46
- Chef::Node.stub!(:new).and_return(@node)
47
- @node.should_receive(:create).and_return(@node)
47
+ Chef::Node.stub!(:new).and_return(node)
48
+ node.should_receive(:create).and_return(node)
48
49
  node = Chef::Node.find_or_create("created-node")
49
50
  node.name.should == 'created-node'
50
- node.should equal(@node)
51
+ node.should equal(node)
51
52
  end
52
53
  end
53
54
 
54
55
  describe "when the node exists on the server" do
55
56
  before do
56
- @node.name('existing-node')
57
- Chef::Node.stub!(:load).and_return(@node)
57
+ node.name('existing-node')
58
+ Chef::Node.stub!(:load).and_return(node)
58
59
  end
59
60
 
60
61
  it "loads the node via the REST API for find_or_create" do
61
- Chef::Node.find_or_create('existing-node').should equal(@node)
62
+ Chef::Node.find_or_create('existing-node').should equal(node)
62
63
  end
63
64
  end
64
65
 
65
66
  describe "run_state" do
66
- it "should have a template_cache hash" do
67
- @node.run_state[:template_cache].should be_a_kind_of(Hash)
68
- end
69
-
70
- it "should have a seen_recipes hash" do
71
- @node.run_state[:seen_recipes].should be_a_kind_of(Hash)
67
+ it "is an empty hash" do
68
+ node.run_state.should respond_to(:keys)
69
+ node.run_state.should be_empty
72
70
  end
73
71
  end
74
72
 
@@ -81,180 +79,225 @@ describe Chef::Node do
81
79
 
82
80
  describe "name" do
83
81
  it "should allow you to set a name with name(something)" do
84
- lambda { @node.name("latte") }.should_not raise_error
82
+ lambda { node.name("latte") }.should_not raise_error
85
83
  end
86
84
 
87
85
  it "should return the name with name()" do
88
- @node.name("latte")
89
- @node.name.should eql("latte")
86
+ node.name("latte")
87
+ node.name.should eql("latte")
90
88
  end
91
89
 
92
90
  it "should always have a string for name" do
93
- lambda { @node.name(Hash.new) }.should raise_error(ArgumentError)
91
+ lambda { node.name(Hash.new) }.should raise_error(ArgumentError)
94
92
  end
95
93
 
96
94
  it "cannot be blank" do
97
- lambda { @node.name("")}.should raise_error(Chef::Exceptions::ValidationFailed)
95
+ lambda { node.name("")}.should raise_error(Chef::Exceptions::ValidationFailed)
98
96
  end
99
97
 
100
98
  it "should not accept name doesn't match /^[\-[:alnum:]_:.]+$/" do
101
- lambda { @node.name("space in it")}.should raise_error(Chef::Exceptions::ValidationFailed)
99
+ lambda { node.name("space in it")}.should raise_error(Chef::Exceptions::ValidationFailed)
102
100
  end
103
101
  end
104
102
 
105
103
  describe "chef_environment" do
106
104
  it "should set an environment with chef_environment(something)" do
107
- lambda { @node.chef_environment("latte") }.should_not raise_error
105
+ lambda { node.chef_environment("latte") }.should_not raise_error
108
106
  end
109
107
 
110
108
  it "should return the chef_environment with chef_environment()" do
111
- @node.chef_environment("latte")
112
- @node.chef_environment.should == "latte"
109
+ node.chef_environment("latte")
110
+ node.chef_environment.should == "latte"
113
111
  end
114
112
 
115
113
  it "should disallow non-strings" do
116
- lambda { @node.chef_environment(Hash.new) }.should raise_error(ArgumentError)
117
- lambda { @node.chef_environment(42) }.should raise_error(ArgumentError)
114
+ lambda { node.chef_environment(Hash.new) }.should raise_error(ArgumentError)
115
+ lambda { node.chef_environment(42) }.should raise_error(ArgumentError)
118
116
  end
119
117
 
120
118
  it "cannot be blank" do
121
- lambda { @node.chef_environment("")}.should raise_error(Chef::Exceptions::ValidationFailed)
119
+ lambda { node.chef_environment("")}.should raise_error(Chef::Exceptions::ValidationFailed)
122
120
  end
123
121
  end
124
122
 
125
123
  describe "attributes" do
126
- it "should be loaded from the node's cookbooks" do
127
- @cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks"))
128
- @node.cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(@cookbook_repo))
129
- @node.load_attributes
130
- @node.ldap_server.should eql("ops1prod")
131
- @node.ldap_basedn.should eql("dc=hjksolutions,dc=com")
132
- @node.ldap_replication_password.should eql("forsure")
133
- @node.smokey.should eql("robinson")
134
- end
135
-
136
124
  it "should have attributes" do
137
- @node.attribute.should be_a_kind_of(Hash)
125
+ node.attribute.should be_a_kind_of(Hash)
138
126
  end
139
127
 
140
128
  it "should allow attributes to be accessed by name or symbol directly on node[]" do
141
- @node.attribute["locust"] = "something"
142
- @node[:locust].should eql("something")
143
- @node["locust"].should eql("something")
129
+ node.default["locust"] = "something"
130
+ node[:locust].should eql("something")
131
+ node["locust"].should eql("something")
144
132
  end
145
133
 
146
134
  it "should return nil if it cannot find an attribute with node[]" do
147
- @node["secret"].should eql(nil)
135
+ node["secret"].should eql(nil)
148
136
  end
149
137
 
150
- it "should allow you to set an attribute via node[]=" do
151
- @node["secret"] = "shush"
152
- @node["secret"].should eql("shush")
138
+ it "does not allow you to set an attribute via node[]=" do
139
+ lambda { node["secret"] = "shush" }.should raise_error(Chef::Exceptions::ImmutableAttributeModification)
153
140
  end
154
141
 
155
142
  it "should allow you to query whether an attribute exists with attribute?" do
156
- @node.attribute["locust"] = "something"
157
- @node.attribute?("locust").should eql(true)
158
- @node.attribute?("no dice").should eql(false)
143
+ node.default["locust"] = "something"
144
+ node.attribute?("locust").should eql(true)
145
+ node.attribute?("no dice").should eql(false)
159
146
  end
160
147
 
161
148
  it "should let you go deep with attribute?" do
162
- @node.set["battles"]["people"]["wonkey"] = true
163
- @node["battles"]["people"].attribute?("wonkey").should == true
164
- @node["battles"]["people"].attribute?("snozzberry").should == false
149
+ node.set["battles"]["people"]["wonkey"] = true
150
+ node["battles"]["people"].attribute?("wonkey").should == true
151
+ node["battles"]["people"].attribute?("snozzberry").should == false
165
152
  end
166
153
 
167
- it "should allow you to set an attribute via method_missing" do
168
- @node.sunshine "is bright"
169
- @node.attribute[:sunshine].should eql("is bright")
154
+ it "does not allow you to set an attribute via method_missing" do
155
+ lambda { node.sunshine = "is bright"}.should raise_error(Chef::Exceptions::ImmutableAttributeModification)
170
156
  end
171
157
 
172
158
  it "should allow you get get an attribute via method_missing" do
173
- @node.sunshine "is bright"
174
- @node.sunshine.should eql("is bright")
159
+ node.default.sunshine = "is bright"
160
+ node.sunshine.should eql("is bright")
175
161
  end
176
162
 
177
163
  describe "normal attributes" do
178
164
  it "should allow you to set an attribute with set, without pre-declaring a hash" do
179
- @node.set[:snoopy][:is_a_puppy] = true
180
- @node[:snoopy][:is_a_puppy].should == true
165
+ node.set[:snoopy][:is_a_puppy] = true
166
+ node[:snoopy][:is_a_puppy].should == true
181
167
  end
182
168
 
183
169
  it "should allow you to set an attribute with set_unless" do
184
- @node.set_unless[:snoopy][:is_a_puppy] = false
185
- @node[:snoopy][:is_a_puppy].should == false
170
+ node.set_unless[:snoopy][:is_a_puppy] = false
171
+ node[:snoopy][:is_a_puppy].should == false
186
172
  end
187
173
 
188
174
  it "should not allow you to set an attribute with set_unless if it already exists" do
189
- @node.set[:snoopy][:is_a_puppy] = true
190
- @node.set_unless[:snoopy][:is_a_puppy] = false
191
- @node[:snoopy][:is_a_puppy].should == true
175
+ node.set[:snoopy][:is_a_puppy] = true
176
+ node.set_unless[:snoopy][:is_a_puppy] = false
177
+ node[:snoopy][:is_a_puppy].should == true
178
+ end
179
+
180
+ it "should allow you to set a value after a set_unless" do
181
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
182
+ node.set_unless[:snoopy][:is_a_puppy] = false
183
+ node.set[:snoopy][:is_a_puppy] = true
184
+ node[:snoopy][:is_a_puppy].should == true
185
+ end
186
+
187
+ it "should let you set a value after a 'dangling' set_unless" do
188
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
189
+ node.set[:snoopy][:is_a_puppy] = "what"
190
+ node.set_unless[:snoopy][:is_a_puppy]
191
+ node.set[:snoopy][:is_a_puppy] = true
192
+ node[:snoopy][:is_a_puppy].should == true
192
193
  end
193
194
 
194
195
  it "auto-vivifies attributes created via method syntax" do
195
- @node.set.fuu.bahrr.baz = "qux"
196
- @node.fuu.bahrr.baz.should == "qux"
196
+ node.set.fuu.bahrr.baz = "qux"
197
+ node.fuu.bahrr.baz.should == "qux"
197
198
  end
198
199
 
199
200
  end
200
201
 
201
202
  describe "default attributes" do
202
203
  it "should be set with default, without pre-declaring a hash" do
203
- @node.default[:snoopy][:is_a_puppy] = true
204
- @node[:snoopy][:is_a_puppy].should == true
204
+ node.default[:snoopy][:is_a_puppy] = true
205
+ node[:snoopy][:is_a_puppy].should == true
205
206
  end
206
207
 
207
208
  it "should allow you to set with default_unless without pre-declaring a hash" do
208
- @node.default_unless[:snoopy][:is_a_puppy] = false
209
- @node[:snoopy][:is_a_puppy].should == false
209
+ node.default_unless[:snoopy][:is_a_puppy] = false
210
+ node[:snoopy][:is_a_puppy].should == false
210
211
  end
211
212
 
212
213
  it "should not allow you to set an attribute with default_unless if it already exists" do
213
- @node.default[:snoopy][:is_a_puppy] = true
214
- @node.default_unless[:snoopy][:is_a_puppy] = false
215
- @node[:snoopy][:is_a_puppy].should == true
214
+ node.default[:snoopy][:is_a_puppy] = true
215
+ node.default_unless[:snoopy][:is_a_puppy] = false
216
+ node[:snoopy][:is_a_puppy].should == true
217
+ end
218
+
219
+ it "should allow you to set a value after a default_unless" do
220
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
221
+ node.default_unless[:snoopy][:is_a_puppy] = false
222
+ node.default[:snoopy][:is_a_puppy] = true
223
+ node[:snoopy][:is_a_puppy].should == true
224
+ end
225
+
226
+ it "should allow you to set a value after a 'dangling' default_unless" do
227
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
228
+ node.default[:snoopy][:is_a_puppy] = "what"
229
+ node.default_unless[:snoopy][:is_a_puppy]
230
+ node.default[:snoopy][:is_a_puppy] = true
231
+ node[:snoopy][:is_a_puppy].should == true
216
232
  end
217
233
 
218
234
  it "auto-vivifies attributes created via method syntax" do
219
- @node.default.fuu.bahrr.baz = "qux"
220
- @node.fuu.bahrr.baz.should == "qux"
235
+ node.default.fuu.bahrr.baz = "qux"
236
+ node.fuu.bahrr.baz.should == "qux"
237
+ end
238
+
239
+ it "accesses force defaults via default!" do
240
+ node.default![:foo] = "wet bar"
241
+ node.default[:foo] = "bar"
242
+ node[:foo].should == "wet bar"
221
243
  end
222
244
 
223
245
  end
224
246
 
225
247
  describe "override attributes" do
226
248
  it "should be set with override, without pre-declaring a hash" do
227
- @node.override[:snoopy][:is_a_puppy] = true
228
- @node[:snoopy][:is_a_puppy].should == true
249
+ node.override[:snoopy][:is_a_puppy] = true
250
+ node[:snoopy][:is_a_puppy].should == true
229
251
  end
230
252
 
231
253
  it "should allow you to set with override_unless without pre-declaring a hash" do
232
- @node.override_unless[:snoopy][:is_a_puppy] = false
233
- @node[:snoopy][:is_a_puppy].should == false
254
+ node.override_unless[:snoopy][:is_a_puppy] = false
255
+ node[:snoopy][:is_a_puppy].should == false
234
256
  end
235
257
 
236
258
  it "should not allow you to set an attribute with override_unless if it already exists" do
237
- @node.override[:snoopy][:is_a_puppy] = true
238
- @node.override_unless[:snoopy][:is_a_puppy] = false
239
- @node[:snoopy][:is_a_puppy].should == true
259
+ node.override[:snoopy][:is_a_puppy] = true
260
+ node.override_unless[:snoopy][:is_a_puppy] = false
261
+ node[:snoopy][:is_a_puppy].should == true
262
+ end
263
+
264
+ it "should allow you to set a value after an override_unless" do
265
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
266
+ node.override_unless[:snoopy][:is_a_puppy] = false
267
+ node.override[:snoopy][:is_a_puppy] = true
268
+ node[:snoopy][:is_a_puppy].should == true
269
+ end
270
+
271
+ it "should allow you to set a value after a 'dangling' override_unless" do
272
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
273
+ node.override_unless[:snoopy][:is_a_puppy] = "what"
274
+ node.override_unless[:snoopy][:is_a_puppy]
275
+ node.override[:snoopy][:is_a_puppy] = true
276
+ node[:snoopy][:is_a_puppy].should == true
240
277
  end
241
278
 
242
279
  it "auto-vivifies attributes created via method syntax" do
243
- @node.override.fuu.bahrr.baz = "qux"
244
- @node.fuu.bahrr.baz.should == "qux"
280
+ node.override.fuu.bahrr.baz = "qux"
281
+ node.fuu.bahrr.baz.should == "qux"
282
+ end
283
+
284
+ it "sets force_overrides via override!" do
285
+ node.override![:foo] = "wet bar"
286
+ node.override[:foo] = "bar"
287
+ node[:foo].should == "wet bar"
245
288
  end
246
289
 
247
290
  end
248
291
 
249
292
  it "should raise an ArgumentError if you ask for an attribute that doesn't exist via method_missing" do
250
- lambda { @node.sunshine }.should raise_error(ArgumentError)
293
+ lambda { node.sunshine }.should raise_error(NoMethodError)
251
294
  end
252
295
 
253
296
  it "should allow you to iterate over attributes with each_attribute" do
254
- @node.sunshine "is bright"
255
- @node.canada "is a nice place"
297
+ node.default.sunshine = "is bright"
298
+ node.default.canada = "is a nice place"
256
299
  seen_attributes = Hash.new
257
- @node.each_attribute do |a,v|
300
+ node.each_attribute do |a,v|
258
301
  seen_attributes[a] = v
259
302
  end
260
303
  seen_attributes.should have_key("sunshine")
@@ -272,62 +315,62 @@ describe Chef::Node do
272
315
 
273
316
  it "consumes the run list portion of a collection of attributes and returns the remainder" do
274
317
  attrs = {"run_list" => [ "role[base]", "recipe[chef::server]" ], "foo" => "bar"}
275
- @node.consume_run_list(attrs).should == {"foo" => "bar"}
276
- @node.run_list.should == [ "role[base]", "recipe[chef::server]" ]
318
+ node.consume_run_list(attrs).should == {"foo" => "bar"}
319
+ node.run_list.should == [ "role[base]", "recipe[chef::server]" ]
277
320
  end
278
321
 
279
322
  it "should overwrites the run list with the run list it consumes" do
280
- @node.consume_run_list "recipes" => [ "one", "two" ]
281
- @node.consume_run_list "recipes" => [ "three" ]
282
- @node.run_list.should == [ "three" ]
323
+ node.consume_run_list "recipes" => [ "one", "two" ]
324
+ node.consume_run_list "recipes" => [ "three" ]
325
+ node.run_list.should == [ "three" ]
283
326
  end
284
327
 
285
328
  it "should not add duplicate recipes from the json attributes" do
286
- @node.run_list << "one"
287
- @node.consume_run_list "recipes" => [ "one", "two", "three" ]
288
- @node.run_list.should == [ "one", "two", "three" ]
329
+ node.run_list << "one"
330
+ node.consume_run_list "recipes" => [ "one", "two", "three" ]
331
+ node.run_list.should == [ "one", "two", "three" ]
289
332
  end
290
333
 
291
334
  it "doesn't change the run list if no run_list is specified in the json" do
292
- @node.run_list << "role[database]"
293
- @node.consume_run_list "foo" => "bar"
294
- @node.run_list.should == ["role[database]"]
335
+ node.run_list << "role[database]"
336
+ node.consume_run_list "foo" => "bar"
337
+ node.run_list.should == ["role[database]"]
295
338
  end
296
339
 
297
340
  it "raises an exception if you provide both recipe and run_list attributes, since this is ambiguous" do
298
- lambda { @node.consume_run_list "recipes" => "stuff", "run_list" => "other_stuff" }.should raise_error(Chef::Exceptions::AmbiguousRunlistSpecification)
341
+ lambda { node.consume_run_list "recipes" => "stuff", "run_list" => "other_stuff" }.should raise_error(Chef::Exceptions::AmbiguousRunlistSpecification)
299
342
  end
300
343
 
301
344
  it "should add json attributes to the node" do
302
- @node.consume_external_attrs(@ohai_data, {"one" => "two", "three" => "four"})
303
- @node.one.should eql("two")
304
- @node.three.should eql("four")
345
+ node.consume_external_attrs(@ohai_data, {"one" => "two", "three" => "four"})
346
+ node.one.should eql("two")
347
+ node.three.should eql("four")
305
348
  end
306
349
 
307
350
  it "should set the tags attribute to an empty array if it is not already defined" do
308
- @node.consume_external_attrs(@ohai_data, {})
309
- @node.tags.should eql([])
351
+ node.consume_external_attrs(@ohai_data, {})
352
+ node.tags.should eql([])
310
353
  end
311
354
 
312
355
  it "should not set the tags attribute to an empty array if it is already defined" do
313
- @node[:tags] = [ "radiohead" ]
314
- @node.consume_external_attrs(@ohai_data, {})
315
- @node.tags.should eql([ "radiohead" ])
356
+ node.normal[:tags] = [ "radiohead" ]
357
+ node.consume_external_attrs(@ohai_data, {})
358
+ node.tags.should eql([ "radiohead" ])
316
359
  end
317
360
 
318
361
  it "deep merges attributes instead of overwriting them" do
319
- @node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}})
320
- @node.one.to_hash.should == {"two" => {"three" => "four"}}
321
- @node.consume_external_attrs(@ohai_data, "one" => {"abc" => "123"})
322
- @node.consume_external_attrs(@ohai_data, "one" => {"two" => {"foo" => "bar"}})
323
- @node.one.to_hash.should == {"two" => {"three" => "four", "foo" => "bar"}, "abc" => "123"}
362
+ node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}})
363
+ node.one.to_hash.should == {"two" => {"three" => "four"}}
364
+ node.consume_external_attrs(@ohai_data, "one" => {"abc" => "123"})
365
+ node.consume_external_attrs(@ohai_data, "one" => {"two" => {"foo" => "bar"}})
366
+ node.one.to_hash.should == {"two" => {"three" => "four", "foo" => "bar"}, "abc" => "123"}
324
367
  end
325
368
 
326
369
  it "gives attributes from JSON priority when deep merging" do
327
- @node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}})
328
- @node.one.to_hash.should == {"two" => {"three" => "four"}}
329
- @node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "forty-two"}})
330
- @node.one.to_hash.should == {"two" => {"three" => "forty-two"}}
370
+ node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}})
371
+ node.one.to_hash.should == {"two" => {"three" => "four"}}
372
+ node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "forty-two"}})
373
+ node.one.to_hash.should == {"two" => {"three" => "forty-two"}}
331
374
  end
332
375
 
333
376
  end
@@ -338,161 +381,249 @@ describe Chef::Node do
338
381
  end
339
382
 
340
383
  it "sets its platform according to platform detection" do
341
- @node.consume_external_attrs(@ohai_data, {})
342
- @node.automatic_attrs[:platform].should == 'foobuntu'
343
- @node.automatic_attrs[:platform_version].should == '23.42'
384
+ node.consume_external_attrs(@ohai_data, {})
385
+ node.automatic_attrs[:platform].should == 'foobuntu'
386
+ node.automatic_attrs[:platform_version].should == '23.42'
344
387
  end
345
388
 
346
389
  it "consumes the run list from provided json attributes" do
347
- @node.consume_external_attrs(@ohai_data, {"run_list" => ['recipe[unicorn]']})
348
- @node.run_list.should == ['recipe[unicorn]']
390
+ node.consume_external_attrs(@ohai_data, {"run_list" => ['recipe[unicorn]']})
391
+ node.run_list.should == ['recipe[unicorn]']
349
392
  end
350
393
 
351
394
  it "saves non-runlist json attrs for later" do
352
395
  expansion = Chef::RunList::RunListExpansion.new('_default', [])
353
- @node.run_list.stub!(:expand).and_return(expansion)
354
- @node.consume_external_attrs(@ohai_data, {"foo" => "bar"})
355
- @node.expand!
356
- @node.normal_attrs.should == {"foo" => "bar", "tags" => []}
396
+ node.run_list.stub!(:expand).and_return(expansion)
397
+ node.consume_external_attrs(@ohai_data, {"foo" => "bar"})
398
+ node.expand!
399
+ node.normal_attrs.should == {"foo" => "bar", "tags" => []}
357
400
  end
358
401
 
359
402
  end
360
403
 
361
404
  describe "when expanding its run list and merging attributes" do
362
405
  before do
363
- @expansion = Chef::RunList::RunListExpansion.new("_default", [])
364
- @node.run_list.stub!(:expand).and_return(@expansion)
406
+ @environment = Chef::Environment.new.tap do |e|
407
+ e.name('rspec_env')
408
+ e.default_attributes("env default key" => "env default value")
409
+ e.override_attributes("env override key" => "env override value")
410
+ end
411
+ Chef::Environment.should_receive(:load).with("rspec_env").and_return(@environment)
412
+ @expansion = Chef::RunList::RunListExpansion.new("rspec_env", [])
413
+ node.chef_environment("rspec_env")
414
+ node.run_list.stub!(:expand).and_return(@expansion)
365
415
  end
366
416
 
367
417
  it "sets the 'recipes' automatic attribute to the recipes in the expanded run_list" do
368
418
  @expansion.recipes << 'recipe[chef::client]' << 'recipe[nginx::default]'
369
- @node.expand!
370
- @node.automatic_attrs[:recipes].should == ['recipe[chef::client]', 'recipe[nginx::default]']
419
+ node.expand!
420
+ node.automatic_attrs[:recipes].should == ['recipe[chef::client]', 'recipe[nginx::default]']
371
421
  end
372
422
 
373
423
  it "sets the 'roles' automatic attribute to the expanded role list" do
374
424
  @expansion.instance_variable_set(:@applied_roles, {'arf' => nil, 'countersnark' => nil})
375
- @node.expand!
376
- @node.automatic_attrs[:roles].sort.should == ['arf', 'countersnark']
425
+ node.expand!
426
+ node.automatic_attrs[:roles].sort.should == ['arf', 'countersnark']
427
+ end
428
+
429
+ it "applies default attributes from the environment as environment defaults" do
430
+ node.expand!
431
+ node.attributes.env_default["env default key"].should == "env default value"
432
+ end
433
+
434
+ it "applies override attributes from the environment as env overrides" do
435
+ node.expand!
436
+ node.attributes.env_override["env override key"].should == "env override value"
437
+ end
438
+
439
+ it "applies default attributes from roles as role defaults" do
440
+ @expansion.default_attrs["role default key"] = "role default value"
441
+ node.expand!
442
+ node.attributes.role_default["role default key"].should == "role default value"
377
443
  end
378
444
 
445
+ it "applies override attributes from roles as role overrides" do
446
+ @expansion.override_attrs["role override key"] = "role override value"
447
+ node.expand!
448
+ node.attributes.role_override["role override key"].should == "role override value"
449
+ end
379
450
  end
380
451
 
381
- # TODO: timh, cw: 2010-5-19: Node.recipe? deprecated. See node.rb
382
- # describe "recipes" do
383
- # it "should have a RunList of recipes that should be applied" do
384
- # @node.recipes.should be_a_kind_of(Chef::RunList)
385
- # end
386
- #
387
- # it "should allow you to query whether or not it has a recipe applied with recipe?" do
388
- # @node.recipes << "sunrise"
389
- # @node.recipe?("sunrise").should eql(true)
390
- # @node.recipe?("not at home").should eql(false)
391
- # end
392
- #
393
- # it "should allow you to query whether or not a recipe has been applied, even if it was included" do
394
- # @node.run_state[:seen_recipes]["snakes"] = true
395
- # @node.recipe?("snakes").should eql(true)
396
- # end
397
- #
398
- # it "should return false if a recipe has not been seen" do
399
- # @node.recipe?("snakes").should eql(false)
400
- # end
401
- #
402
- # it "should allow you to set recipes with arguments" do
403
- # @node.recipes "one", "two"
404
- # @node.recipe?("one").should eql(true)
405
- # @node.recipe?("two").should eql(true)
406
- # end
407
- # end
452
+ describe "when querying for recipes in the run list" do
453
+ context "when a recipe is in the top level run list" do
454
+ before do
455
+ node.run_list << "recipe[nginx::module]"
456
+ end
457
+
458
+ it "finds the recipe" do
459
+ node.recipe?("nginx::module").should be_true
460
+ end
461
+
462
+ it "does not find a recipe not in the run list" do
463
+ node.recipe?("nginx::other_module").should be_false
464
+ end
465
+ end
466
+ context "when a recipe is in the expanded run list only" do
467
+ before do
468
+ node.run_list << "role[base]"
469
+ node.automatic_attrs[:recipes] = [ "nginx::module" ]
470
+ end
471
+
472
+ it "finds a recipe in the expanded run list" do
473
+ node.recipe?("nginx::module").should be_true
474
+ end
475
+
476
+ it "does not find a recipe that's not in the run list" do
477
+ node.recipe?("nginx::other_module").should be_false
478
+ end
479
+ end
480
+ end
481
+
482
+ describe "when clearing computed state at the beginning of a run" do
483
+ before do
484
+ node.default[:foo] = "default"
485
+ node.normal[:foo] = "normal"
486
+ node.override[:foo] = "override"
487
+ node.reset_defaults_and_overrides
488
+ end
489
+
490
+ it "removes default attributes" do
491
+ node.default.should be_empty
492
+ end
493
+
494
+ it "removes override attributes" do
495
+ node.override.should be_empty
496
+ end
497
+
498
+ it "leaves normal level attributes untouched" do
499
+ node[:foo].should == "normal"
500
+ end
501
+
502
+ end
503
+
504
+ describe "when merging environment attributes" do
505
+ before do
506
+ node.chef_environment = "rspec"
507
+ @expansion = Chef::RunList::RunListExpansion.new("rspec", [])
508
+ @expansion.default_attrs.replace({:default => "from role", :d_role => "role only"})
509
+ @expansion.override_attrs.replace({:override => "from role", :o_role => "role only"})
510
+
511
+
512
+ @environment = Chef::Environment.new
513
+ @environment.default_attributes = {:default => "from env", :d_env => "env only" }
514
+ @environment.override_attributes = {:override => "from env", :o_env => "env only"}
515
+ Chef::Environment.stub!(:load).and_return(@environment)
516
+ node.apply_expansion_attributes(@expansion)
517
+ end
518
+
519
+ it "does not nuke role-only default attrs" do
520
+ node[:d_role].should == "role only"
521
+ end
522
+
523
+ it "does not nuke role-only override attrs" do
524
+ node[:o_role].should == "role only"
525
+ end
526
+
527
+ it "does not nuke env-only default attrs" do
528
+ node[:o_env].should == "env only"
529
+ end
530
+
531
+ it "does not nuke role-only override attrs" do
532
+ node[:o_env].should == "env only"
533
+ end
534
+
535
+ it "gives role defaults precedence over env defaults" do
536
+ node[:default].should == "from role"
537
+ end
538
+
539
+ it "gives env overrides precedence over role overrides" do
540
+ node[:override].should == "from env"
541
+ end
542
+ end
543
+
544
+ describe "when evaluating attributes files" do
545
+ before do
546
+ @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
547
+ @cookbook_loader = Chef::CookbookLoader.new(@cookbook_repo)
548
+ @cookbook_loader.load_cookbooks
549
+
550
+ @cookbook_collection = Chef::CookbookCollection.new(@cookbook_loader.cookbooks_by_name)
551
+
552
+ @events = Chef::EventDispatch::Dispatcher.new
553
+ @run_context = Chef::RunContext.new(node, @cookbook_collection, @events)
554
+
555
+ node.include_attribute("openldap::default")
556
+ node.include_attribute("openldap::smokey")
557
+ end
558
+
559
+ it "sets attributes from the files" do
560
+ node.ldap_server.should eql("ops1prod")
561
+ node.ldap_basedn.should eql("dc=hjksolutions,dc=com")
562
+ node.ldap_replication_password.should eql("forsure")
563
+ node.smokey.should eql("robinson")
564
+ end
565
+
566
+ it "gives a sensible error when attempting to load a missing attributes file" do
567
+ lambda { node.include_attribute("nope-this::doesnt-exist") }.should raise_error(Chef::Exceptions::CookbookNotFound)
568
+ end
569
+ end
408
570
 
409
571
  describe "roles" do
410
572
  it "should allow you to query whether or not it has a recipe applied with role?" do
411
- @node.run_list << "role[sunrise]"
412
- @node.role?("sunrise").should eql(true)
413
- @node.role?("not at home").should eql(false)
573
+ node.run_list << "role[sunrise]"
574
+ node.role?("sunrise").should eql(true)
575
+ node.role?("not at home").should eql(false)
414
576
  end
415
577
 
416
578
  it "should allow you to set roles with arguments" do
417
- @node.run_list << "role[one]"
418
- @node.run_list << "role[two]"
419
- @node.role?("one").should eql(true)
420
- @node.role?("two").should eql(true)
579
+ node.run_list << "role[one]"
580
+ node.run_list << "role[two]"
581
+ node.role?("one").should eql(true)
582
+ node.role?("two").should eql(true)
421
583
  end
422
584
  end
423
585
 
424
586
  describe "run_list" do
425
587
  it "should have a Chef::RunList of recipes and roles that should be applied" do
426
- @node.run_list.should be_a_kind_of(Chef::RunList)
588
+ node.run_list.should be_a_kind_of(Chef::RunList)
427
589
  end
428
590
 
429
591
  it "should allow you to query the run list with arguments" do
430
- @node.run_list "recipe[baz]"
431
- @node.run_list?("recipe[baz]").should eql(true)
592
+ node.run_list "recipe[baz]"
593
+ node.run_list?("recipe[baz]").should eql(true)
432
594
  end
433
595
 
434
596
  it "should allow you to set the run list with arguments" do
435
- @node.run_list "recipe[baz]", "role[foo]"
436
- @node.run_list?("recipe[baz]").should eql(true)
437
- @node.run_list?("role[foo]").should eql(true)
597
+ node.run_list "recipe[baz]", "role[foo]"
598
+ node.run_list?("recipe[baz]").should eql(true)
599
+ node.run_list?("role[foo]").should eql(true)
438
600
  end
439
601
  end
440
602
 
441
603
  describe "from file" do
442
604
  it "should load a node from a ruby file" do
443
- @node.from_file(File.expand_path(File.join(CHEF_SPEC_DATA, "nodes", "test.rb")))
444
- @node.name.should eql("test.example.com-short")
445
- @node.sunshine.should eql("in")
446
- @node.something.should eql("else")
447
- @node.recipes.should == ["operations-master", "operations-monitoring"]
605
+ node.from_file(File.expand_path(File.join(CHEF_SPEC_DATA, "nodes", "test.rb")))
606
+ node.name.should eql("test.example.com-short")
607
+ node.sunshine.should eql("in")
608
+ node.something.should eql("else")
609
+ node.run_list.should == ["operations-master", "operations-monitoring"]
448
610
  end
449
611
 
450
612
  it "should raise an exception if the file cannot be found or read" do
451
- lambda { @node.from_file("/tmp/monkeydiving") }.should raise_error(IOError)
452
- end
453
- end
454
-
455
- describe "find_file" do
456
- it "should load a node from a file by fqdn" do
457
- @node.find_file("test.example.com")
458
- @node.name.should == "test.example.com"
459
- @node.chef_environment.should == "dev"
460
- end
461
-
462
- it "should load a node from a file by hostname" do
463
- File.stub!(:exists?).and_return(true)
464
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.example.com.rb")).and_return(false)
465
- @node.find_file("test.example.com")
466
- @node.name.should == "test.example.com-short"
467
- end
468
-
469
- it "should load a node from the default file" do
470
- File.stub!(:exists?).and_return(true)
471
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.example.com.rb")).and_return(false)
472
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.rb")).and_return(false)
473
- @node.find_file("test.example.com")
474
- @node.name.should == "test.example.com-default"
475
- end
476
-
477
- it "should raise an ArgumentError if it cannot find any node file at all" do
478
- File.stub!(:exists?).and_return(true)
479
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.example.com.rb")).and_return(false)
480
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.rb")).and_return(false)
481
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "default.rb")).and_return(false)
482
- lambda { @node.find_file("test.example.com") }.should raise_error(ArgumentError)
613
+ lambda { node.from_file("/tmp/monkeydiving") }.should raise_error(IOError)
483
614
  end
484
615
  end
485
616
 
486
617
  describe "update_from!" do
487
618
  before(:each) do
488
- @node.name("orig")
489
- @node.chef_environment("dev")
490
- @node.default_attrs = { "one" => { "two" => "three", "four" => "five", "eight" => "nine" } }
491
- @node.override_attrs = { "one" => { "two" => "three", "four" => "six" } }
492
- @node.normal_attrs = { "one" => { "two" => "seven" } }
493
- @node.run_list << "role[marxist]"
494
- @node.run_list << "role[leninist]"
495
- @node.run_list << "recipe[stalinist]"
619
+ node.name("orig")
620
+ node.chef_environment("dev")
621
+ node.default_attrs = { "one" => { "two" => "three", "four" => "five", "eight" => "nine" } }
622
+ node.override_attrs = { "one" => { "two" => "three", "four" => "six" } }
623
+ node.normal_attrs = { "one" => { "two" => "seven" } }
624
+ node.run_list << "role[marxist]"
625
+ node.run_list << "role[leninist]"
626
+ node.run_list << "recipe[stalinist]"
496
627
 
497
628
  @example = Chef::Node.new()
498
629
  @example.name("newname")
@@ -506,31 +637,31 @@ describe Chef::Node do
506
637
  end
507
638
 
508
639
  it "allows update of everything except name" do
509
- @node.update_from!(@example)
510
- @node.name.should == "orig"
511
- @node.chef_environment.should == @example.chef_environment
512
- @node.default_attrs.should == @example.default_attrs
513
- @node.override_attrs.should == @example.override_attrs
514
- @node.normal_attrs.should == @example.normal_attrs
515
- @node.run_list.should == @example.run_list
640
+ node.update_from!(@example)
641
+ node.name.should == "orig"
642
+ node.chef_environment.should == @example.chef_environment
643
+ node.default_attrs.should == @example.default_attrs
644
+ node.override_attrs.should == @example.override_attrs
645
+ node.normal_attrs.should == @example.normal_attrs
646
+ node.run_list.should == @example.run_list
516
647
  end
517
648
 
518
649
  it "should not update the name of the node" do
519
- @node.should_not_receive(:name).with(@example.name)
520
- @node.update_from!(@example)
650
+ node.should_not_receive(:name).with(@example.name)
651
+ node.update_from!(@example)
521
652
  end
522
653
  end
523
654
 
524
655
  describe "to_hash" do
525
656
  it "should serialize itself as a hash" do
526
- @node.chef_environment("dev")
527
- @node.default_attrs = { "one" => { "two" => "three", "four" => "five", "eight" => "nine" } }
528
- @node.override_attrs = { "one" => { "two" => "three", "four" => "six" } }
529
- @node.normal_attrs = { "one" => { "two" => "seven" } }
530
- @node.run_list << "role[marxist]"
531
- @node.run_list << "role[leninist]"
532
- @node.run_list << "recipe[stalinist]"
533
- h = @node.to_hash
657
+ node.chef_environment("dev")
658
+ node.default_attrs = { "one" => { "two" => "three", "four" => "five", "eight" => "nine" } }
659
+ node.override_attrs = { "one" => { "two" => "three", "four" => "six" } }
660
+ node.normal_attrs = { "one" => { "two" => "seven" } }
661
+ node.run_list << "role[marxist]"
662
+ node.run_list << "role[leninist]"
663
+ node.run_list << "recipe[stalinist]"
664
+ h = node.to_hash
534
665
  h["one"]["two"].should == "three"
535
666
  h["one"]["four"].should == "six"
536
667
  h["one"]["eight"].should == "nine"
@@ -543,10 +674,10 @@ describe Chef::Node do
543
674
  end
544
675
  end
545
676
 
546
- describe "json" do
677
+ describe "converting to or from json" do
547
678
  it "should serialize itself as json", :json => true do
548
- @node.find_file("test.example.com")
549
- json = Chef::JSONCompat.to_json(@node)
679
+ node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
680
+ json = Chef::JSONCompat.to_json(node)
550
681
  json.should =~ /json_class/
551
682
  json.should =~ /name/
552
683
  json.should =~ /chef_environment/
@@ -556,33 +687,50 @@ describe Chef::Node do
556
687
  json.should =~ /run_list/
557
688
  end
558
689
 
559
- it 'should serialze valid json with a run list', :json => true do
690
+ it 'should serialize valid json with a run list', :json => true do
560
691
  #This test came about because activesupport mucks with Chef json serialization
561
692
  #Test should pass with and without Activesupport
562
- @node.run_list << {"type" => "role", "name" => 'Cthulu'}
563
- @node.run_list << {"type" => "role", "name" => 'Hastur'}
564
- json = Chef::JSONCompat.to_json(@node)
693
+ node.run_list << {"type" => "role", "name" => 'Cthulu'}
694
+ node.run_list << {"type" => "role", "name" => 'Hastur'}
695
+ json = Chef::JSONCompat.to_json(node)
565
696
  json.should =~ /\"run_list\":\[\"role\[Cthulu\]\",\"role\[Hastur\]\"\]/
566
697
  end
567
698
 
699
+ it "merges the override components into a combined override object" do
700
+ node.attributes.role_override["role override"] = "role override"
701
+ node.attributes.env_override["env override"] = "env override"
702
+ node_for_json = node.for_json
703
+ node_for_json["override"]["role override"].should == "role override"
704
+ node_for_json["override"]["env override"].should == "env override"
705
+ end
706
+
707
+ it "merges the default components into a combined default object" do
708
+ node.attributes.role_default["role default"] = "role default"
709
+ node.attributes.env_default["env default"] = "env default"
710
+ node_for_json = node.for_json
711
+ node_for_json["default"]["role default"].should == "role default"
712
+ node_for_json["default"]["env default"].should == "env default"
713
+ end
714
+
715
+
568
716
  it "should deserialize itself from json", :json => true do
569
- @node.find_file("test.example.com")
570
- json = Chef::JSONCompat.to_json(@node)
717
+ node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
718
+ json = Chef::JSONCompat.to_json(node)
571
719
  serialized_node = Chef::JSONCompat.from_json(json)
572
720
  serialized_node.should be_a_kind_of(Chef::Node)
573
- serialized_node.name.should eql(@node.name)
574
- serialized_node.chef_environment.should eql(@node.chef_environment)
575
- @node.each_attribute do |k,v|
721
+ serialized_node.name.should eql(node.name)
722
+ serialized_node.chef_environment.should eql(node.chef_environment)
723
+ node.each_attribute do |k,v|
576
724
  serialized_node[k].should eql(v)
577
725
  end
578
- serialized_node.run_list.should == @node.run_list
726
+ serialized_node.run_list.should == node.run_list
579
727
  end
580
728
  end
581
729
 
582
730
  describe "to_s" do
583
731
  it "should turn into a string like node[name]" do
584
- @node.name("airplane")
585
- @node.to_s.should eql("node[airplane]")
732
+ node.name("airplane")
733
+ node.to_s.should eql("node[airplane]")
586
734
  end
587
735
  end
588
736
 
@@ -621,31 +769,31 @@ describe Chef::Node do
621
769
  describe "destroy" do
622
770
  it "should destroy a node" do
623
771
  @rest.should_receive(:delete_rest).with("nodes/monkey").and_return("foo")
624
- @node.name("monkey")
625
- @node.destroy
772
+ node.name("monkey")
773
+ node.destroy
626
774
  end
627
775
  end
628
776
 
629
777
  describe "save" do
630
778
  it "should update a node if it already exists" do
631
- @node.name("monkey")
632
- @rest.should_receive(:put_rest).with("nodes/monkey", @node).and_return("foo")
633
- @node.save
779
+ node.name("monkey")
780
+ @rest.should_receive(:put_rest).with("nodes/monkey", node).and_return("foo")
781
+ node.save
634
782
  end
635
783
 
636
784
  it "should not try and create if it can update" do
637
- @node.name("monkey")
638
- @rest.should_receive(:put_rest).with("nodes/monkey", @node).and_return("foo")
785
+ node.name("monkey")
786
+ @rest.should_receive(:put_rest).with("nodes/monkey", node).and_return("foo")
639
787
  @rest.should_not_receive(:post_rest)
640
- @node.save
788
+ node.save
641
789
  end
642
790
 
643
791
  it "should create if it cannot update" do
644
- @node.name("monkey")
792
+ node.name("monkey")
645
793
  exception = mock("404 error", :code => "404")
646
794
  @rest.should_receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception))
647
- @rest.should_receive(:post_rest).with("nodes", @node)
648
- @node.save
795
+ @rest.should_receive(:post_rest).with("nodes", node)
796
+ node.save
649
797
  end
650
798
 
651
799
  describe "when whyrun mode is enabled" do
@@ -656,89 +804,13 @@ describe Chef::Node do
656
804
  Chef::Config[:why_run] = false
657
805
  end
658
806
  it "should not save" do
659
- @node.name("monkey")
807
+ node.name("monkey")
660
808
  @rest.should_not_receive(:put_rest)
661
809
  @rest.should_not_receive(:post_rest)
662
- @node.save
810
+ node.save
663
811
  end
664
812
  end
665
813
  end
666
814
  end
667
815
 
668
- describe "acting as a CouchDB-backed model" do
669
- before(:each) do
670
- @couchdb = Chef::CouchDB.new
671
- @mock_couch = mock('couch mock')
672
- end
673
-
674
- describe "list" do
675
- before(:each) do
676
- @mock_couch.stub!(:list).and_return(
677
- { "rows" => [ { "value" => "a", "key" => "avenue" } ] }
678
- )
679
- Chef::CouchDB.stub!(:new).and_return(@mock_couch)
680
- end
681
-
682
- it "should retrieve a list of nodes from CouchDB" do
683
- Chef::Node.cdb_list.should eql(["avenue"])
684
- end
685
-
686
- it "should return just the ids if inflate is false" do
687
- Chef::Node.cdb_list(false).should eql(["avenue"])
688
- end
689
-
690
- it "should return the full objects if inflate is true" do
691
- Chef::Node.cdb_list(true).should eql(["a"])
692
- end
693
- end
694
-
695
- describe "when loading a given node" do
696
- it "should load a node from couchdb by name" do
697
- @couchdb.should_receive(:load).with("node", "coffee").and_return(true)
698
- Chef::CouchDB.stub!(:new).and_return(@couchdb)
699
- Chef::Node.cdb_load("coffee")
700
- end
701
- end
702
-
703
- describe "when destroying a Node" do
704
- it "should delete this node from couchdb" do
705
- @couchdb.should_receive(:delete).with("node", "bob", 1).and_return(true)
706
- Chef::CouchDB.stub!(:new).and_return(@couchdb)
707
- node = Chef::Node.new
708
- node.name "bob"
709
- node.couchdb_rev = 1
710
- node.cdb_destroy
711
- end
712
- end
713
-
714
- describe "when saving a Node" do
715
- before(:each) do
716
- @couchdb.stub!(:store).and_return({ "rev" => 33 })
717
- Chef::CouchDB.stub!(:new).and_return(@couchdb)
718
- @node = Chef::Node.new
719
- @node.name "bob"
720
- @node.couchdb_rev = 1
721
- end
722
-
723
- it "should save the node to couchdb" do
724
- @couchdb.should_receive(:store).with("node", "bob", @node).and_return({ "rev" => 33 })
725
- @node.cdb_save
726
- end
727
-
728
- it "should store the new couchdb_rev" do
729
- @node.cdb_save
730
- @node.couchdb_rev.should eql(33)
731
- end
732
- end
733
-
734
- describe "create_design_document" do
735
- it "should create our design document" do
736
- @couchdb.should_receive(:create_design_document).with("nodes", Chef::Node::DESIGN_DOCUMENT)
737
- Chef::CouchDB.stub!(:new).and_return(@couchdb)
738
- Chef::Node.create_design_document
739
- end
740
- end
741
-
742
- end
743
-
744
816
  end