chef-dk 0.11.2 → 0.12.0

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