microwave 1.0.4 → 11.400.2

Sign up to get free protection for your applications and to get access to all the features.
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