chef-dk 3.9.0 → 3.10.1

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