chef-dk 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +190 -190
  3. data/Gemfile +26 -26
  4. data/LICENSE +201 -201
  5. data/README.md +292 -276
  6. data/Rakefile +18 -18
  7. data/bin/chef +25 -25
  8. data/chef-dk.gemspec +62 -0
  9. data/lib/chef-dk.rb +19 -19
  10. data/lib/chef-dk/authenticated_http.rb +40 -40
  11. data/lib/chef-dk/builtin_commands.rb +60 -60
  12. data/lib/chef-dk/chef_runner.rb +98 -98
  13. data/lib/chef-dk/cli.rb +200 -200
  14. data/lib/chef-dk/command/base.rb +79 -79
  15. data/lib/chef-dk/command/clean_policy_cookbooks.rb +116 -116
  16. data/lib/chef-dk/command/clean_policy_revisions.rb +113 -113
  17. data/lib/chef-dk/command/delete_policy.rb +122 -122
  18. data/lib/chef-dk/command/delete_policy_group.rb +122 -122
  19. data/lib/chef-dk/command/diff.rb +316 -316
  20. data/lib/chef-dk/command/env.rb +90 -90
  21. data/lib/chef-dk/command/exec.rb +45 -45
  22. data/lib/chef-dk/command/export.rb +151 -151
  23. data/lib/chef-dk/command/gem.rb +47 -47
  24. data/lib/chef-dk/command/generate.rb +120 -120
  25. data/lib/chef-dk/command/generator_commands.rb +80 -80
  26. data/lib/chef-dk/command/generator_commands/app.rb +107 -107
  27. data/lib/chef-dk/command/generator_commands/attribute.rb +37 -37
  28. data/lib/chef-dk/command/generator_commands/base.rb +121 -121
  29. data/lib/chef-dk/command/generator_commands/cookbook.rb +153 -119
  30. data/lib/chef-dk/command/generator_commands/cookbook_code_file.rb +100 -100
  31. data/lib/chef-dk/command/generator_commands/cookbook_file.rb +45 -45
  32. data/lib/chef-dk/command/generator_commands/generator_generator.rb +177 -177
  33. data/lib/chef-dk/command/generator_commands/lwrp.rb +36 -36
  34. data/lib/chef-dk/command/generator_commands/policyfile.rb +127 -86
  35. data/lib/chef-dk/command/generator_commands/recipe.rb +36 -36
  36. data/lib/chef-dk/command/generator_commands/repo.rb +125 -96
  37. data/lib/chef-dk/command/generator_commands/template.rb +46 -46
  38. data/lib/chef-dk/command/install.rb +121 -121
  39. data/lib/chef-dk/command/provision.rb +438 -438
  40. data/lib/chef-dk/command/push.rb +118 -118
  41. data/lib/chef-dk/command/push_archive.rb +126 -126
  42. data/lib/chef-dk/command/shell_init.rb +180 -180
  43. data/lib/chef-dk/command/show_policy.rb +165 -165
  44. data/lib/chef-dk/command/undelete.rb +155 -155
  45. data/lib/chef-dk/command/update.rb +129 -129
  46. data/lib/chef-dk/command/verify.rb +534 -490
  47. data/lib/chef-dk/commands_map.rb +115 -115
  48. data/lib/chef-dk/completions/bash.sh.erb +5 -5
  49. data/lib/chef-dk/completions/chef.fish.erb +10 -10
  50. data/lib/chef-dk/completions/zsh.zsh.erb +21 -21
  51. data/lib/chef-dk/component_test.rb +173 -171
  52. data/lib/chef-dk/configurable.rb +57 -57
  53. data/lib/chef-dk/cookbook_metadata.rb +45 -45
  54. data/lib/chef-dk/cookbook_omnifetch.rb +32 -32
  55. data/lib/chef-dk/cookbook_profiler/git.rb +151 -151
  56. data/lib/chef-dk/cookbook_profiler/identifiers.rb +72 -72
  57. data/lib/chef-dk/cookbook_profiler/null_scm.rb +32 -32
  58. data/lib/chef-dk/exceptions.rb +126 -113
  59. data/lib/chef-dk/generator.rb +163 -163
  60. data/lib/chef-dk/helpers.rb +159 -159
  61. data/lib/chef-dk/pager.rb +106 -106
  62. data/lib/chef-dk/policyfile/chef_repo_cookbook_source.rb +138 -122
  63. data/lib/chef-dk/policyfile/chef_server_cookbook_source.rb +54 -54
  64. data/lib/chef-dk/policyfile/community_cookbook_source.rb +97 -82
  65. data/lib/chef-dk/policyfile/comparison_base.rb +124 -124
  66. data/lib/chef-dk/policyfile/cookbook_location_specification.rb +141 -133
  67. data/lib/chef-dk/policyfile/cookbook_locks.rb +466 -466
  68. data/lib/chef-dk/policyfile/cookbook_sources.rb +22 -21
  69. data/lib/chef-dk/policyfile/delivery_supermarket_source.rb +90 -0
  70. data/lib/chef-dk/policyfile/differ.rb +266 -266
  71. data/lib/chef-dk/policyfile/dsl.rb +223 -197
  72. data/lib/chef-dk/policyfile/lister.rb +232 -232
  73. data/lib/chef-dk/policyfile/null_cookbook_source.rb +45 -45
  74. data/lib/chef-dk/policyfile/read_cookbook_for_compat_mode_upload.rb +124 -124
  75. data/lib/chef-dk/policyfile/reports/install.rb +70 -70
  76. data/lib/chef-dk/policyfile/reports/table_printer.rb +58 -58
  77. data/lib/chef-dk/policyfile/reports/upload.rb +70 -70
  78. data/lib/chef-dk/policyfile/solution_dependencies.rb +298 -298
  79. data/lib/chef-dk/policyfile/storage_config.rb +100 -100
  80. data/lib/chef-dk/policyfile/undo_record.rb +142 -142
  81. data/lib/chef-dk/policyfile/undo_stack.rb +130 -130
  82. data/lib/chef-dk/policyfile/uploader.rb +213 -213
  83. data/lib/chef-dk/policyfile_compiler.rb +380 -322
  84. data/lib/chef-dk/policyfile_lock.rb +552 -552
  85. data/lib/chef-dk/policyfile_services/clean_policies.rb +95 -95
  86. data/lib/chef-dk/policyfile_services/clean_policy_cookbooks.rb +125 -125
  87. data/lib/chef-dk/policyfile_services/export_repo.rb +309 -309
  88. data/lib/chef-dk/policyfile_services/install.rb +125 -125
  89. data/lib/chef-dk/policyfile_services/push.rb +114 -114
  90. data/lib/chef-dk/policyfile_services/push_archive.rb +173 -173
  91. data/lib/chef-dk/policyfile_services/rm_policy.rb +142 -142
  92. data/lib/chef-dk/policyfile_services/rm_policy_group.rb +86 -86
  93. data/lib/chef-dk/policyfile_services/show_policy.rb +237 -237
  94. data/lib/chef-dk/policyfile_services/undelete.rb +108 -108
  95. data/lib/chef-dk/policyfile_services/update_attributes.rb +104 -104
  96. data/lib/chef-dk/service_exception_inspectors.rb +25 -25
  97. data/lib/chef-dk/service_exception_inspectors/base.rb +40 -40
  98. data/lib/chef-dk/service_exception_inspectors/http.rb +121 -121
  99. data/lib/chef-dk/service_exceptions.rb +143 -143
  100. data/lib/chef-dk/shell_out.rb +36 -36
  101. data/lib/chef-dk/skeletons/code_generator/files/default/Berksfile +3 -3
  102. data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +100 -100
  103. data/lib/chef-dk/skeletons/code_generator/files/default/cookbook_readmes/README-policy.md +9 -9
  104. data/lib/chef-dk/skeletons/code_generator/files/default/cookbook_readmes/README.md +54 -54
  105. data/lib/chef-dk/skeletons/code_generator/files/default/gitignore +16 -16
  106. data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +28 -28
  107. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/README.md +27 -27
  108. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/attributes/default.rb +7 -7
  109. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/metadata.rb +3 -3
  110. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/recipes/default.rb +8 -8
  111. data/lib/chef-dk/skeletons/code_generator/files/default/repo/data_bags/README.md +58 -58
  112. data/lib/chef-dk/skeletons/code_generator/files/default/repo/data_bags/example/example_item.json +3 -3
  113. data/lib/chef-dk/skeletons/code_generator/files/default/repo/dot-chef-repo.txt +6 -0
  114. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/README.md +9 -9
  115. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/example.json +12 -12
  116. data/lib/chef-dk/skeletons/code_generator/files/default/repo/policies/README.md +24 -0
  117. data/lib/chef-dk/skeletons/code_generator/files/default/repo/roles/README.md +9 -9
  118. data/lib/chef-dk/skeletons/code_generator/files/default/repo/roles/example.json +12 -12
  119. data/lib/chef-dk/skeletons/code_generator/files/default/serverspec_spec_helper.rb +8 -8
  120. data/lib/chef-dk/skeletons/code_generator/files/default/spec_helper.rb +2 -2
  121. data/lib/chef-dk/skeletons/code_generator/files/default/spec_helper_policyfile.rb +2 -0
  122. data/lib/chef-dk/skeletons/code_generator/metadata.rb +8 -8
  123. data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +97 -97
  124. data/lib/chef-dk/skeletons/code_generator/recipes/attribute.rb +12 -12
  125. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +117 -104
  126. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook_file.rb +24 -24
  127. data/lib/chef-dk/skeletons/code_generator/recipes/lwrp.rb +23 -23
  128. data/lib/chef-dk/skeletons/code_generator/recipes/policyfile.rb +8 -8
  129. data/lib/chef-dk/skeletons/code_generator/recipes/recipe.rb +27 -27
  130. data/lib/chef-dk/skeletons/code_generator/recipes/repo.rb +67 -48
  131. data/lib/chef-dk/skeletons/code_generator/recipes/template.rb +32 -32
  132. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.all_rights.erb +3 -3
  133. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.apache2.erb +201 -201
  134. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.gplv2.erb +339 -339
  135. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.gplv3.erb +674 -674
  136. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.mit.erb +21 -21
  137. data/lib/chef-dk/skeletons/code_generator/templates/default/Policyfile.rb.erb +25 -20
  138. data/lib/chef-dk/skeletons/code_generator/templates/default/README.md.erb +4 -4
  139. data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen.yml.erb +21 -16
  140. data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen_policyfile.yml.erb +32 -27
  141. data/lib/chef-dk/skeletons/code_generator/templates/default/metadata.rb.erb +7 -7
  142. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe.rb.erb +5 -5
  143. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe_spec.rb.erb +20 -20
  144. data/lib/chef-dk/skeletons/code_generator/templates/default/repo/gitignore.erb +11 -11
  145. data/lib/chef-dk/skeletons/code_generator/templates/default/serverspec_default_spec.rb.erb +9 -9
  146. data/lib/chef-dk/ui.rb +58 -58
  147. data/lib/chef-dk/version.rb +20 -20
  148. data/lib/kitchen/provisioner/policyfile_zero.rb +189 -193
  149. data/spec/shared/a_file_generator.rb +125 -125
  150. data/spec/shared/a_generated_file.rb +12 -12
  151. data/spec/shared/command_with_ui_object.rb +11 -11
  152. data/spec/shared/custom_generator_cookbook.rb +117 -117
  153. data/spec/shared/fixture_cookbook_checksums.rb +47 -47
  154. data/spec/shared/setup_git_cookbooks.rb +53 -53
  155. data/spec/spec_helper.rb +50 -49
  156. data/spec/test_helpers.rb +84 -84
  157. data/spec/unit/chef_runner_spec.rb +111 -111
  158. data/spec/unit/cli_spec.rb +357 -357
  159. data/spec/unit/command/base_spec.rb +169 -169
  160. data/spec/unit/command/clean_policy_cookbooks_spec.rb +181 -181
  161. data/spec/unit/command/clean_policy_revisions_spec.rb +181 -181
  162. data/spec/unit/command/delete_policy_group_spec.rb +207 -207
  163. data/spec/unit/command/delete_policy_spec.rb +207 -207
  164. data/spec/unit/command/diff_spec.rb +312 -312
  165. data/spec/unit/command/env_spec.rb +52 -52
  166. data/spec/unit/command/exec_spec.rb +179 -179
  167. data/spec/unit/command/export_spec.rb +189 -189
  168. data/spec/unit/command/generate_spec.rb +142 -142
  169. data/spec/unit/command/generator_commands/app_spec.rb +169 -169
  170. data/spec/unit/command/generator_commands/attribute_spec.rb +32 -32
  171. data/spec/unit/command/generator_commands/cookbook_file_spec.rb +32 -32
  172. data/spec/unit/command/generator_commands/cookbook_spec.rb +450 -320
  173. data/spec/unit/command/generator_commands/generator_generator_spec.rb +229 -229
  174. data/spec/unit/command/generator_commands/lwrp_spec.rb +32 -32
  175. data/spec/unit/command/generator_commands/policyfile_spec.rb +225 -125
  176. data/spec/unit/command/generator_commands/recipe_spec.rb +34 -34
  177. data/spec/unit/command/generator_commands/repo_spec.rb +367 -283
  178. data/spec/unit/command/generator_commands/template_spec.rb +32 -32
  179. data/spec/unit/command/install_spec.rb +179 -179
  180. data/spec/unit/command/provision_spec.rb +592 -592
  181. data/spec/unit/command/push_archive_spec.rb +153 -153
  182. data/spec/unit/command/push_spec.rb +199 -199
  183. data/spec/unit/command/shell_init_spec.rb +329 -329
  184. data/spec/unit/command/show_policy_spec.rb +235 -235
  185. data/spec/unit/command/undelete_spec.rb +246 -246
  186. data/spec/unit/command/update_spec.rb +251 -251
  187. data/spec/unit/command/verify_spec.rb +325 -323
  188. data/spec/unit/commands_map_spec.rb +57 -57
  189. data/spec/unit/component_test_spec.rb +126 -126
  190. data/spec/unit/cookbook_metadata_spec.rb +98 -98
  191. data/spec/unit/cookbook_profiler/git_spec.rb +176 -176
  192. data/spec/unit/cookbook_profiler/identifiers_spec.rb +83 -83
  193. data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_one.rb +9 -9
  194. data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_two.rb +9 -9
  195. data/spec/unit/fixtures/command/cli_test_command.rb +26 -26
  196. data/spec/unit/fixtures/command/explicit_path_example.rb +7 -7
  197. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -16
  198. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/Berksfile +3 -3
  199. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -4
  200. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/chefignore +96 -96
  201. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -8
  202. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -8
  203. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/.kitchen.yml +16 -16
  204. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/Berksfile +3 -3
  205. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/README.md +4 -4
  206. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/chefignore +96 -96
  207. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/metadata.rb +8 -8
  208. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/recipes/default.rb +8 -8
  209. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/.kitchen.yml +16 -16
  210. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/Berksfile +3 -3
  211. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/README.md +4 -4
  212. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/chefignore +96 -96
  213. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/metadata.rb +8 -8
  214. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/recipes/default.rb +8 -8
  215. data/spec/unit/fixtures/cookbooks_api/pruned_small_universe.json +1321 -1321
  216. data/spec/unit/fixtures/cookbooks_api/small_universe.json +2987 -2987
  217. data/spec/unit/fixtures/cookbooks_api/universe.json +1 -1
  218. data/spec/unit/fixtures/cookbooks_api/update_fixtures.rb +36 -36
  219. data/spec/unit/fixtures/dev_cookbooks/README.md +16 -16
  220. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/integration_test +2 -2
  221. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/verify_me +5 -5
  222. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/chef/verify_me +3 -3
  223. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/test-kitchen/verify_me +2 -2
  224. data/spec/unit/fixtures/example_cookbook/.gitignore +17 -17
  225. data/spec/unit/fixtures/example_cookbook/.kitchen.yml +16 -16
  226. data/spec/unit/fixtures/example_cookbook/Berksfile +3 -3
  227. data/spec/unit/fixtures/example_cookbook/README.md +4 -4
  228. data/spec/unit/fixtures/example_cookbook/chefignore +96 -96
  229. data/spec/unit/fixtures/example_cookbook/metadata.rb +8 -8
  230. data/spec/unit/fixtures/example_cookbook/recipes/default.rb +8 -8
  231. data/spec/unit/fixtures/example_cookbook_metadata_json_only/.gitignore +17 -17
  232. data/spec/unit/fixtures/example_cookbook_metadata_json_only/.kitchen.yml +16 -16
  233. data/spec/unit/fixtures/example_cookbook_metadata_json_only/Berksfile +3 -3
  234. data/spec/unit/fixtures/example_cookbook_metadata_json_only/README.md +4 -4
  235. data/spec/unit/fixtures/example_cookbook_metadata_json_only/chefignore +96 -96
  236. data/spec/unit/fixtures/example_cookbook_metadata_json_only/metadata.json +5 -5
  237. data/spec/unit/fixtures/example_cookbook_metadata_json_only/recipes/default.rb +8 -8
  238. data/spec/unit/fixtures/example_cookbook_no_metadata/.gitignore +17 -17
  239. data/spec/unit/fixtures/example_cookbook_no_metadata/.kitchen.yml +16 -16
  240. data/spec/unit/fixtures/example_cookbook_no_metadata/Berksfile +3 -3
  241. data/spec/unit/fixtures/example_cookbook_no_metadata/README.md +4 -4
  242. data/spec/unit/fixtures/example_cookbook_no_metadata/chefignore +96 -96
  243. data/spec/unit/fixtures/example_cookbook_no_metadata/recipes/default.rb +8 -8
  244. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/README.md +4 -4
  245. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/chefignore +96 -96
  246. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/metadata.rb +8 -8
  247. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/recipes/default.rb +8 -8
  248. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/Berksfile +3 -3
  249. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/README.md +4 -4
  250. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/chefignore +96 -96
  251. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/metadata.rb +9 -9
  252. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/recipes/default.rb +8 -8
  253. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/.kitchen.yml +16 -16
  254. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/Berksfile +3 -3
  255. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/README.md +4 -4
  256. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/chefignore +96 -96
  257. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/metadata.rb +8 -8
  258. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/recipes/default.rb +8 -8
  259. data/spec/unit/fixtures/local_path_cookbooks/metadata-missing/README.md +2 -2
  260. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -16
  261. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -4
  262. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -8
  263. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -8
  264. data/spec/unit/generator_spec.rb +120 -120
  265. data/spec/unit/helpers_spec.rb +92 -92
  266. data/spec/unit/pager_spec.rb +119 -119
  267. data/spec/unit/policyfile/chef_repo_cookbook_source_spec.rb +93 -66
  268. data/spec/unit/policyfile/chef_server_cookbook_source_spec.rb +34 -34
  269. data/spec/unit/policyfile/community_cookbook_source_spec.rb +84 -51
  270. data/spec/unit/policyfile/comparison_base_spec.rb +343 -343
  271. data/spec/unit/policyfile/cookbook_location_specification_spec.rb +257 -252
  272. data/spec/unit/policyfile/cookbook_locks_spec.rb +529 -529
  273. data/spec/unit/policyfile/delivery_supermarket_source_spec.rb +130 -0
  274. data/spec/unit/policyfile/differ_spec.rb +687 -687
  275. data/spec/unit/policyfile/lister_spec.rb +272 -272
  276. data/spec/unit/policyfile/null_cookbook_source_spec.rb +35 -35
  277. data/spec/unit/policyfile/read_cookbook_for_compat_mode_upload_spec.rb +92 -92
  278. data/spec/unit/policyfile/reports/install_spec.rb +115 -115
  279. data/spec/unit/policyfile/reports/upload_spec.rb +96 -96
  280. data/spec/unit/policyfile/solution_dependencies_spec.rb +145 -145
  281. data/spec/unit/policyfile/storage_config_spec.rb +172 -172
  282. data/spec/unit/policyfile/undo_record_spec.rb +260 -260
  283. data/spec/unit/policyfile/undo_stack_spec.rb +266 -266
  284. data/spec/unit/policyfile/uploader_spec.rb +410 -410
  285. data/spec/unit/policyfile_demands_spec.rb +997 -876
  286. data/spec/unit/policyfile_evaluation_spec.rb +557 -441
  287. data/spec/unit/policyfile_lock_build_spec.rb +1056 -1056
  288. data/spec/unit/policyfile_lock_install_spec.rb +138 -138
  289. data/spec/unit/policyfile_lock_serialization_spec.rb +425 -425
  290. data/spec/unit/policyfile_lock_validation_spec.rb +611 -611
  291. data/spec/unit/policyfile_services/clean_policies_spec.rb +236 -236
  292. data/spec/unit/policyfile_services/clean_policy_cookbooks_spec.rb +275 -275
  293. data/spec/unit/policyfile_services/export_repo_spec.rb +439 -439
  294. data/spec/unit/policyfile_services/install_spec.rb +191 -191
  295. data/spec/unit/policyfile_services/push_archive_spec.rb +345 -345
  296. data/spec/unit/policyfile_services/push_spec.rb +233 -233
  297. data/spec/unit/policyfile_services/rm_policy_group_spec.rb +241 -241
  298. data/spec/unit/policyfile_services/rm_policy_spec.rb +266 -266
  299. data/spec/unit/policyfile_services/show_policy_spec.rb +889 -889
  300. data/spec/unit/policyfile_services/undelete_spec.rb +304 -304
  301. data/spec/unit/policyfile_services/update_attributes_spec.rb +217 -217
  302. data/spec/unit/service_exception_inspectors/base_spec.rb +43 -43
  303. data/spec/unit/service_exception_inspectors/http_spec.rb +140 -140
  304. data/spec/unit/shell_out_spec.rb +34 -34
  305. data/warning.txt +9 -0
  306. metadata +18 -5
