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
@@ -22,12 +22,15 @@ describe Chef::Resource::RemoteDirectory do
22
22
  include_context Chef::Resource::Directory
23
23
 
24
24
  let(:directory_base) { "directory_spec" }
25
+ let(:default_mode) { "755" }
25
26
 
26
27
  def create_resource
27
28
  cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
28
29
  Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
29
30
  node = Chef::Node.new
30
- cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(cookbook_repo))
31
+ cl = Chef::CookbookLoader.new(cookbook_repo)
32
+ cl.load_cookbooks
33
+ cookbook_collection = Chef::CookbookCollection.new(cl)
31
34
  events = Chef::EventDispatch::Dispatcher.new
32
35
  run_context = Chef::RunContext.new(node, cookbook_collection, events)
33
36
 
@@ -37,57 +40,90 @@ describe Chef::Resource::RemoteDirectory do
37
40
  resource
38
41
  end
39
42
 
43
+ def create_extraneous_files
44
+ FileUtils.mkdir_p(File.join(path, 'remotesubdir'))
45
+ @existing1 = File.join(path, 'marked_for_death.txt')
46
+ @existing2 = File.join(path, 'remotesubdir', 'marked_for_death_again.txt')
47
+ FileUtils.touch(@existing1)
48
+ FileUtils.touch(@existing2)
49
+ end
50
+
40
51
  let!(:resource) do
41
52
  create_resource
42
53
  end
43
54
 
55
+ let(:resource_second_pass) do
56
+ create_resource
57
+ end
58
+
59
+ # See spec/data/cookbooks/openldap/files/default
60
+ let(:expected_files) do
61
+ [
62
+ File.join(path, 'remote_dir_file1.txt'),
63
+ File.join(path, 'remote_dir_file2.txt'),
64
+ File.join(path, 'remotesubdir', 'remote_subdir_file1.txt'),
65
+ File.join(path, 'remotesubdir', 'remote_subdir_file2.txt'),
66
+ File.join(path, 'remotesubdir', '.a_dotfile'),
67
+ File.join(path, '.a_dotdir', '.a_dotfile_in_a_dotdir')
68
+ ]
69
+ end
70
+
44
71
  it_behaves_like "a directory resource"
45
72
 
46
- context "when creating the remote directory" do
47
- it "transfers the directory with all contents" do
48
- resource.run_action(:create)
49
- File.should exist(File.join(path, 'remote_dir_file1.txt'))
50
- File.should exist(File.join(path, 'remote_dir_file2.txt'))
51
- File.should exist(File.join(path, 'remotesubdir', 'remote_subdir_file1.txt'))
52
- File.should exist(File.join(path, 'remotesubdir', 'remote_subdir_file2.txt'))
53
- File.should exist(File.join(path, 'remotesubdir', '.a_dotfile'))
54
- File.should exist(File.join(path, '.a_dotdir', '.a_dotfile_in_a_dotdir'))
55
- end
73
+ it_behaves_like "a securable resource with reporting"
56
74
 
57
- context "with purging enabled" do
58
- before(:each) do
59
- resource.purge(true)
75
+ context "when creating the remote directory with purging disabled" do
76
+
77
+ context "and the directory does not yet exist" do
78
+ before do
79
+ resource.run_action(:create)
60
80
  end
61
81
 
62
- it "removes existing files if purge is true" do
63
- FileUtils.mkdir_p(File.join(path, 'remotesubdir'))
64
- existing1 = File.join(path, 'marked_for_death.txt')
65
- existing2 = File.join(path, 'remotesubdir', 'marked_for_death_again.txt')
66
- FileUtils.touch(existing1)
67
- FileUtils.touch(existing2)
82
+ it "transfers the directory with all contents" do
83
+ expected_files.each do |file_path|
84
+ File.should exist(file_path)
85
+ end
86
+ end
87
+
88
+ it "is marked as updated by last action" do
89
+ resource.should be_updated_by_last_action
90
+ end
91
+ end
68
92
 
