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