@@ -1,876 +1,997 @@
1
- #
2
- # Copyright:: Copyright (c) 2014 Chef Software Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require 'spec_helper'
19
- require 'chef-dk/policyfile_compiler'
20
-
21
- describe ChefDK::PolicyfileCompiler, "when expressing the Policyfile graph demands" do
22
-
23
- let(:run_list) { [] }
24
-
25
- let(:default_source) { nil }
26
-
27
- let(:external_cookbook_universe) { {} }
28
-
29
- let(:policyfile) do
30
- policyfile = ChefDK::PolicyfileCompiler.new.build do |p|
31
-
32
- p.default_source(*default_source) if default_source
33
- p.run_list(*run_list)
34
-
35
- allow(p.default_source.first).to receive(:universe_graph).and_return(external_cookbook_universe)
36
- end
37
-
38
- policyfile
39
- end
40
-
41
- let(:demands) { policyfile.graph_demands }
42
-
43
- shared_context("community default source") do
44
-
45
- let(:default_source) { [:community] }
46
-
47
- let(:external_cookbook_universe) do
48
- {
49
- "nginx" => {
50
- "1.0.0" => [ [ "apt", "~> 2.0" ], [ "yum", "~> 1.0" ] ],
51
- "1.2.0" => [ [ "apt", "~> 2.1" ], [ "yum", "~> 1.0" ] ],
52
- "2.0.0" => [ [ "apt", "~> 3.0" ], [ "yum", "~> 1.0" ], [ "ohai", "~> 2.0" ] ]
53
- },
54
-
55
- "mysql" => {
56
- "3.0.0" => [ [ "apt", "~> 2.0" ], [ "yum", "~> 1.0" ] ],
57
- "4.0.0" => [ [ "apt", "~> 2.4" ], [ "yum", "~> 1.1" ] ],
58
- "5.0.0" => [ ],
59
- },
60
-
61
- "local-cookbook" => {
62
- "9.9.9" => [ ["local-cookbook-on-community-dep", "= 1.0.0"] ]
63
- },
64
-
65
- "git-sourced-cookbook" => {
66
- "10.10.10" => [ ["git-sourced-cookbook-dep", "= 1.0.0"] ]
67
- },
68
-
69
- "remote-cb" => {
70
- "0.1.0" => [ ],
71
- "1.1.1" => [ ]
72
- },
73
-
74
- "remote-cb-two" => {
75
- "0.1.0" => [ ],
76
- "1.1.1" => [ ]
77
- },
78
-
79
- "local-cookbook-dep-one" => {
80
- "1.5.0" => [ ]
81
- },
82
-
83
- "git-sourced-cookbook-dep" => {
84
- "2.8.0" => [ ]
85
- }
86
-
87
- }
88
- end
89
- end
90
-
91
- shared_context("chef server default source") do
92
-
93
- let(:default_source) { [:chef_server, "https://chef.example.com"] }
94
-
95
- let(:external_cookbook_universe) do
96
- {
97
- "nginx" => {
98
- "1.0.0" => [ [ "apt", "~> 2.0" ], [ "yum", "~> 1.0" ] ],
99
- },
100
-
101
- "mysql" => {
102
- "5.0.0" => [ ],
103
- },
104
-
105
- "local-cookbook" => {
106
- "9.9.9" => [ ["local-cookbook-on-community-dep", "= 1.0.0"] ]
107
- },
108
-
109
- "remote-cb" => {
110
- "1.1.1" => [ ]
111
- },
112
-
113
- "git-sourced-cookbook" => {
114
- "10.10.10" => [ ["git-sourced-cookbook-dep", "= 1.0.0"] ]
115
- },
116
-
117
- "private-cookbook" => {
118
- "0.1.0" => [ ]
119
- },
120
-
121
- "local-cookbook-dep-one" => {
122
- "1.6.0" => [ ]
123
- },
124
-
125
- "git-sourced-cookbook-dep" => {
126
- "2.9.0" => [ ]
127
- }
128
-
129
-
130
- }
131
- end
132
- end
133
-
134
- describe "when normalizing run_list items" do
135
-
136
- it "normalizes a bare cookbook name" do
137
- policyfile.run_list("local-cookbook")
138
- expect(policyfile.normalized_run_list).to eq(["recipe[local-cookbook::default]"])
139
- end
140
-
141
- it "normalizes a bare cookbook::recipe item" do
142
- policyfile.run_list("local-cookbook::server")
143
- expect(policyfile.normalized_run_list).to eq(["recipe[local-cookbook::server]"])
144
- end
145
-
146
- it "normalizes a recipe[] item with implicit default" do
147
- policyfile.run_list("recipe[local-cookbook]")
148
- expect(policyfile.normalized_run_list).to eq(["recipe[local-cookbook::default]"])
149
- end
150
-
151
- it "does not modify a fully qualified recipe" do
152
- policyfile.run_list("recipe[local-cookbook::jazz_hands]")
153
- expect(policyfile.normalized_run_list).to eq(["recipe[local-cookbook::jazz_hands]"])
154
- end
155
-
156
- describe "in an alternate run list" do
157
-
158
- it "normalizes a bare cookbook name" do
159
- policyfile.named_run_list(:foo, "local-cookbook")
160
- expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::default]"])
161
- end
162
-
163
- it "normalizes a bare cookbook::recipe item" do
164
- policyfile.named_run_list(:foo, "local-cookbook::server")
165
- expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::server]"])
166
- end
167
-
168
- it "normalizes a recipe[] item with implicit default" do
169
- policyfile.named_run_list(:foo, "recipe[local-cookbook]")
170
- expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::default]"])
171
- end
172
-
173
- it "does not modify a fully qualified recipe" do
174
- policyfile.named_run_list(:foo, "recipe[local-cookbook::jazz_hands]")
175
- expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::jazz_hands]"])
176
- end
177
-
178
- end
179
- end
180
-
181
- before do
182
- expect(policyfile.errors).to eq([])
183
- end
184
-
185
- context "Given no local or git cookbooks, no default source, and an empty run list" do
186
-
187
- let(:run_list) { [] }
188
-
189
- it "has an empty set of demands" do
190
- expect(demands).to eq([])
191
- end
192
-
193
- it "uses an empty universe for dependencies" do
194
- expect(policyfile.artifacts_graph).to eq({})
195
- end
196
-
197
- it "has an empty solution" do
198
- expect(policyfile).to receive(:ensure_cache_dir_exists)
199
- expect(policyfile.graph_solution).to eq({})
200
- end
201
-
202
- it "has an empty set of solution_dependencies" do
203
- expected_solution_deps = {
204
- "Policyfile" => [],
205
- "dependencies" => {}
206
- }
207
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
208
- end
209
- end
210
-
211
- context "Given a run list and no local or git cookbooks" do
212
-
213
- let(:run_list) { ["remote-cb"] }
214
-
215
- context "with no default source" do
216
-
217
- it "fails to locate the cookbook" do
218
- expect { policyfile.graph_solution }.to raise_error(Solve::Errors::NoSolutionError)
219
- end
220
-
221
- context "when the policyfile also has a `cookbook` entry for the run list item" do
222
-
223
- before do
224
- policyfile.dsl.cookbook "remote-cb"
225
- end
226
-
227
- it "fails to locate the cookbook" do
228
- expect { policyfile.graph_solution }.to raise_error(Solve::Errors::NoSolutionError)
229
- end
230
-
231
- end
232
-
233
- end
234
-
235
- context "And the default source is the community site" do
236
-
237
- include_context "community default source"
238
-
239
- it "has an unconstrained demand on the required cookbooks" do
240
- expect(demands).to eq([["remote-cb", ">= 0.0.0"]])
241
- end
242
-
243
- it "uses the community site universe for dependencies" do
244
- expect(policyfile.artifacts_graph).to eq(external_cookbook_universe)
245
- end
246
-
247
- it "uses the community cookbook in the solution" do
248
- expect(policyfile).to receive(:ensure_cache_dir_exists)
249
- expect(policyfile.graph_solution).to eq({"remote-cb" => "1.1.1"})
250
- end
251
-
252
- it "includes the cookbook in the solution dependencies" do
253
- expected_solution_deps = {
254
- "Policyfile" => [],
255
- "dependencies" => { "remote-cb (1.1.1)" => [] }
256
- }
257
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
258
- end
259
-
260
- end
261
-
262
- context "And the default source is the chef-server" do
263
-
264
- include_context "chef server default source"
265
-
266
- it "has an unconstrained demand on the required cookbooks" do
267
- expect(demands).to eq([["remote-cb", ">= 0.0.0"]])
268
- end
269
-
270
- it "uses the chef-server universe for dependencies" do
271
- expect(policyfile.artifacts_graph).to eq(external_cookbook_universe)
272
- end
273
-
274
- it "uses the chef-server cookbook in the solution" do
275
- expect(policyfile).to receive(:ensure_cache_dir_exists)
276
- expect(policyfile.graph_solution).to eq({"remote-cb" => "1.1.1"})
277
- end
278
- end
279
- end
280
-
281
- context "Given a local cookbook and only that cookbook in the run list" do
282
-
283
- let(:run_list) { ['local-cookbook'] }
284
-
285
- before do
286
- policyfile.dsl.cookbook('local-cookbook', path: "/foo")
287
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
288
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([])
289
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached).and_return(true)
290
- end
291
-
292
- it "demands a solution using the local cookbook" do
293
- expect(demands).to eq([["local-cookbook", "= 2.3.4"]])
294
- end
295
-
296
- it "includes the local cookbook in the artifact universe" do
297
- expected_artifacts_graph = {
298
- "local-cookbook" => { "2.3.4" => [] }
299
- }
300
- expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
301
- end
302
-
303
- it "includes the cookbook in the solution dependencies" do
304
- expected_solution_deps = {
305
- "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
306
- "dependencies" => { "local-cookbook (2.3.4)" => [] }
307
- }
308
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
309
- end
310
-
311
- end
312
-
313
- context "Given a local cookbook with a dependency and only the local cookbook in the run list" do
314
-
315
- let(:run_list) { ['local-cookbook'] }
316
-
317
- context "And the default source is the community site" do
318
-
319
- include_context "community default source"
320
-
321
- before do
322
- policyfile.dsl.cookbook("local-cookbook", path: "foo/")
323
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached)
324
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
325
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([ [ "local-cookbook-dep-one", "~> 1.0"] ])
326
- end
327
-
328
- it "demands a solution using the local cookbook" do
329
- expect(demands).to eq([["local-cookbook", "= 2.3.4"]])
330
- end
331
-
332
- it "overrides the community site universe with the local cookbook and its dependencies" do
333
- expected_artifacts_graph = external_cookbook_universe.dup
334
- expected_artifacts_graph["local-cookbook"] = {
335
- "2.3.4" => [ [ "local-cookbook-dep-one", "~> 1.0" ] ]
336
- }
337
- expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
338
- end
339
-
340
- it "uses the local cookbook in the solution and gets dependencies remotely" do
341
- expect(policyfile).to receive(:ensure_cache_dir_exists)
342
- expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "local-cookbook-dep-one" => "1.5.0"})
343
- end
344
-
345
- it "includes the cookbook and dependencies in the solution dependencies" do
346
- expected_solution_deps = {
347
- "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
348
- "dependencies" => {
349
- "local-cookbook (2.3.4)" => [[ "local-cookbook-dep-one", "~> 1.0"]],
350
- "local-cookbook-dep-one (1.5.0)" => []
351
- }
352
-
353
- }
354
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
355
- end
356
-
357
- end
358
- context "And the default source is the chef server" do
359
-
360
- include_context "chef server default source"
361
-
362
- before do
363
- policyfile.dsl.cookbook("local-cookbook", path: "foo/")
364
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached)
365
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
366
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([ [ "local-cookbook-dep-one", "~> 1.0"] ])
367
- end
368
-
369
- it "demands a solution using the local cookbook" do
370
- expect(demands).to eq([["local-cookbook", "= 2.3.4"]])
371
- end
372
-
373
- it "overrides the chef server universe with the local cookbook and its dependencies" do
374
- # all versions of "local-cookbook" from the cookbook site universe
375
- # should be removed so we won't run into trouble if there's a community
376
- # cookbook with the same name and version but different deps.
377
- expected_artifacts_graph = external_cookbook_universe.dup
378
- expected_artifacts_graph["local-cookbook"] = {
379
- "2.3.4" => [ [ "local-cookbook-dep-one", "~> 1.0" ] ]
380
- }
381
- expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
382
- end
383
-
384
- it "uses the local cookbook in the solution and gets dependencies remotely" do
385
- expect(policyfile).to receive(:ensure_cache_dir_exists)
386
- expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "local-cookbook-dep-one" => "1.6.0"})
387
- end
388
-
389
- it "includes the cookbook and dependencies in the solution dependencies" do
390
- expected_solution_deps = {
391
- "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
392
- "dependencies" => {
393
- "local-cookbook (2.3.4)" => [[ "local-cookbook-dep-one", "~> 1.0"]],
394
- "local-cookbook-dep-one (1.6.0)" => []
395
- }
396
-
397
- }
398
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
399
- end
400
-
401
- end
402
- end
403
-
404
- context "Given a git-sourced cookbook with no dependencies and only the git cookbook in the run list" do
405
-
406
- let(:run_list) { ["git-sourced-cookbook"] }
407
-
408
- before do
409
- policyfile.dsl.cookbook("git-sourced-cookbook", git: "git://git.example.org:user/a-cookbook.git")
410
- allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:ensure_cached)
411
- allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:version).and_return("8.6.7")
412
- allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:dependencies).and_return([ ])
413
- end
414
-
415
- it "demands a solution using the git sourced cookbook" do
416
- expect(demands).to eq([["git-sourced-cookbook", "= 8.6.7"]])
417
- end
418
-
419
- it "includes the git-sourced cookbook in the universe graph" do
420
- expected_artifacts_graph = {
421
- "git-sourced-cookbook" => { "8.6.7" => [ ] }
422
- }
423
- expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
424
- end
425
-
426
- it "uses the git sourced cookbook in the solution" do
427
- expect(policyfile).to receive(:ensure_cache_dir_exists)
428
- expect(policyfile.graph_solution).to eq({"git-sourced-cookbook" => "8.6.7"})
429
- end
430
-
431
- it "includes the cookbook and dependencies in the solution dependencies" do
432
- expected_solution_deps = {
433
- "Policyfile" => [ [ "git-sourced-cookbook", ">= 0.0.0" ] ],
434
- "dependencies" => {
435
- "git-sourced-cookbook (8.6.7)" => []
436
- }
437
-
438
- }
439
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
440
- end
441
-
442
- end
443
-
444
- context "Given a git-sourced cookbook with a dependency and only the git cookbook in the run list" do
445
-
446
- let(:run_list) { ["git-sourced-cookbook"] }
447
-
448
- before do
449
- policyfile.dsl.cookbook("git-sourced-cookbook", git: "git://git.example.org:user/a-cookbook.git")
450
- allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:ensure_cached)
451
- allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:version).and_return("8.6.7")
452
- allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:dependencies).and_return([ ["git-sourced-cookbook-dep", "~> 2.2" ] ])
453
- end
454
-
455
- context "And the default source is the community site" do
456
-
457
- include_context "community default source"
458
-
459
- it "demands a solution using the git sourced cookbook" do
460
- expect(demands).to eq([["git-sourced-cookbook", "= 8.6.7"]])
461
- end
462
-
463
- it "overrides the community site universe with the git-sourced cookbook and deps" do
464
- expected_artifacts_graph = external_cookbook_universe.dup
465
- expected_artifacts_graph["git-sourced-cookbook"] = {
466
- "8.6.7" => [ ["git-sourced-cookbook-dep", "~> 2.2" ] ]
467
- }
468
- expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
469
- end
470
-
471
- it "uses the git sourced cookbook with remote dependencies in the solution" do
472
- expect(policyfile).to receive(:ensure_cache_dir_exists)
473
- expect(policyfile.graph_solution).to eq({"git-sourced-cookbook" => "8.6.7", "git-sourced-cookbook-dep" => "2.8.0"})
474
- end
475
-
476
- it "includes the cookbook and dependencies in the solution dependencies" do
477
- expected_solution_deps = {
478
- "Policyfile" => [ [ "git-sourced-cookbook", ">= 0.0.0" ] ],
479
- "dependencies" => {
480
- "git-sourced-cookbook (8.6.7)" => [ [ "git-sourced-cookbook-dep", "~> 2.2" ] ],
481
- "git-sourced-cookbook-dep (2.8.0)" => []
482
- }
483
-
484
- }
485
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
486
- end
487
-
488
- end
489
-
490
- context "And the default source is the chef server" do
491
-
492
- include_context "chef server default source"
493
-
494
- it "demands a solution using the git sourced cookbook" do
495
- expect(demands).to eq([["git-sourced-cookbook", "= 8.6.7"]])
496
- end
497
-
498
- it "overrides the chef server universe with the git-sourced cookbook and deps" do
499
- expected_artifacts_graph = external_cookbook_universe.dup
500
- expected_artifacts_graph["git-sourced-cookbook"] = {
501
- "8.6.7" => [ ["git-sourced-cookbook-dep", "~> 2.2" ] ]
502
- }
503
- expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
504
- end
505
-
506
- it "uses the git sourced cookbook with remote dependencies in the solution" do
507
- expect(policyfile).to receive(:ensure_cache_dir_exists)
508
- expect(policyfile.graph_solution).to eq({"git-sourced-cookbook" => "8.6.7", "git-sourced-cookbook-dep" => "2.9.0"})
509
- end
510
-
511
- it "includes the cookbook and dependencies in the solution dependencies" do
512
- expected_solution_deps = {
513
- "Policyfile" => [ [ "git-sourced-cookbook", ">= 0.0.0" ] ],
514
- "dependencies" => {
515
- "git-sourced-cookbook (8.6.7)" => [ [ "git-sourced-cookbook-dep", "~> 2.2" ] ],
516
- "git-sourced-cookbook-dep (2.9.0)" => []
517
- }
518
-
519
- }
520
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
521
- end
522
-
523
- end
524
- end
525
-
526
- context "Given a local cookbook with a run list containing the local cookbook and another cookbook" do
527
-
528
- let(:run_list) { ['local-cookbook', 'remote-cb'] }
529
-
530
- before do
531
- policyfile.dsl.cookbook("local-cookbook", path: "foo/")
532
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached)
533
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
534
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([])
535
- end
536
-
537
- context "And the default source is the community site" do
538
-
539
- include_context "community default source"
540
-
541
- it "demands a solution with the local cookbook and any version of the other cookbook" do
542
- expect(demands).to eq([["local-cookbook", "= 2.3.4"], ["remote-cb", ">= 0.0.0"]])
543
- end
544
-
545
- it "overrides the community universe with the local cookbook and deps" do
546
- expected_artifacts_graph = external_cookbook_universe.dup
547
- expected_artifacts_graph["local-cookbook"] = { "2.3.4" => [ ] }
548
- expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
549
- end
550
-
551
- it "uses the locally specified cookbook and remote cookbooks in the solution" do
552
- expect(policyfile).to receive(:ensure_cache_dir_exists)
553
- expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "remote-cb" => "1.1.1"})
554
- end
555
-
556
- it "includes the cookbook and dependencies in the solution dependencies" do
557
- expected_solution_deps = {
558
- "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
559
- "dependencies" => {
560
- "local-cookbook (2.3.4)" => [],
561
- "remote-cb (1.1.1)" => []
562
- }
563
-
564
- }
565
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
566
- end
567
-
568
- end
569
-
570
- context "And the default source is the chef server" do
571
-
572
- include_context "chef server default source"
573
-
574
- it "demands a solution with the local cookbook and any version of the other cookbook" do
575
- expect(demands).to eq([["local-cookbook", "= 2.3.4"], ["remote-cb", ">= 0.0.0"]])
576
- end
577
-
578
- it "overrides the chef-server universe with the local cookbook and deps" do
579
- expected_artifacts_graph = external_cookbook_universe.dup
580
- expected_artifacts_graph["local-cookbook"] = { "2.3.4" => [ ] }
581
- expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
582
- end
583
-
584
- it "uses the locally specified cookbook and remote cookbooks in the solution" do
585
- expect(policyfile).to receive(:ensure_cache_dir_exists)
586
- expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "remote-cb" => "1.1.1"})
587
- end
588
-
589
- it "includes the cookbook and dependencies in the solution dependencies" do
590
- expected_solution_deps = {
591
- "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
592
- "dependencies" => {
593
- "local-cookbook (2.3.4)" => [],
594
- "remote-cb (1.1.1)" => []
595
- }
596
-
597
- }
598
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
599
- end
600
-
601
- end
602
- end
603
-
604
- context "given a cookbook with a version constraint in the policyfile" do
605
-
606
- include_context "community default source"
607
-
608
- let(:run_list) { ['remote-cb'] }
609
-
610
- before do
611
- policyfile.dsl.cookbook("remote-cb", "~> 0.1")
612
- end
613
-
614
- it "demands a solution that matches the version constraint in the policyfile" do
615
- expect(demands).to eq([["remote-cb", "~> 0.1"]])
616
- end
617
-
618
- it "emits a solution that satisfies the policyfile constraint" do
619
- expect(policyfile).to receive(:ensure_cache_dir_exists)
620
- expect(policyfile.graph_solution).to eq({"remote-cb" => "0.1.0"})
621
- end
622
-
623
- it "includes the policyfile constraint in the solution dependencies" do
624
- expected_solution_deps = {
625
- "Policyfile" => [ [ "remote-cb", "~> 0.1" ] ],
626
- "dependencies" => {
627
- "remote-cb (0.1.0)" => []
628
- }
629
-
630
- }
631
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
632
- end
633
- end
634
-
635
- context "given a cookbook that isn't in the run list is specified with a version constraint in the policyfile" do
636
-
637
- include_context "community default source"
638
-
639
- let(:run_list) { ['local-cookbook'] }
640
-
641
- before do
642
- policyfile.dsl.cookbook("remote-cb", "~> 0.1")
643
-
644
- policyfile.dsl.cookbook("local-cookbook", path: "foo/")
645
-
646
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached)
647
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
648
- allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([])
649
- end
650
-
651
- it "demands a solution that matches the version constraint in the policyfile" do
652
- expect(demands).to eq([["local-cookbook", "= 2.3.4"], ["remote-cb", "~> 0.1"]])
653
- end
654
-
655
- it "emits a solution that satisfies the policyfile constraint" do
656
- expect(policyfile).to receive(:ensure_cache_dir_exists)
657
- expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "remote-cb" => "0.1.0"})
658
- end
659
-
660
- it "includes the policyfile constraint in the solution dependencies" do
661
- expected_solution_deps = {
662
- "Policyfile" => [ [ "remote-cb", "~> 0.1" ], [ "local-cookbook", ">= 0.0.0"] ],
663
- "dependencies" => {
664
- "local-cookbook (2.3.4)" => [],
665
- "remote-cb (0.1.0)" => []
666
- }
667
-
668
- }
669
- expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
670
- end
671
- end
672
-
673
- context "Given a run_list and named run_lists" do
674
-
675
- before do
676
- policyfile.dsl.named_run_list(:foo, 'local-cookbook', 'nginx')
677
- policyfile.dsl.named_run_list(:bar, 'remote-cb', 'nginx')
678
- policyfile.dsl.run_list('private-cookbook', 'nginx')
679
- end
680
-
681
- it "demands a solution that satisfies all of the run lists, with no duplicates" do
682
- expect(policyfile.graph_demands).to include(["private-cookbook", ">= 0.0.0"])
683
- expect(policyfile.graph_demands).to include(["nginx", ">= 0.0.0"])
684
- expect(policyfile.graph_demands).to include(["remote-cb", ">= 0.0.0"])
685
- expect(policyfile.graph_demands).to include(["local-cookbook", ">= 0.0.0"])
686
-
687
- # ensure there are no duplicates:
688
- expected_demands = [["private-cookbook", ">= 0.0.0"],
689
- ["nginx", ">= 0.0.0"],
690
- ["local-cookbook", ">= 0.0.0"],
691
- ["remote-cb", ">= 0.0.0"]]
692
- expect(policyfile.graph_demands).to eq(expected_demands)
693
- end
694
-
695
- end
696
-
697
- context "when using multiple default sources" do
698
-
699
- include_context "community default source"
700
-
701
- let(:run_list) { [ 'repo-cookbook-one', 'remote-cb', 'remote-cb-two' ] }
702
-
703
- before do
704
- policyfile.default_source(:chef_repo, "path/to/repo")
705
- allow(policyfile.default_source.last).to receive(:universe_graph).and_return(repo_cookbook_universe)
706
- end
707
-
708
- context "when the graphs don't conflict" do
709
-
710
- before do
711
- # This is on the community site
712
- policyfile.dsl.cookbook("remote-cb")
713
- end
714
-
715
- let(:repo_cookbook_universe) do
716
- {
717
- "repo-cookbook-one" => {
718
- "1.0.0" => [ ]
719
- },
720
-
721
- "repo-cookbook-two" => {
722
- "9.9.9" => [ ["repo-cookbook-on-community-dep", "= 1.0.0"] ]
723
- },
724
-
725
- "private-cookbook" => {
726
- "0.1.0" => [ ]
727
- }
728
- }
729
- end
730
-
731
- it "merges the graphs" do
732
- merged = policyfile.remote_artifacts_graph
733
- expected = external_cookbook_universe.merge(repo_cookbook_universe)
734
-
735
- expect(merged).to eq(expected)
736
- end
737
-
738
- it "solves the graph demands using cookbooks from both sources" do
739
- expected = {"repo-cookbook-one" => "1.0.0", "remote-cb" => "1.1.1", "remote-cb-two" => "1.1.1"}
740
- expect(policyfile.graph_solution).to eq(expected)
741
- end
742
-
743
- it "finds the location of a cookbook declared via explicit `cookbook` with no source options" do
744
- community_source = policyfile.default_source.first
745
-
746
- expected_source_options = { artifactserver: "https://chef.example/url", version: "1.1.1" }
747
-
748
- expect(community_source).to be_a(ChefDK::Policyfile::CommunityCookbookSource)
749
- expect(community_source).to receive(:source_options_for).
750
- with("remote-cb", "1.1.1").
751
- and_return(expected_source_options)
752
-
753
- location_spec = policyfile.create_spec_for_cookbook("remote-cb", "1.1.1")
754
- expect(location_spec.source_options).to eq(expected_source_options)
755
- end
756
-
757
- it "sources cookbooks from the correct source when the cookbook doesn't have a `cookbook` entry" do
758
- # these don't have `cookbook` entries in the Policyfile.rb, so they are nil
759
- expect(policyfile.cookbook_location_spec_for("repo-cookbook-one")).to be_nil
760
- expect(policyfile.cookbook_location_spec_for("remote-cb-two")).to be_nil
761
-
762
- # We have to stub #source_options_for or else we'd need to stub the
763
- # source options data inside the source object. That's getting a bit
764
- # too deep into the source object's internals.
765
-
766
- expected_repo_options = { path: "path/to/cookbook", version: "1.0.0" }
767
- repo_source = policyfile.default_source.last
768
- expect(repo_source).to be_a(ChefDK::Policyfile::ChefRepoCookbookSource)
769
- expect(repo_source).to receive(:source_options_for).
770
- with("repo-cookbook-one", "1.0.0").
771
- and_return(expected_repo_options)
772
-
773
-
774
- repo_cb_location = policyfile.create_spec_for_cookbook("repo-cookbook-one", "1.0.0")
775
- expect(repo_cb_location.source_options).to eq(expected_repo_options)
776
-
777
- expected_server_options = { artifactserver: "https://chef.example/url", version: "1.1.1" }
778
- community_source = policyfile.default_source.first
779
- expect(community_source).to be_a(ChefDK::Policyfile::CommunityCookbookSource)
780
- expect(community_source).to receive(:source_options_for).
781
- with("remote-cb-two", "1.1.1").
782
- and_return(expected_server_options)
783
-
784
- remote_cb_location = policyfile.create_spec_for_cookbook("remote-cb-two", "1.1.1")
785
- expect(remote_cb_location.source_options).to eq(expected_server_options)
786
- end
787
-
788
- end
789
-
790
- context "when the graphs conflict" do
791
-
792
- let(:repo_cookbook_universe) do
793
- {
794
- "repo-cookbook-one" => {
795
- "1.0.0" => [ ]
796
- },
797
-
798
- "repo-cookbook-two" => {
799
- "9.9.9" => [ ["repo-cookbook-on-community-dep", "= 1.0.0"] ]
800
- },
801
-
802
- "private-cookbook" => {
803
- "0.1.0" => [ ]
804
- },
805
-
806
- # NOTE: cookbooks are considered to conflict when both sources have
807
- # cookbooks with the same name, regardless of whether any version
808
- # numbers overlap.
809
- #
810
- # The before block does the equivalent to putting this in the
811
- # Policyfile.rb:
812
- #
813
- # cookbook "remote-cb"
814
- #
815
- # This makes the compiler take a slightly different code path than if
816
- # the cookbook was just in the dep graphs.
817
- "remote-cb" => {
818
- "99.99.99" => [ ]
819
- },
820
-
821
- # This also conflicts, but only via the graphs
822
- "remote-cb-two" => {
823
- "1.2.3" => [ ]
824
- }
825
-
826
- }
827
- end
828
-
829
- context "and no explicit source is given for the conflicting cookbook" do
830
-
831
- before do
832
- # This is on the community site
833
- policyfile.dsl.cookbook("remote-cb")
834
- end
835
-
836
- it "raises an error describing the conflict" do
837
- expected_err = <<-ERROR
838
- Source supermarket(https://supermarket.chef.io) and chef_repo(path/to/repo) contain conflicting cookbooks:
839
- - remote-cb
840
- - remote-cb-two
841
- ERROR
842
-
843
- expect { policyfile.remote_artifacts_graph }.to raise_error do |error|
844
- expect(error).to be_a(ChefDK::CookbookSourceConflict)
845
- expect(error.message).to eq(expected_err)
846
- end
847
- end
848
- end
849
-
850
- context "and the conflicting cookbook has an explicit source in the Policyfile" do
851
-
852
- before do
853
- # This is on the community site
854
- policyfile.dsl.cookbook("remote-cb", path: "path/to/remote-cb")
855
- policyfile.dsl.cookbook("remote-cb-two", git: "git://git.example:user/remote-cb-two.git")
856
- policyfile.error!
857
- end
858
-
859
- it "solves the graph" do
860
- expect { policyfile.remote_artifacts_graph }.to_not raise_error
861
- end
862
-
863
- it "assigns the correct source options to the cookbook" do
864
- remote_cb_source_opts = policyfile.cookbook_location_spec_for("remote-cb").source_options
865
- expect(remote_cb_source_opts).to eq(path: "path/to/remote-cb")
866
-
867
- remote_cb_two_source_opts = policyfile.cookbook_location_spec_for("remote-cb-two").source_options
868
- expect(remote_cb_two_source_opts).to eq(git: "git://git.example:user/remote-cb-two.git")
869
- end
870
- end
871
-
872
- end
873
-
874
- end
875
-
876
- end
1
+ #
2
+ # Copyright:: Copyright (c) 2014 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'spec_helper'
19
+ require 'chef-dk/policyfile_compiler'
20
+
21
+ describe ChefDK::PolicyfileCompiler, "when expressing the Policyfile graph demands" do
22
+
23
+ let(:run_list) { [] }
24
+
25
+ let(:default_source) { nil }
26
+
27
+ let(:external_cookbook_universe) { {} }
28
+
29
+ let(:policyfile) do
30
+ policyfile = ChefDK::PolicyfileCompiler.new.build do |p|
31
+
32
+ p.default_source(*default_source) if default_source
33
+ p.run_list(*run_list)
34
+
35
+ allow(p.default_source.first).to receive(:universe_graph).and_return(external_cookbook_universe)
36
+ end
37
+
38
+ policyfile
39
+ end
40
+
41
+ let(:demands) { policyfile.graph_demands }
42
+
43
+ shared_context("community default source") do
44
+
45
+ let(:default_source) { [:community] }
46
+
47
+ let(:external_cookbook_universe) do
48
+ {
49
+ "nginx" => {
50
+ "1.0.0" => [ [ "apt", "~> 2.0" ], [ "yum", "~> 1.0" ] ],
51
+ "1.2.0" => [ [ "apt", "~> 2.1" ], [ "yum", "~> 1.0" ] ],
52
+ "2.0.0" => [ [ "apt", "~> 3.0" ], [ "yum", "~> 1.0" ], [ "ohai", "~> 2.0" ] ]
53
+ },
54
+
55
+ "mysql" => {
56
+ "3.0.0" => [ [ "apt", "~> 2.0" ], [ "yum", "~> 1.0" ] ],
57
+ "4.0.0" => [ [ "apt", "~> 2.4" ], [ "yum", "~> 1.1" ] ],
58
+ "5.0.0" => [ ],
59
+ },
60
+
61
+ "local-cookbook" => {
62
+ "9.9.9" => [ ["local-cookbook-on-community-dep", "= 1.0.0"] ]
63
+ },
64
+
65
+ "git-sourced-cookbook" => {
66
+ "10.10.10" => [ ["git-sourced-cookbook-dep", "= 1.0.0"] ]
67
+ },
68
+
69
+ "remote-cb" => {
70
+ "0.1.0" => [ ],
71
+ "1.1.1" => [ ]
72
+ },
73
+
74
+ "remote-cb-two" => {
75
+ "0.1.0" => [ ],
76
+ "1.1.1" => [ ]
77
+ },
78
+
79
+ "local-cookbook-dep-one" => {
80
+ "1.5.0" => [ ]
81
+ },
82
+
83
+ "git-sourced-cookbook-dep" => {
84
+ "2.8.0" => [ ]
85
+ }
86
+
87
+ }
88
+ end
89
+ end
90
+
91
+ shared_context("chef server default source") do
92
+
93
+ let(:default_source) { [:chef_server, "https://chef.example.com"] }
94
+
95
+ let(:external_cookbook_universe) do
96
+ {
97
+ "nginx" => {
98
+ "1.0.0" => [ [ "apt", "~> 2.0" ], [ "yum", "~> 1.0" ] ],
99
+ },
100
+
101
+ "mysql" => {
102
+ "5.0.0" => [ ],
103
+ },
104
+
105
+ "local-cookbook" => {
106
+ "9.9.9" => [ ["local-cookbook-on-community-dep", "= 1.0.0"] ]
107
+ },
108
+
109
+ "remote-cb" => {
110
+ "1.1.1" => [ ]
111
+ },
112
+
113
+ "git-sourced-cookbook" => {
114
+ "10.10.10" => [ ["git-sourced-cookbook-dep", "= 1.0.0"] ]
115
+ },
116
+
117
+ "private-cookbook" => {
118
+ "0.1.0" => [ ]
119
+ },
120
+
121
+ "local-cookbook-dep-one" => {
122
+ "1.6.0" => [ ]
123
+ },
124
+
125
+ "git-sourced-cookbook-dep" => {
126
+ "2.9.0" => [ ]
127
+ }
128
+
129
+
130
+ }
131
+ end
132
+ end
133
+
134
+ describe "when normalizing run_list items" do
135
+
136
+ it "normalizes a bare cookbook name" do
137
+ policyfile.run_list("local-cookbook")
138
+ expect(policyfile.normalized_run_list).to eq(["recipe[local-cookbook::default]"])
139
+ end
140
+
141
+ it "normalizes a bare cookbook::recipe item" do
142
+ policyfile.run_list("local-cookbook::server")
143
+ expect(policyfile.normalized_run_list).to eq(["recipe[local-cookbook::server]"])
144
+ end
145
+
146
+ it "normalizes a recipe[] item with implicit default" do
147
+ policyfile.run_list("recipe[local-cookbook]")
148
+ expect(policyfile.normalized_run_list).to eq(["recipe[local-cookbook::default]"])
149
+ end
150
+
151
+ it "does not modify a fully qualified recipe" do
152
+ policyfile.run_list("recipe[local-cookbook::jazz_hands]")
153
+ expect(policyfile.normalized_run_list).to eq(["recipe[local-cookbook::jazz_hands]"])
154
+ end
155
+
156
+ describe "in an alternate run list" do
157
+
158
+ it "normalizes a bare cookbook name" do
159
+ policyfile.named_run_list(:foo, "local-cookbook")
160
+ expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::default]"])
161
+ end
162
+
163
+ it "normalizes a bare cookbook::recipe item" do
164
+ policyfile.named_run_list(:foo, "local-cookbook::server")
165
+ expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::server]"])
166
+ end
167
+
168
+ it "normalizes a recipe[] item with implicit default" do
169
+ policyfile.named_run_list(:foo, "recipe[local-cookbook]")
170
+ expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::default]"])
171
+ end
172
+
173
+ it "does not modify a fully qualified recipe" do
174
+ policyfile.named_run_list(:foo, "recipe[local-cookbook::jazz_hands]")
175
+ expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::jazz_hands]"])
176
+ end
177
+
178
+ end
179
+ end
180
+
181
+ before do
182
+ expect(policyfile.errors).to eq([])
183
+ end
184
+
185
+ context "Given no local or git cookbooks, no default source, and an empty run list" do
186
+
187
+ let(:run_list) { [] }
188
+
189
+ it "has an empty set of demands" do
190
+ expect(demands).to eq([])
191
+ end
192
+
193
+ it "uses an empty universe for dependencies" do
194
+ expect(policyfile.artifacts_graph).to eq({})
195
+ end
196
+
197
+ it "has an empty solution" do
198
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
199
+ expect(policyfile.graph_solution).to eq({})
200
+ end
201
+
202
+ it "has an empty set of solution_dependencies" do
203
+ expected_solution_deps = {
204
+ "Policyfile" => [],
205
+ "dependencies" => {}
206
+ }
207
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
208
+ end
209
+ end
210
+
211
+ context "Given a run list and no local or git cookbooks" do
212
+
213
+ let(:run_list) { ["remote-cb"] }
214
+
215
+ context "with no default source" do
216
+
217
+ it "fails to locate the cookbook" do
218
+ expect { policyfile.graph_solution }.to raise_error(Solve::Errors::NoSolutionError)
219
+ end
220
+
221
+ context "when the policyfile also has a `cookbook` entry for the run list item" do
222
+
223
+ before do
224
+ policyfile.dsl.cookbook "remote-cb"
225
+ end
226
+
227
+ it "fails to locate the cookbook" do
228
+ expect { policyfile.graph_solution }.to raise_error(Solve::Errors::NoSolutionError)
229
+ end
230
+
231
+ end
232
+
233
+ end
234
+
235
+ context "And the default source is the community site" do
236
+
237
+ include_context "community default source"
238
+
239
+ it "has an unconstrained demand on the required cookbooks" do
240
+ expect(demands).to eq([["remote-cb", ">= 0.0.0"]])
241
+ end
242
+
243
+ it "uses the community site universe for dependencies" do
244
+ expect(policyfile.artifacts_graph).to eq(external_cookbook_universe)
245
+ end
246
+
247
+ it "uses the community cookbook in the solution" do
248
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
249
+ expect(policyfile.graph_solution).to eq({"remote-cb" => "1.1.1"})
250
+ end
251
+
252
+ it "includes the cookbook in the solution dependencies" do
253
+ expected_solution_deps = {
254
+ "Policyfile" => [],
255
+ "dependencies" => { "remote-cb (1.1.1)" => [] }
256
+ }
257
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
258
+ end
259
+
260
+ end
261
+
262
+ context "And the default source is the chef-server" do
263
+
264
+ include_context "chef server default source"
265
+
266
+ it "has an unconstrained demand on the required cookbooks" do
267
+ expect(demands).to eq([["remote-cb", ">= 0.0.0"]])
268
+ end
269
+
270
+ it "uses the chef-server universe for dependencies" do
271
+ expect(policyfile.artifacts_graph).to eq(external_cookbook_universe)
272
+ end
273
+
274
+ it "uses the chef-server cookbook in the solution" do
275
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
276
+ expect(policyfile.graph_solution).to eq({"remote-cb" => "1.1.1"})
277
+ end
278
+ end
279
+ end
280
+
281
+ context "Given a local cookbook and only that cookbook in the run list" do
282
+
283
+ let(:run_list) { ['local-cookbook'] }
284
+
285
+ before do
286
+ policyfile.dsl.cookbook('local-cookbook', path: "/foo")
287
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
288
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([])
289
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached).and_return(true)
290
+ end
291
+
292
+ it "demands a solution using the local cookbook" do
293
+ expect(demands).to eq([["local-cookbook", "= 2.3.4"]])
294
+ end
295
+
296
+ it "includes the local cookbook in the artifact universe" do
297
+ expected_artifacts_graph = {
298
+ "local-cookbook" => { "2.3.4" => [] }
299
+ }
300
+ expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
301
+ end
302
+
303
+ it "includes the cookbook in the solution dependencies" do
304
+ expected_solution_deps = {
305
+ "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
306
+ "dependencies" => { "local-cookbook (2.3.4)" => [] }
307
+ }
308
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
309
+ end
310
+
311
+ end
312
+
313
+ context "Given a local cookbook with a dependency and only the local cookbook in the run list" do
314
+
315
+ let(:run_list) { ['local-cookbook'] }
316
+
317
+ context "And the default source is the community site" do
318
+
319
+ include_context "community default source"
320
+
321
+ before do
322
+ policyfile.dsl.cookbook("local-cookbook", path: "foo/")
323
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached)
324
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
325
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([ [ "local-cookbook-dep-one", "~> 1.0"] ])
326
+ end
327
+
328
+ it "demands a solution using the local cookbook" do
329
+ expect(demands).to eq([["local-cookbook", "= 2.3.4"]])
330
+ end
331
+
332
+ it "overrides the community site universe with the local cookbook and its dependencies" do
333
+ expected_artifacts_graph = external_cookbook_universe.dup
334
+ expected_artifacts_graph["local-cookbook"] = {
335
+ "2.3.4" => [ [ "local-cookbook-dep-one", "~> 1.0" ] ]
336
+ }
337
+ expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
338
+ end
339
+
340
+ it "uses the local cookbook in the solution and gets dependencies remotely" do
341
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
342
+ expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "local-cookbook-dep-one" => "1.5.0"})
343
+ end
344
+
345
+ it "includes the cookbook and dependencies in the solution dependencies" do
346
+ expected_solution_deps = {
347
+ "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
348
+ "dependencies" => {
349
+ "local-cookbook (2.3.4)" => [[ "local-cookbook-dep-one", "~> 1.0"]],
350
+ "local-cookbook-dep-one (1.5.0)" => []
351
+ }
352
+
353
+ }
354
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
355
+ end
356
+
357
+ end
358
+ context "And the default source is the chef server" do
359
+
360
+ include_context "chef server default source"
361
+
362
+ before do
363
+ policyfile.dsl.cookbook("local-cookbook", path: "foo/")
364
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached)
365
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
366
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([ [ "local-cookbook-dep-one", "~> 1.0"] ])
367
+ end
368
+
369
+ it "demands a solution using the local cookbook" do
370
+ expect(demands).to eq([["local-cookbook", "= 2.3.4"]])
371
+ end
372
+
373
+ it "overrides the chef server universe with the local cookbook and its dependencies" do
374
+ # all versions of "local-cookbook" from the cookbook site universe
375
+ # should be removed so we won't run into trouble if there's a community
376
+ # cookbook with the same name and version but different deps.
377
+ expected_artifacts_graph = external_cookbook_universe.dup
378
+ expected_artifacts_graph["local-cookbook"] = {
379
+ "2.3.4" => [ [ "local-cookbook-dep-one", "~> 1.0" ] ]
380
+ }
381
+ expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
382
+ end
383
+
384
+ it "uses the local cookbook in the solution and gets dependencies remotely" do
385
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
386
+ expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "local-cookbook-dep-one" => "1.6.0"})
387
+ end
388
+
389
+ it "includes the cookbook and dependencies in the solution dependencies" do
390
+ expected_solution_deps = {
391
+ "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
392
+ "dependencies" => {
393
+ "local-cookbook (2.3.4)" => [[ "local-cookbook-dep-one", "~> 1.0"]],
394
+ "local-cookbook-dep-one (1.6.0)" => []
395
+ }
396
+
397
+ }
398
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
399
+ end
400
+
401
+ end
402
+ end
403
+
404
+ context "Given a git-sourced cookbook with no dependencies and only the git cookbook in the run list" do
405
+
406
+ let(:run_list) { ["git-sourced-cookbook"] }
407
+
408
+ before do
409
+ policyfile.dsl.cookbook("git-sourced-cookbook", git: "git://git.example.org:user/a-cookbook.git")
410
+ allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:ensure_cached)
411
+ allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:version).and_return("8.6.7")
412
+ allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:dependencies).and_return([ ])
413
+ end
414
+
415
+ it "demands a solution using the git sourced cookbook" do
416
+ expect(demands).to eq([["git-sourced-cookbook", "= 8.6.7"]])
417
+ end
418
+
419
+ it "includes the git-sourced cookbook in the universe graph" do
420
+ expected_artifacts_graph = {
421
+ "git-sourced-cookbook" => { "8.6.7" => [ ] }
422
+ }
423
+ expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
424
+ end
425
+
426
+ it "uses the git sourced cookbook in the solution" do
427
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
428
+ expect(policyfile.graph_solution).to eq({"git-sourced-cookbook" => "8.6.7"})
429
+ end
430
+
431
+ it "includes the cookbook and dependencies in the solution dependencies" do
432
+ expected_solution_deps = {
433
+ "Policyfile" => [ [ "git-sourced-cookbook", ">= 0.0.0" ] ],
434
+ "dependencies" => {
435
+ "git-sourced-cookbook (8.6.7)" => []
436
+ }
437
+
438
+ }
439
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
440
+ end
441
+
442
+ end
443
+
444
+ context "Given a git-sourced cookbook with a dependency and only the git cookbook in the run list" do
445
+
446
+ let(:run_list) { ["git-sourced-cookbook"] }
447
+
448
+ before do
449
+ policyfile.dsl.cookbook("git-sourced-cookbook", git: "git://git.example.org:user/a-cookbook.git")
450
+ allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:ensure_cached)
451
+ allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:version).and_return("8.6.7")
452
+ allow(policyfile.cookbook_location_spec_for("git-sourced-cookbook")).to receive(:dependencies).and_return([ ["git-sourced-cookbook-dep", "~> 2.2" ] ])
453
+ end
454
+
455
+ context "And the default source is the community site" do
456
+
457
+ include_context "community default source"
458
+
459
+ it "demands a solution using the git sourced cookbook" do
460
+ expect(demands).to eq([["git-sourced-cookbook", "= 8.6.7"]])
461
+ end
462
+
463
+ it "overrides the community site universe with the git-sourced cookbook and deps" do
464
+ expected_artifacts_graph = external_cookbook_universe.dup
465
+ expected_artifacts_graph["git-sourced-cookbook"] = {
466
+ "8.6.7" => [ ["git-sourced-cookbook-dep", "~> 2.2" ] ]
467
+ }
468
+ expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
469
+ end
470
+
471
+ it "uses the git sourced cookbook with remote dependencies in the solution" do
472
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
473
+ expect(policyfile.graph_solution).to eq({"git-sourced-cookbook" => "8.6.7", "git-sourced-cookbook-dep" => "2.8.0"})
474
+ end
475
+
476
+ it "includes the cookbook and dependencies in the solution dependencies" do
477
+ expected_solution_deps = {
478
+ "Policyfile" => [ [ "git-sourced-cookbook", ">= 0.0.0" ] ],
479
+ "dependencies" => {
480
+ "git-sourced-cookbook (8.6.7)" => [ [ "git-sourced-cookbook-dep", "~> 2.2" ] ],
481
+ "git-sourced-cookbook-dep (2.8.0)" => []
482
+ }
483
+
484
+ }
485
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
486
+ end
487
+
488
+ end
489
+
490
+ context "And the default source is the chef server" do
491
+
492
+ include_context "chef server default source"
493
+
494
+ it "demands a solution using the git sourced cookbook" do
495
+ expect(demands).to eq([["git-sourced-cookbook", "= 8.6.7"]])
496
+ end
497
+
498
+ it "overrides the chef server universe with the git-sourced cookbook and deps" do
499
+ expected_artifacts_graph = external_cookbook_universe.dup
500
+ expected_artifacts_graph["git-sourced-cookbook"] = {
501
+ "8.6.7" => [ ["git-sourced-cookbook-dep", "~> 2.2" ] ]
502
+ }
503
+ expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
504
+ end
505
+
506
+ it "uses the git sourced cookbook with remote dependencies in the solution" do
507
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
508
+ expect(policyfile.graph_solution).to eq({"git-sourced-cookbook" => "8.6.7", "git-sourced-cookbook-dep" => "2.9.0"})
509
+ end
510
+
511
+ it "includes the cookbook and dependencies in the solution dependencies" do
512
+ expected_solution_deps = {
513
+ "Policyfile" => [ [ "git-sourced-cookbook", ">= 0.0.0" ] ],
514
+ "dependencies" => {
515
+ "git-sourced-cookbook (8.6.7)" => [ [ "git-sourced-cookbook-dep", "~> 2.2" ] ],
516
+ "git-sourced-cookbook-dep (2.9.0)" => []
517
+ }
518
+
519
+ }
520
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
521
+ end
522
+
523
+ end
524
+ end
525
+
526
+ context "Given a local cookbook with a run list containing the local cookbook and another cookbook" do
527
+
528
+ let(:run_list) { ['local-cookbook', 'remote-cb'] }
529
+
530
+ before do
531
+ policyfile.dsl.cookbook("local-cookbook", path: "foo/")
532
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached)
533
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
534
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([])
535
+ end
536
+
537
+ context "And the default source is the community site" do
538
+
539
+ include_context "community default source"
540
+
541
+ it "demands a solution with the local cookbook and any version of the other cookbook" do
542
+ expect(demands).to eq([["local-cookbook", "= 2.3.4"], ["remote-cb", ">= 0.0.0"]])
543
+ end
544
+
545
+ it "overrides the community universe with the local cookbook and deps" do
546
+ expected_artifacts_graph = external_cookbook_universe.dup
547
+ expected_artifacts_graph["local-cookbook"] = { "2.3.4" => [ ] }
548
+ expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
549
+ end
550
+
551
+ it "uses the locally specified cookbook and remote cookbooks in the solution" do
552
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
553
+ expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "remote-cb" => "1.1.1"})
554
+ end
555
+
556
+ it "includes the cookbook and dependencies in the solution dependencies" do
557
+ expected_solution_deps = {
558
+ "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
559
+ "dependencies" => {
560
+ "local-cookbook (2.3.4)" => [],
561
+ "remote-cb (1.1.1)" => []
562
+ }
563
+
564
+ }
565
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
566
+ end
567
+
568
+ end
569
+
570
+ context "And the default source is the chef server" do
571
+
572
+ include_context "chef server default source"
573
+
574
+ it "demands a solution with the local cookbook and any version of the other cookbook" do
575
+ expect(demands).to eq([["local-cookbook", "= 2.3.4"], ["remote-cb", ">= 0.0.0"]])
576
+ end
577
+
578
+ it "overrides the chef-server universe with the local cookbook and deps" do
579
+ expected_artifacts_graph = external_cookbook_universe.dup
580
+ expected_artifacts_graph["local-cookbook"] = { "2.3.4" => [ ] }
581
+ expect(policyfile.artifacts_graph).to eq(expected_artifacts_graph)
582
+ end
583
+
584
+ it "uses the locally specified cookbook and remote cookbooks in the solution" do
585
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
586
+ expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "remote-cb" => "1.1.1"})
587
+ end
588
+
589
+ it "includes the cookbook and dependencies in the solution dependencies" do
590
+ expected_solution_deps = {
591
+ "Policyfile" => [ [ "local-cookbook", ">= 0.0.0" ] ],
592
+ "dependencies" => {
593
+ "local-cookbook (2.3.4)" => [],
594
+ "remote-cb (1.1.1)" => []
595
+ }
596
+
597
+ }
598
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
599
+ end
600
+
601
+ end
602
+ end
603
+
604
+ context "given a cookbook with a version constraint in the policyfile" do
605
+
606
+ include_context "community default source"
607
+
608
+ let(:run_list) { ['remote-cb'] }
609
+
610
+ before do
611
+ policyfile.dsl.cookbook("remote-cb", "~> 0.1")
612
+ end
613
+
614
+ it "demands a solution that matches the version constraint in the policyfile" do
615
+ expect(demands).to eq([["remote-cb", "~> 0.1"]])
616
+ end
617
+
618
+ it "emits a solution that satisfies the policyfile constraint" do
619
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
620
+ expect(policyfile.graph_solution).to eq({"remote-cb" => "0.1.0"})
621
+ end
622
+
623
+ it "includes the policyfile constraint in the solution dependencies" do
624
+ expected_solution_deps = {
625
+ "Policyfile" => [ [ "remote-cb", "~> 0.1" ] ],
626
+ "dependencies" => {
627
+ "remote-cb (0.1.0)" => []
628
+ }
629
+
630
+ }
631
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
632
+ end
633
+ end
634
+
635
+ context "given a cookbook that isn't in the run list is specified with a version constraint in the policyfile" do
636
+
637
+ include_context "community default source"
638
+
639
+ let(:run_list) { ['local-cookbook'] }
640
+
641
+ before do
642
+ policyfile.dsl.cookbook("remote-cb", "~> 0.1")
643
+
644
+ policyfile.dsl.cookbook("local-cookbook", path: "foo/")
645
+
646
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:ensure_cached)
647
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:version).and_return("2.3.4")
648
+ allow(policyfile.cookbook_location_spec_for("local-cookbook")).to receive(:dependencies).and_return([])
649
+ end
650
+
651
+ it "demands a solution that matches the version constraint in the policyfile" do
652
+ expect(demands).to eq([["local-cookbook", "= 2.3.4"], ["remote-cb", "~> 0.1"]])
653
+ end
654
+
655
+ it "emits a solution that satisfies the policyfile constraint" do
656
+ expect(policyfile).to receive(:ensure_cache_dir_exists)
657
+ expect(policyfile.graph_solution).to eq({"local-cookbook" => "2.3.4", "remote-cb" => "0.1.0"})
658
+ end
659
+
660
+ it "includes the policyfile constraint in the solution dependencies" do
661
+ expected_solution_deps = {
662
+ "Policyfile" => [ [ "remote-cb", "~> 0.1" ], [ "local-cookbook", ">= 0.0.0"] ],
663
+ "dependencies" => {
664
+ "local-cookbook (2.3.4)" => [],
665
+ "remote-cb (0.1.0)" => []
666
+ }
667
+
668
+ }
669
+ expect(policyfile.solution_dependencies.to_lock).to eq(expected_solution_deps)
670
+ end
671
+ end
672
+
673
+ context "Given a run_list and named run_lists" do
674
+
675
+ before do
676
+ policyfile.dsl.named_run_list(:foo, 'local-cookbook', 'nginx')
677
+ policyfile.dsl.named_run_list(:bar, 'remote-cb', 'nginx')
678
+ policyfile.dsl.run_list('private-cookbook', 'nginx')
679
+ end
680
+
681
+ it "demands a solution that satisfies all of the run lists, with no duplicates" do
682
+ expect(policyfile.graph_demands).to include(["private-cookbook", ">= 0.0.0"])
683
+ expect(policyfile.graph_demands).to include(["nginx", ">= 0.0.0"])
684
+ expect(policyfile.graph_demands).to include(["remote-cb", ">= 0.0.0"])
685
+ expect(policyfile.graph_demands).to include(["local-cookbook", ">= 0.0.0"])
686
+
687
+ # ensure there are no duplicates:
688
+ expected_demands = [["private-cookbook", ">= 0.0.0"],
689
+ ["nginx", ">= 0.0.0"],
690
+ ["local-cookbook", ">= 0.0.0"],
691
+ ["remote-cb", ">= 0.0.0"]]
692
+ expect(policyfile.graph_demands).to eq(expected_demands)
693
+ end
694
+
695
+ end
696
+
697
+ context "when using multiple default sources" do
698
+
699
+ include_context "community default source"
700
+
701
+ let(:run_list) { [ 'repo-cookbook-one', 'remote-cb', 'remote-cb-two' ] }
702
+
703
+ before do
704
+ policyfile.default_source(:chef_repo, "path/to/repo")
705
+ allow(policyfile.default_source.last).to receive(:universe_graph).and_return(repo_cookbook_universe)
706
+ end
707
+
708
+ context "when the graphs don't conflict" do
709
+
710
+ before do
711
+ # This is on the community site
712
+ policyfile.dsl.cookbook("remote-cb")
713
+ end
714
+
715
+ let(:repo_cookbook_universe) do
716
+ {
717
+ "repo-cookbook-one" => {
718
+ "1.0.0" => [ ]
719
+ },
720
+
721
+ "repo-cookbook-two" => {
722
+ "9.9.9" => [ ["repo-cookbook-on-community-dep", "= 1.0.0"] ]
723
+ },
724
+
725
+ "private-cookbook" => {
726
+ "0.1.0" => [ ]
727
+ }
728
+ }
729
+ end
730
+
731
+ it "merges the graphs" do
732
+ merged = policyfile.remote_artifacts_graph
733
+ expected = external_cookbook_universe.merge(repo_cookbook_universe)
734
+
735
+ expect(merged).to eq(expected)
736
+ end
737
+
738
+ it "solves the graph demands using cookbooks from both sources" do
739
+ expected = {"repo-cookbook-one" => "1.0.0", "remote-cb" => "1.1.1", "remote-cb-two" => "1.1.1"}
740
+ expect(policyfile.graph_solution).to eq(expected)
741
+ end
742
+
743
+ it "finds the location of a cookbook declared via explicit `cookbook` with no source options" do
744
+ community_source = policyfile.default_source.first
745
+
746
+ expected_source_options = { artifactserver: "https://chef.example/url", version: "1.1.1" }
747
+
748
+ expect(community_source).to be_a(ChefDK::Policyfile::CommunityCookbookSource)
749
+ expect(community_source).to receive(:source_options_for).
750
+ with("remote-cb", "1.1.1").
751
+ and_return(expected_source_options)
752
+
753
+ location_spec = policyfile.create_spec_for_cookbook("remote-cb", "1.1.1")
754
+ expect(location_spec.source_options).to eq(expected_source_options)
755
+ end
756
+
757
+ it "sources cookbooks from the correct source when the cookbook doesn't have a `cookbook` entry" do
758
+ # these don't have `cookbook` entries in the Policyfile.rb, so they are nil
759
+ expect(policyfile.cookbook_location_spec_for("repo-cookbook-one")).to be_nil
760
+ expect(policyfile.cookbook_location_spec_for("remote-cb-two")).to be_nil
761
+
762
+ # We have to stub #source_options_for or else we'd need to stub the
763
+ # source options data inside the source object. That's getting a bit
764
+ # too deep into the source object's internals.
765
+
766
+ expected_repo_options = { path: "path/to/cookbook", version: "1.0.0" }
767
+ repo_source = policyfile.default_source.last
768
+ expect(repo_source).to be_a(ChefDK::Policyfile::ChefRepoCookbookSource)
769
+ expect(repo_source).to receive(:source_options_for).
770
+ with("repo-cookbook-one", "1.0.0").
771
+ and_return(expected_repo_options)
772
+
773
+
774
+ repo_cb_location = policyfile.create_spec_for_cookbook("repo-cookbook-one", "1.0.0")
775
+ expect(repo_cb_location.source_options).to eq(expected_repo_options)
776
+
777
+ expected_server_options = { artifactserver: "https://chef.example/url", version: "1.1.1" }
778
+ community_source = policyfile.default_source.first
779
+ expect(community_source).to be_a(ChefDK::Policyfile::CommunityCookbookSource)
780
+ expect(community_source).to receive(:source_options_for).
781
+ with("remote-cb-two", "1.1.1").
782
+ and_return(expected_server_options)
783
+
784
+ remote_cb_location = policyfile.create_spec_for_cookbook("remote-cb-two", "1.1.1")
785
+ expect(remote_cb_location.source_options).to eq(expected_server_options)
786
+ end
787
+
788
+ end
789
+
790
+ context "when the graphs conflict" do
791
+
792
+ let(:repo_cookbook_universe) do
793
+ {
794
+ "repo-cookbook-one" => {
795
+ "1.0.0" => [ ]
796
+ },
797
+
798
+ "repo-cookbook-two" => {
799
+ "9.9.9" => [ ["repo-cookbook-on-community-dep", "= 1.0.0"] ]
800
+ },
801
+
802
+ "private-cookbook" => {
803
+ "0.1.0" => [ ]
804
+ },
805
+
806
+ # NOTE: cookbooks are considered to conflict when both sources have
807
+ # cookbooks with the same name, regardless of whether any version
808
+ # numbers overlap.
809
+ #
810
+ # The before block does the equivalent to putting this in the
811
+ # Policyfile.rb:
812
+ #
813
+ # cookbook "remote-cb"
814
+ #
815
+ # This makes the compiler take a slightly different code path than if
816
+ # the cookbook was just in the dep graphs.
817
+ "remote-cb" => {
818
+ "99.99.99" => [ ]
819
+ },
820
+
821
+ # This also conflicts, but only via the graphs
822
+ "remote-cb-two" => {
823
+ "1.2.3" => [ ]
824
+ },
825
+
826
+ # This has a dependency on a conflicting cookbook
827
+ "dep_on_conflicting_cookbook" => {
828
+
829
+ # Only the older cookbook has the conflicting dep, however we don't
830
+ # know how the dependency solver will solve this without doing more
831
+ # inspection of the graph, so the expected behavior is to error if
832
+ # any possible solution could have a conflict.
833
+ "1.0.0" => [ ["remote-cb-two", ">= 0.0.0" ] ],
834
+ "2.0.0" => [ ]
835
+
836
+ }
837
+
838
+ }
839
+ end
840
+
841
+ context "and the conflicting cookbook is in the run list" do
842
+
843
+ let(:run_list) { [ 'repo-cookbook-one', 'remote-cb', 'remote-cb-two' ] }
844
+
845
+ context "and no explicit source is given for the conflicting cookbook" do
846
+
847
+ before do
848
+ # This is on the community site
849
+ policyfile.dsl.cookbook("remote-cb")
850
+ end
851
+
852
+ it "raises an error describing the conflict" do
853
+ repo_path = File.expand_path("path/to/repo")
854
+
855
+ expected_err = <<-ERROR
856
+ Source supermarket(https://supermarket.chef.io) and chef_repo(#{repo_path}) contain conflicting cookbooks:
857
+ - remote-cb
858
+ - remote-cb-two
859
+
860
+ You can set a preferred source to resolve this issue with code like:
861
+
862
+ default_source :supermarket, "https://supermarket.chef.io" do |s|
863
+ s.preferred_for "remote-cb", "remote-cb-two"
864
+ end
865
+ ERROR
866
+
867
+ expect { policyfile.remote_artifacts_graph }.to raise_error do |error|
868
+ expect(error).to be_a(ChefDK::CookbookSourceConflict)
869
+ expect(error.message).to eq(expected_err)
870
+ end
871
+ end
872
+ end
873
+
874
+ context "and the conflicting cookbook has an explicit source in the Policyfile" do
875
+
876
+ before do
877
+ # This is on the community site
878
+ policyfile.dsl.cookbook("remote-cb", path: "path/to/remote-cb")
879
+ policyfile.dsl.cookbook("remote-cb-two", git: "git://git.example:user/remote-cb-two.git")
880
+ policyfile.error!
881
+ end
882
+
883
+ it "solves the graph" do
884
+ expect { policyfile.remote_artifacts_graph }.to_not raise_error
885
+ end
886
+
887
+ it "assigns the correct source options to the cookbook" do
888
+ remote_cb_source_opts = policyfile.cookbook_location_spec_for("remote-cb").source_options
889
+ expect(remote_cb_source_opts).to eq(path: "path/to/remote-cb")
890
+
891
+ remote_cb_two_source_opts = policyfile.cookbook_location_spec_for("remote-cb-two").source_options
892
+ expect(remote_cb_two_source_opts).to eq(git: "git://git.example:user/remote-cb-two.git")
893
+ end
894
+ end
895
+
896
+ context "and the conflicting cookbook has a preferred source" do
897
+
898
+ let(:community_source) { policyfile.dsl.default_source.first }
899
+
900
+ let(:repo_source) { policyfile.dsl.default_source.last }
901
+
902
+ let(:full_universe_graph) do
903
+ {
904
+ "remote-cb" => {
905
+ "1.1.1" => {
906
+ "download_url" => "https://supermarket.chef.io/api/v1/cookbooks/remote-cb/versions/1.1.1/download"
907
+ }
908
+ }
909
+ }
910
+ end
911
+
912
+ let(:cookbook_version_paths) do
913
+ {
914
+ "remote-cb-two" => {
915
+ "1.1.1" => "path/to/repo/remote-cb-two"
916
+ }
917
+ }
918
+ end
919
+
920
+ before do
921
+ community_source.preferred_for 'remote-cb'
922
+ allow(community_source).to receive(:full_community_graph).and_return(full_universe_graph)
923
+ allow(repo_source).to receive(:cookbook_version_paths).and_return(cookbook_version_paths)
924
+ repo_source.preferred_for 'remote-cb-two'
925
+ end
926
+
927
+ it "solves the graph" do
928
+ expect { policyfile.remote_artifacts_graph }.to_not raise_error
929
+ end
930
+
931
+ it "assigns the correct source options to the cookbook" do
932
+ expected_remote_cb_source_opts = {
933
+ artifactserver: "https://supermarket.chef.io/api/v1/cookbooks/remote-cb/versions/1.1.1/download",
934
+ version: "1.1.1"
935
+ }
936
+ actual_remote_cb_source_opts = policyfile.create_spec_for_cookbook("remote-cb", "1.1.1").source_options
937
+ expect(actual_remote_cb_source_opts).to eq(expected_remote_cb_source_opts)
938
+
939
+ expected_remote_cb_two_source_opts = {
940
+ path: "path/to/repo/remote-cb-two",
941
+ version: "1.1.1"
942
+ }
943
+ actual_remote_cb_two_source_opts = policyfile.create_spec_for_cookbook("remote-cb-two", "1.1.1").source_options
944
+ expect(actual_remote_cb_two_source_opts).to eq(expected_remote_cb_two_source_opts)
945
+ end
946
+
947
+ end
948
+
949
+ end
950
+
951
+ context "when top-level cookbooks don't conflict, but dependencies could" do
952
+
953
+ let(:run_list) { [ "dep_on_conflicting_cookbook" ] }
954
+
955
+ it "raises an error describing the conflict" do
956
+ repo_path = File.expand_path("path/to/repo")
957
+
958
+ expected_err = <<-ERROR
959
+ Source supermarket(https://supermarket.chef.io) and chef_repo(#{repo_path}) contain conflicting cookbooks:
960
+ - remote-cb-two
961
+
962
+ You can set a preferred source to resolve this issue with code like:
963
+
964
+ default_source :supermarket, "https://supermarket.chef.io" do |s|
965
+ s.preferred_for "remote-cb-two"
966
+ end
967
+ ERROR
968
+
969
+ expect { policyfile.remote_artifacts_graph }.to raise_error do |error|
970
+ expect(error).to be_a(ChefDK::CookbookSourceConflict)
971
+ expect(error.message).to eq(expected_err)
972
+ end
973
+ end
974
+ end
975
+
976
+ context "when the conflicting cookbook could not be in the solution set" do
977
+
978
+ let(:run_list) { [ 'local_cookbook' ] }
979
+
980
+ it "creates the merged graph without error" do
981
+ expect { policyfile.remote_artifacts_graph }.to_not raise_error
982
+ expect { policyfile.graph }.to_not raise_error
983
+ end
984
+
985
+ it "has an empty set of artifacts for the conflicting cookbook" do
986
+ expect(policyfile.remote_artifacts_graph["remote-cb"]).to eq({})
987
+ expect(policyfile.remote_artifacts_graph["remote-cb-two"]).to eq({})
988
+ end
989
+
990
+ end
991
+
992
+
993
+ end
994
+
995
+ end
996
+
997
+ end