93
+ context "and there are extraneous files in the directory" do
94
+ before do
95
+ create_extraneous_files
69
96
  resource.run_action(:create)
70
- File.should_not exist(existing1)
71
- File.should_not exist(existing2)
72
97
  end
73
98
 
74
- it "removes files in subdirectories before files above" do
75
- FileUtils.mkdir_p(File.join(path, 'a', 'multiply', 'nested', 'directory'))
76
- existing1 = File.join(path, 'a', 'foo.txt')
77
- existing2 = File.join(path, 'a', 'multiply', 'bar.txt')
78
- existing3 = File.join(path, 'a', 'multiply', 'nested', 'baz.txt')
79
- existing4 = File.join(path, 'a', 'multiply', 'nested', 'directory', 'qux.txt')
80
- FileUtils.touch(existing1)
81
- FileUtils.touch(existing2)
82
- FileUtils.touch(existing3)
83
- FileUtils.touch(existing4)
99
+ it "does not modify the expected state of the directory" do
100
+ expected_files.each do |file_path|
101
+ File.should exist(file_path)
102
+ end
103
+ end
84
104
 
105
+ it "does not remove unmanaged files" do
106
+ File.should exist(@existing1)
107
+ File.should exist(@existing2)
108
+ end
109
+ end
110
+
111
+ context "and the directory is in the desired state" do
112
+ before do
85
113
  resource.run_action(:create)
86
- File.should_not exist(existing1)
87
- File.should_not exist(existing2)
88
- File.should_not exist(existing3)
89
- File.should_not exist(existing4)
114
+ resource_second_pass.run_action(:create)
90
115
  end
116
+
117
+ it "does not modify the expected state of the directory" do
118
+ expected_files.each do |file_path|
119
+ File.should exist(file_path)
120
+ end
121
+ end
122
+
123
+ it "is not marked as updated by last action" do
124
+ resource_second_pass.should_not be_updated_by_last_action
125
+ end
126
+
91
127
  end
92
128
 
93
129
  describe "with overwrite disabled" do
@@ -111,4 +147,74 @@ describe Chef::Resource::RemoteDirectory do
111
147
  end
112
148
  end
113
149
  end
150
+
151
+ context "when creating the directory with purging enabled" do
152
+ before(:each) do
153
+ resource.purge(true)
154
+ end
155
+
156
+ context "and there are no extraneous files in the directory" do
157
+ before do
158
+ resource.run_action(:create)
159
+ end
160
+
161
+ it "creates the directory contents as normal" do
162
+ expected_files.each do |file_path|
163
+ File.should exist(file_path)
164
+ end
165
+ end
166
+
167
+ end
168
+
169
+ context "and there are extraneous files in the directory" do
170
+ before do
171
+ create_extraneous_files
172
+ resource.run_action(:create)
173
+ end
174
+
175
+ it "removes unmanaged files" do
176
+ File.should_not exist(@existing1)
177
+ File.should_not exist(@existing2)
178
+ end
179
+
180
+ it "does not modify managed files" do
181
+ expected_files.each do |file_path|
182
+ File.should exist(file_path)
183
+ end
184
+ end
185
+
186
+ it "is marked as updated by last action" do
187
+ resource.should be_updated_by_last_action
188
+ end
189
+ end
190
+
191
+ context "and there are deeply nested extraneous files in the directory" do
192
+ before do
193
+ FileUtils.mkdir_p(File.join(path, 'a', 'multiply', 'nested', 'directory'))
194
+ @existing1 = File.join(path, 'a', 'foo.txt')
195
+ @existing2 = File.join(path, 'a', 'multiply', 'bar.txt')
196
+ @existing3 = File.join(path, 'a', 'multiply', 'nested', 'baz.txt')
197
+ @existing4 = File.join(path, 'a', 'multiply', 'nested', 'directory', 'qux.txt')
198
+ FileUtils.touch(@existing1)
199
+ FileUtils.touch(@existing2)
200
+ FileUtils.touch(@existing3)
201
+ FileUtils.touch(@existing4)
202
+
203
+ resource.run_action(:create)
204
+ end
205
+
206
+ it "removes files in subdirectories before files above" do
207
+ File.should_not exist(@existing1)
208
+ File.should_not exist(@existing2)
209
+ File.should_not exist(@existing3)
210
+ File.should_not exist(@existing4)
211
+ end
212
+
213
+ it "is marked as updated by last action" do
214
+ resource.should be_updated_by_last_action
215
+ end
216
+
217
+ end
218
+ end
219
+
114
220
  end
@@ -24,7 +24,13 @@ describe Chef::Resource::RemoteFile do
24
24
 
25
25
  let(:file_base) { "remote_file_spec" }
26
26
  let(:source) { 'http://localhost:9000/nyan_cat.png' }
27
- let(:expected_content) { IO.read(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png')) }
27
+ let(:expected_content) do
28
+ content = File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f|
29
+ f.read
30
+ end
31
+ content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding)
32
+ content
33
+ end
28
34
 
29
35
  def create_resource
30
36
  node = Chef::Node.new
@@ -39,14 +45,31 @@ describe Chef::Resource::RemoteFile do
39
45
  create_resource
40
46
  end
41
47
 
48
+ let(:default_mode) do
49
+ # TODO: Lots of ugly here :(
50
+ # RemoteFile uses FileUtils.cp. FileUtils does a copy by opening the
51
+ # destination file and writing to it. Before 1.9.3, it does not preserve
52
+ # the mode of the copied file. In 1.9.3 and after, it does. So we have to
53
+ # figure out what the default mode ought to be via heuristic.
54
+
55
+ t = Tempfile.new("get-the-mode")
56
+ path = t.path
57
+ path_2 = t.path + "fileutils-mode-test"
58
+ FileUtils.cp(path, path_2)
59
+ t.close
60
+ m = File.stat(path_2).mode
61
+ (07777 & m).to_s(8)
62
+ end
63
+
42
64
  before(:all) do
43
- Thin::Logging.silent = false
44
65
  @server = TinyServer::Manager.new
45
66
  @server.start
46
67
  @api = TinyServer::API.instance
47
68
  @api.clear
48
69
  @api.get("/nyan_cat.png", 200) {
49
- IO.read(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'))
70
+ File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f|
71
+ f.read
72
+ end
50
73
  }
51
74
  end
52
75
 
@@ -55,4 +78,6 @@ describe Chef::Resource::RemoteFile do
55
78
  end
56
79
 
57
80
  it_behaves_like "a file resource"
81
+
82
+ it_behaves_like "a securable resource with reporting"
58
83
  end
@@ -27,14 +27,16 @@ describe Chef::Resource::Template do
27
27
 
28
28
  let(:node) do
29
29
  node = Chef::Node.new
30
- node[:slappiness] = "a warm gun"
30
+ node.normal[:slappiness] = "a warm gun"
31
31
  node
32
32
  end
33
33
 
34
34
  def create_resource
35
35
  cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
36
36
  Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
37
- cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(cookbook_repo))
37
+ cl = Chef::CookbookLoader.new(cookbook_repo)
38
+ cl.load_cookbooks
39
+ cookbook_collection = Chef::CookbookCollection.new(cl)
38
40
  events = Chef::EventDispatch::Dispatcher.new
39
41
  run_context = Chef::RunContext.new(node, cookbook_collection, events)
40
42
  resource = Chef::Resource::Template.new(path, run_context)
@@ -47,8 +49,27 @@ describe Chef::Resource::Template do
47
49
  create_resource
48
50
  end
49
51
 
52
+ let(:default_mode) do
53
+ # TODO: Lots of ugly here :(
54
+ # RemoteFile uses FileUtils.cp. FileUtils does a copy by opening the
55
+ # destination file and writing to it. Before 1.9.3, it does not preserve
56
+ # the mode of the copied file. In 1.9.3 and after, it does. So we have to
57
+ # figure out what the default mode ought to be via heuristic.
58
+
59
+ t = Tempfile.new("get-the-mode")
60
+ path = t.path
61
+ path_2 = t.path + "fileutils-mode-test"
62
+ FileUtils.cp(path, path_2)
63
+ t.close
64
+ m = File.stat(path_2).mode
65
+ (07777 & m).to_s(8)
66
+ end
67
+
68
+
50
69
  it_behaves_like "a file resource"
51
70
 
71
+ it_behaves_like "a securable resource with reporting"
72
+
52
73
  context "when the target file does not exist" do
53
74
  it "creates the template with the rendered content using the variable attribute when the :create action is run" do
54
75
  resource.source('openldap_variable_stuff.conf.erb')
@@ -0,0 +1,238 @@
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
+ require File.expand_path('../../spec_helper', __FILE__)
19
+ require 'chef/client'
20
+
21
+ describe Chef::RunLock do
22
+
23
+ # This behavior is believed to work on windows, but the tests use UNIX APIs.
24
+ describe "when locking the chef-client run", :unix_only => true do
25
+
26
+ ##
27
+ # Lockfile location and helpers
28
+
29
+ let(:random_temp_root) do
30
+ Kernel.srand(Time.now.to_i + Process.pid)
31
+ "/tmp/#{Kernel.rand(Time.now.to_i + Process.pid)}"
32
+ end
33
+
34
+ let(:file_cache_path){ "/var/chef/cache" }
35
+ let(:lockfile){ "#{random_temp_root}/this/long/path/does/not/exist/chef-client-running.pid" }
36
+
37
+ # make sure to start with a clean slate.
38
+ before(:each){ FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
39
+ after(:each){ FileUtils.rm_r(random_temp_root) }
40
+
41
+ def wait_on_lock
42
+ tries = 0
43
+ until File.exist?(lockfile)
44
+ raise "Lockfile never created, abandoning test" if tries > 10
45
+ tries += 1
46
+ sleep 0.1
47
+ end
48
+ end
49
+
50
+ ##
51
+ # Side channel via a pipe allows child processes to send errors to the parent
52
+
53
+ # Don't lazy create the pipe or else we might not share it with subprocesses
54
+ let!(:error_pipe) do
55
+ r,w = IO.pipe
56
+ w.sync = true
57
+ [r,w]
58
+ end
59
+
60
+ let(:error_read) { error_pipe[0] }
61
+ let(:error_write) { error_pipe[1] }
62
+
63
+ after do
64
+ error_read.close unless error_read.closed?
65
+ error_write.close unless error_write.closed?
66
+ end
67
+
68
+ # Send a RuntimeError from the child process to the parent process. Also
69
+ # prints error to $stdout, just in case something goes wrong with the error
70
+ # marshaling stuff.
71
+ def send_side_channel_error(message)
72
+ $stderr.puts(message)
73
+ $stderr.puts(caller)
74
+ e = RuntimeError.new(message)
75
+ error_write.print(Marshal.dump(e))
76
+ end
77
+
78
+ # Read the error (if any) from the error channel. If a marhaled error is
79
+ # present, it is unmarshaled and raised (which will fail the test)
80
+ def raise_side_channel_error!
81
+ error_write.close
82
+ err = error_read.read
83
+ error_read.close
84
+ begin
85
+ # ArgumentError from Marshal.load indicates no data, which we assume
86
+ # means no error in child process.
87
+ raise Marshal.load(err)
88
+ rescue ArgumentError
89
+ nil
90
+ end
91
+ end
92
+
93
+ ##
94
+ # Interprocess synchronization via a pipe. This allows us to control the
95
+ # state of the processes competing over the lock without relying on sleep.
96
+
97
+ let!(:sync_pipe) do
98
+ r,w = IO.pipe
99
+ w.sync = true
100
+ [r,w]
101
+ end
102
+ let(:sync_read) { sync_pipe[0] }
103
+ let(:sync_write) { sync_pipe[1] }
104
+
105
+ after do
106
+ sync_read.close unless sync_read.closed?
107
+ sync_write.close unless sync_write.closed?
108
+ end
109
+
110
+ # Wait on synchronization signal. If not received within the timeout, an
111
+ # error is sent via the error channel, and the process exits.
112
+ def sync_wait
113
+ if IO.select([sync_read], nil, nil, 20).nil?
114
+ # timeout reading from the sync pipe.
115
+ send_side_channel_error("Error syncing processes in run lock test (timeout)")
116
+ exit!(1)
117
+ else
118
+ sync_read.getc
119
+ end
120
+ end
121
+
122
+ # Sends a character in the sync pipe, which wakes ("unlocks") another
123
+ # process that is waiting on the sync signal
124
+ def sync_send
125
+ sync_write.putc("!")
126
+ sync_write.flush
127
+ end
128
+
129
+ ##
130
+ # IPC to record test results in a pipe. Tests can read pipe contents to
131
+ # check that operations occur in the expected order.
132
+
133
+ let!(:results_pipe) do
134
+ r,w = IO.pipe
135
+ w.sync = true
136
+ [r,w]
137
+ end
138
+ let(:results_read) { results_pipe[0] }
139
+ let(:results_write) { results_pipe[1] }
140
+
141
+ after do
142
+ results_read.close unless results_read.closed?
143
+ results_write.close unless results_write.closed?
144
+ end
145
+
146
+ # writes the message to the results pipe for later checking.
147
+ # note that nothing accounts for the pipe filling and waiting forever on a
148
+ # read or write call, so don't put too much data in.
149
+ def record(message)
150
+ results_write.puts(message)
151
+ results_write.flush
152
+ end
153
+
154
+ def results
155
+ results_write.flush
156
+ results_write.close
157
+ message = results_read.read
158
+ results_read.close
159
+ message
160
+ end
161
+
162
+ ##
163
+ # Run lock is the system under test
164
+ let!(:run_lock) { Chef::RunLock.new(:file_cache_path => file_cache_path, :lockfile => lockfile) }
165
+
166
+ it "creates the full path to the lockfile" do
167
+ lambda { run_lock.acquire }.should_not raise_error(Errno::ENOENT)
168
+ File.should exist(lockfile)
169
+ end
170
+
171
+ it "allows only one chef client run per lockfile" do
172
+ # First process, gets the lock and keeps it.
173
+ p1 = fork do
174
+ run_lock.acquire
175
+ record "p1 has lock"
176
+ # Wait until the other process is trying to get the lock:
177
+ sync_wait
178
+ # sleep a little bit to make process p2 wait on the lock
179
+ sleep 2
180
+ record "p1 releasing lock"
181
+ run_lock.release
182
+ exit!(0)
183
+ end
184
+
185
+ # Wait until p1 creates the lockfile
186
+ wait_on_lock
187
+
188
+ p2 = fork do
189
+ # inform process p1 that we're trying to get the lock
190
+ sync_send
191
+ run_lock.acquire
192
+ record "p2 has lock"
193
+ run_lock.release
194
+ exit!(0)
195
+ end
196
+
197
+ Process.waitpid2(p1)
198
+ Process.waitpid2(p2)
199
+
200
+ raise_side_channel_error!
201
+
202
+ expected=<<-E
203
+ p1 has lock
204
+ p1 releasing lock
205
+ p2 has lock
206
+ E
207
+ results.should == expected
208
+ end
209
+
210
+ it "clears the lock if the process dies unexpectedly" do
211
+ p1 = fork do
212
+ run_lock.acquire
213
+ record "p1 has lock"
214
+ sleep 60
215
+ record "p1 still has lock"
216
+ exit! 1
217
+ end
218
+
219
+ wait_on_lock
220
+ Process.kill(:KILL, p1)
221
+ Process.waitpid2(p1)
222
+
223
+
224
+ p2 = fork do
225
+ run_lock.acquire
226
+ record "p2 has lock"
227
+ run_lock.release
228
+ exit! 0
229
+ end
230
+
231
+ Process.waitpid2(p2)
232
+
233
+ results.should =~ /p2 has lock\Z/
234
+ end
235
+ end
236
+
237
+ end
238
+