puppet 6.12.0-x64-mingw32 → 6.17.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (412) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +2 -7
  3. data/CONTRIBUTING.md +7 -13
  4. data/Gemfile +4 -2
  5. data/Gemfile.lock +39 -36
  6. data/README.md +18 -25
  7. data/ext/project_data.yaml +1 -1
  8. data/ext/windows/service/daemon.rb +3 -3
  9. data/lib/puppet.rb +52 -13
  10. data/lib/puppet/agent.rb +20 -14
  11. data/lib/puppet/application/agent.rb +26 -17
  12. data/lib/puppet/application/describe.rb +7 -5
  13. data/lib/puppet/application/device.rb +2 -2
  14. data/lib/puppet/application/filebucket.rb +19 -15
  15. data/lib/puppet/application/plugin.rb +1 -0
  16. data/lib/puppet/application/resource.rb +1 -1
  17. data/lib/puppet/application/ssl.rb +4 -4
  18. data/lib/puppet/configurer.rb +65 -69
  19. data/lib/puppet/configurer/plugin_handler.rb +10 -1
  20. data/lib/puppet/confine.rb +1 -1
  21. data/lib/puppet/context/trusted_information.rb +14 -8
  22. data/lib/puppet/daemon.rb +13 -27
  23. data/lib/puppet/defaults.rb +154 -58
  24. data/lib/puppet/environments.rb +27 -20
  25. data/lib/puppet/face/facts.rb +8 -5
  26. data/lib/puppet/face/help.rb +29 -3
  27. data/lib/puppet/face/module/search.rb +5 -0
  28. data/lib/puppet/face/plugin.rb +2 -2
  29. data/lib/puppet/file_serving/http_metadata.rb +14 -2
  30. data/lib/puppet/file_serving/metadata.rb +4 -1
  31. data/lib/puppet/file_serving/terminus_selector.rb +7 -8
  32. data/lib/puppet/file_system/file_impl.rb +14 -10
  33. data/lib/puppet/file_system/memory_file.rb +6 -0
  34. data/lib/puppet/file_system/memory_impl.rb +13 -0
  35. data/lib/puppet/file_system/uniquefile.rb +12 -16
  36. data/lib/puppet/file_system/windows.rb +7 -10
  37. data/lib/puppet/forge.rb +1 -1
  38. data/lib/puppet/forge/cache.rb +1 -1
  39. data/lib/puppet/forge/repository.rb +4 -7
  40. data/lib/puppet/functions/call.rb +1 -1
  41. data/lib/puppet/functions/eyaml_lookup_key.rb +13 -8
  42. data/lib/puppet/functions/filter.rb +1 -0
  43. data/lib/puppet/functions/reduce.rb +2 -4
  44. data/lib/puppet/http.rb +5 -0
  45. data/lib/puppet/http/client.rb +293 -73
  46. data/lib/puppet/http/errors.rb +2 -0
  47. data/lib/puppet/http/external_client.rb +90 -0
  48. data/lib/puppet/http/redirector.rb +43 -7
  49. data/lib/puppet/http/resolver.rb +46 -3
  50. data/lib/puppet/http/resolver/server_list.rb +76 -16
  51. data/lib/puppet/http/resolver/settings.rb +23 -3
  52. data/lib/puppet/http/resolver/srv.rb +29 -3
  53. data/lib/puppet/http/response.rb +87 -1
  54. data/lib/puppet/http/retry_after_handler.rb +39 -0
  55. data/lib/puppet/http/service.rb +151 -7
  56. data/lib/puppet/http/service/ca.rb +76 -14
  57. data/lib/puppet/http/service/compiler.rb +319 -0
  58. data/lib/puppet/http/service/file_server.rb +206 -0
  59. data/lib/puppet/http/service/report.rb +49 -23
  60. data/lib/puppet/http/session.rb +103 -7
  61. data/lib/puppet/indirector.rb +1 -1
  62. data/lib/puppet/indirector/catalog/compiler.rb +10 -0
  63. data/lib/puppet/indirector/catalog/rest.rb +34 -0
  64. data/lib/puppet/indirector/facts/rest.rb +42 -0
  65. data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  66. data/lib/puppet/indirector/file_bucket_file/rest.rb +48 -0
  67. data/lib/puppet/indirector/file_content/http.rb +5 -0
  68. data/lib/puppet/indirector/file_content/rest.rb +30 -0
  69. data/lib/puppet/indirector/file_metadata/http.rb +27 -8
  70. data/lib/puppet/indirector/file_metadata/rest.rb +52 -0
  71. data/lib/puppet/indirector/json.rb +1 -1
  72. data/lib/puppet/indirector/msgpack.rb +1 -1
  73. data/lib/puppet/indirector/node/rest.rb +24 -0
  74. data/lib/puppet/indirector/report/rest.rb +19 -0
  75. data/lib/puppet/indirector/report/yaml.rb +23 -0
  76. data/lib/puppet/indirector/request.rb +1 -1
  77. data/lib/puppet/indirector/rest.rb +12 -0
  78. data/lib/puppet/indirector/status/rest.rb +18 -0
  79. data/lib/puppet/loaders.rb +6 -0
  80. data/lib/puppet/metatype/manager.rb +80 -80
  81. data/lib/puppet/network/http/api/indirected_routes.rb +1 -1
  82. data/lib/puppet/network/http/api/master/v3/environment.rb +3 -0
  83. data/lib/puppet/network/http/base_pool.rb +7 -2
  84. data/lib/puppet/network/http/compression.rb +7 -0
  85. data/lib/puppet/network/http/connection.rb +6 -0
  86. data/lib/puppet/network/http/connection_adapter.rb +184 -0
  87. data/lib/puppet/network/http/nocache_pool.rb +2 -0
  88. data/lib/puppet/network/http/pool.rb +13 -6
  89. data/lib/puppet/network/http_pool.rb +2 -1
  90. data/lib/puppet/node/environment.rb +11 -1
  91. data/lib/puppet/pal/catalog_compiler.rb +5 -0
  92. data/lib/puppet/pal/pal_impl.rb +4 -29
  93. data/lib/puppet/parser/ast/leaf.rb +5 -5
  94. data/lib/puppet/parser/ast/pops_bridge.rb +6 -15
  95. data/lib/puppet/parser/compiler.rb +43 -33
  96. data/lib/puppet/parser/compiler/catalog_validator/env_relationship_validator.rb +2 -0
  97. data/lib/puppet/parser/compiler/catalog_validator/site_validator.rb +2 -0
  98. data/lib/puppet/parser/environment_compiler.rb +4 -1
  99. data/lib/puppet/parser/functions.rb +18 -13
  100. data/lib/puppet/parser/functions/filter.rb +1 -0
  101. data/lib/puppet/parser/resource.rb +3 -2
  102. data/lib/puppet/parser/resource/param.rb +6 -0
  103. data/lib/puppet/pops/evaluator/access_operator.rb +2 -2
  104. data/lib/puppet/pops/evaluator/evaluator_impl.rb +6 -6
  105. data/lib/puppet/pops/issues.rb +5 -0
  106. data/lib/puppet/pops/loader/puppet_plan_instantiator.rb +12 -3
  107. data/lib/puppet/pops/loaders.rb +7 -5
  108. data/lib/puppet/pops/parser/evaluating_parser.rb +5 -7
  109. data/lib/puppet/pops/resource/resource_type_impl.rb +2 -0
  110. data/lib/puppet/pops/types/p_object_type_extension.rb +10 -0
  111. data/lib/puppet/pops/types/type_calculator.rb +24 -0
  112. data/lib/puppet/pops/validation/checker4_0.rb +11 -1
  113. data/lib/puppet/pops/validation/tasks_checker.rb +5 -1
  114. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  115. data/lib/puppet/provider/aix_object.rb +4 -2
  116. data/lib/puppet/provider/group/aix.rb +1 -0
  117. data/lib/puppet/provider/group/groupadd.rb +57 -24
  118. data/lib/puppet/provider/group/windows_adsi.rb +3 -3
  119. data/lib/puppet/provider/package/aix.rb +17 -2
  120. data/lib/puppet/provider/package/apt.rb +78 -4
  121. data/lib/puppet/provider/package/aptitude.rb +1 -1
  122. data/lib/puppet/provider/package/dnfmodule.rb +69 -15
  123. data/lib/puppet/provider/package/dpkg.rb +14 -7
  124. data/lib/puppet/provider/package/fink.rb +20 -3
  125. data/lib/puppet/provider/package/gem.rb +41 -7
  126. data/lib/puppet/provider/package/openbsd.rb +13 -1
  127. data/lib/puppet/provider/package/pacman.rb +2 -5
  128. data/lib/puppet/provider/package/pip.rb +143 -48
  129. data/lib/puppet/provider/package/pip3.rb +0 -2
  130. data/lib/puppet/provider/package/pkg.rb +18 -5
  131. data/lib/puppet/provider/package/pkgdmg.rb +1 -1
  132. data/lib/puppet/provider/package/pkgng.rb +16 -4
  133. data/lib/puppet/provider/package/portage.rb +2 -2
  134. data/lib/puppet/provider/package/puppet_gem.rb +6 -2
  135. data/lib/puppet/provider/package/rpm.rb +6 -213
  136. data/lib/puppet/provider/package/yum.rb +109 -25
  137. data/lib/puppet/provider/package/zypper.rb +59 -1
  138. data/lib/puppet/provider/service/systemd.rb +22 -4
  139. data/lib/puppet/provider/service/windows.rb +23 -7
  140. data/lib/puppet/provider/user/aix.rb +1 -0
  141. data/lib/puppet/provider/user/directoryservice.rb +30 -5
  142. data/lib/puppet/provider/user/useradd.rb +22 -12
  143. data/lib/puppet/reports/http.rb +15 -9
  144. data/lib/puppet/reports/store.rb +1 -1
  145. data/lib/puppet/resource.rb +2 -1
  146. data/lib/puppet/resource/type.rb +8 -0
  147. data/lib/puppet/resource/type_collection.rb +20 -16
  148. data/lib/puppet/runtime.rb +31 -1
  149. data/lib/puppet/settings.rb +4 -0
  150. data/lib/puppet/settings/http_extra_headers_setting.rb +25 -0
  151. data/lib/puppet/ssl.rb +1 -0
  152. data/lib/puppet/ssl/certificate.rb +2 -1
  153. data/lib/puppet/ssl/host.rb +4 -4
  154. data/lib/puppet/ssl/oids.rb +1 -0
  155. data/lib/puppet/ssl/ssl_context.rb +2 -2
  156. data/lib/puppet/ssl/ssl_provider.rb +20 -1
  157. data/lib/puppet/ssl/state_machine.rb +81 -35
  158. data/lib/puppet/ssl/verifier_adapter.rb +9 -1
  159. data/lib/puppet/test/test_helper.rb +15 -11
  160. data/lib/puppet/transaction/report.rb +2 -2
  161. data/lib/puppet/transaction/resource_harness.rb +1 -1
  162. data/lib/puppet/trusted_external.rb +29 -1
  163. data/lib/puppet/type.rb +18 -6
  164. data/lib/puppet/type/file.rb +51 -13
  165. data/lib/puppet/type/file/checksum.rb +4 -4
  166. data/lib/puppet/type/file/source.rb +51 -60
  167. data/lib/puppet/type/group.rb +2 -2
  168. data/lib/puppet/type/package.rb +102 -10
  169. data/lib/puppet/type/service.rb +55 -8
  170. data/lib/puppet/type/user.rb +3 -28
  171. data/lib/puppet/util.rb +39 -15
  172. data/lib/puppet/util/at_fork.rb +1 -1
  173. data/lib/puppet/util/autoload.rb +4 -18
  174. data/lib/puppet/util/checksums.rb +19 -4
  175. data/lib/puppet/util/fileparsing.rb +2 -2
  176. data/lib/puppet/util/instance_loader.rb +14 -10
  177. data/lib/puppet/util/log/destinations.rb +2 -11
  178. data/lib/puppet/util/package/version/debian.rb +175 -0
  179. data/lib/puppet/util/package/version/gem.rb +15 -0
  180. data/lib/puppet/util/package/version/pip.rb +167 -0
  181. data/lib/puppet/util/package/version/range.rb +53 -0
  182. data/lib/puppet/util/package/version/range/eq.rb +14 -0
  183. data/lib/puppet/util/package/version/range/gt.rb +14 -0
  184. data/lib/puppet/util/package/version/range/gt_eq.rb +14 -0
  185. data/lib/puppet/util/package/version/range/lt.rb +14 -0
  186. data/lib/puppet/util/package/version/range/lt_eq.rb +14 -0
  187. data/lib/puppet/util/package/version/range/min_max.rb +21 -0
  188. data/lib/puppet/util/package/version/range/simple.rb +11 -0
  189. data/lib/puppet/util/package/version/rpm.rb +73 -0
  190. data/lib/puppet/util/pidlock.rb +36 -10
  191. data/lib/puppet/util/platform.rb +5 -0
  192. data/lib/puppet/util/plist.rb +6 -0
  193. data/lib/puppet/util/provider_features.rb +1 -1
  194. data/lib/puppet/util/reference.rb +1 -1
  195. data/lib/puppet/util/rpm_compare.rb +193 -0
  196. data/lib/puppet/util/storage.rb +0 -1
  197. data/lib/puppet/util/windows/adsi.rb +2 -2
  198. data/lib/puppet/util/windows/api_types.rb +45 -32
  199. data/lib/puppet/util/windows/eventlog.rb +1 -6
  200. data/lib/puppet/util/windows/principal.rb +8 -6
  201. data/lib/puppet/util/windows/process.rb +15 -14
  202. data/lib/puppet/util/windows/registry.rb +11 -11
  203. data/lib/puppet/util/windows/security.rb +1 -0
  204. data/lib/puppet/util/windows/service.rb +43 -26
  205. data/lib/puppet/util/windows/sid.rb +3 -3
  206. data/lib/puppet/util/windows/user.rb +23 -8
  207. data/lib/puppet/util/yaml.rb +1 -1
  208. data/lib/puppet/version.rb +1 -1
  209. data/locales/puppet.pot +707 -574
  210. data/man/man5/puppet.conf.5 +74 -14
  211. data/man/man8/puppet-agent.8 +7 -7
  212. data/man/man8/puppet-apply.8 +1 -1
  213. data/man/man8/puppet-catalog.8 +1 -1
  214. data/man/man8/puppet-config.8 +1 -1
  215. data/man/man8/puppet-describe.8 +1 -1
  216. data/man/man8/puppet-device.8 +2 -2
  217. data/man/man8/puppet-doc.8 +1 -1
  218. data/man/man8/puppet-epp.8 +1 -1
  219. data/man/man8/puppet-facts.8 +1 -1
  220. data/man/man8/puppet-filebucket.8 +17 -2
  221. data/man/man8/puppet-generate.8 +1 -1
  222. data/man/man8/puppet-help.8 +6 -3
  223. data/man/man8/puppet-key.8 +1 -1
  224. data/man/man8/puppet-lookup.8 +1 -1
  225. data/man/man8/puppet-man.8 +1 -1
  226. data/man/man8/puppet-module.8 +4 -1
  227. data/man/man8/puppet-node.8 +1 -1
  228. data/man/man8/puppet-parser.8 +1 -1
  229. data/man/man8/puppet-plugin.8 +1 -1
  230. data/man/man8/puppet-report.8 +1 -1
  231. data/man/man8/puppet-resource.8 +1 -1
  232. data/man/man8/puppet-script.8 +1 -1
  233. data/man/man8/puppet-ssl.8 +2 -2
  234. data/man/man8/puppet-status.8 +1 -1
  235. data/man/man8/puppet.8 +2 -2
  236. data/spec/fixtures/ssl/unknown-127.0.0.1-key.pem +67 -0
  237. data/spec/fixtures/ssl/unknown-127.0.0.1.pem +48 -0
  238. data/spec/fixtures/ssl/unknown-ca-key.pem +67 -0
  239. data/spec/fixtures/ssl/unknown-ca.pem +59 -0
  240. data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-installed.txt → dnf-module-list.txt} +8 -0
  241. data/spec/fixtures/unit/provider/package/pkgng/pkg.version +2 -0
  242. data/spec/fixtures/unit/provider/package/yum/yum-check-update-subscription-manager.txt +9 -0
  243. data/spec/fixtures/unit/provider/package/zypper/zypper-search-uninstalled.out +13 -0
  244. data/spec/fixtures/unit/provider/service/systemd/list_unit_files_services +9 -0
  245. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_fetch_if_not_on_the_local_disk.yml +1 -102
  246. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_not_update_if_content_on_disk_is_up-to-date.yml +1 -106
  247. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_update_if_content_differs_on_disk.yml +1 -106
  248. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_mtime_is_older_on_disk.yml +1 -102
  249. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_no_header_specified.yml +1 -98
  250. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_not_on_the_local_disk.yml +1 -102
  251. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_not_update_if_mtime_is_newer_on_disk.yml +1 -102
  252. data/spec/integration/application/agent_spec.rb +483 -0
  253. data/spec/integration/application/apply_spec.rb +132 -3
  254. data/spec/integration/application/filebucket_spec.rb +190 -0
  255. data/spec/integration/application/plugin_spec.rb +73 -0
  256. data/spec/integration/configurer_spec.rb +26 -7
  257. data/spec/integration/defaults_spec.rb +1 -2
  258. data/spec/integration/http/client_spec.rb +47 -37
  259. data/spec/integration/indirector/facts/facter_spec.rb +4 -0
  260. data/spec/integration/indirector/report/yaml.rb +83 -0
  261. data/spec/integration/module_tool/forge_spec.rb +2 -15
  262. data/spec/integration/network/http_pool_spec.rb +93 -20
  263. data/spec/integration/node/environment_spec.rb +15 -0
  264. data/spec/integration/parser/compiler_spec.rb +11 -0
  265. data/spec/integration/type/file_spec.rb +1 -1
  266. data/spec/integration/util/windows/adsi_spec.rb +6 -1
  267. data/spec/integration/util/windows/registry_spec.rb +7 -7
  268. data/spec/integration/util/windows/user_spec.rb +40 -5
  269. data/spec/lib/puppet/test_ca.rb +2 -2
  270. data/spec/lib/puppet_spec/https.rb +16 -7
  271. data/spec/lib/puppet_spec/puppetserver.rb +119 -0
  272. data/spec/shared_contexts/https.rb +29 -0
  273. data/spec/unit/agent_spec.rb +80 -26
  274. data/spec/unit/application/agent_spec.rb +9 -5
  275. data/spec/unit/application/apply_spec.rb +2 -12
  276. data/spec/unit/application/describe_spec.rb +88 -50
  277. data/spec/unit/application/device_spec.rb +2 -2
  278. data/spec/unit/application/filebucket_spec.rb +22 -2
  279. data/spec/unit/application/resource_spec.rb +2 -2
  280. data/spec/unit/configurer/fact_handler_spec.rb +4 -8
  281. data/spec/unit/configurer/plugin_handler_spec.rb +36 -19
  282. data/spec/unit/configurer_spec.rb +17 -18
  283. data/spec/unit/context/trusted_information_spec.rb +25 -2
  284. data/spec/unit/daemon_spec.rb +5 -64
  285. data/spec/unit/defaults_spec.rb +25 -2
  286. data/spec/unit/environments_spec.rb +65 -28
  287. data/spec/unit/face/facts_spec.rb +24 -20
  288. data/spec/unit/face/module/search_spec.rb +17 -0
  289. data/spec/unit/face/plugin_spec.rb +12 -10
  290. data/spec/unit/file_serving/http_metadata_spec.rb +37 -14
  291. data/spec/unit/file_serving/terminus_selector_spec.rb +45 -26
  292. data/spec/unit/file_system/uniquefile_spec.rb +11 -0
  293. data/spec/unit/file_system_spec.rb +26 -2
  294. data/spec/unit/functions/lookup_spec.rb +13 -0
  295. data/spec/unit/http/client_spec.rb +327 -35
  296. data/spec/unit/http/external_client_spec.rb +201 -0
  297. data/spec/unit/http/resolver_spec.rb +34 -2
  298. data/spec/unit/http/response_spec.rb +75 -0
  299. data/spec/unit/http/service/ca_spec.rb +53 -11
  300. data/spec/unit/http/service/compiler_spec.rb +627 -0
  301. data/spec/unit/http/service/file_server_spec.rb +308 -0
  302. data/spec/unit/http/service/report_spec.rb +27 -9
  303. data/spec/unit/http/service_spec.rb +98 -5
  304. data/spec/unit/http/session_spec.rb +190 -7
  305. data/spec/unit/indirector/catalog/compiler_spec.rb +47 -29
  306. data/spec/unit/indirector/catalog/rest_spec.rb +59 -2
  307. data/spec/unit/indirector/facts/rest_spec.rb +79 -24
  308. data/spec/unit/indirector/file_bucket_file/rest_spec.rb +82 -2
  309. data/spec/unit/indirector/file_content/rest_spec.rb +53 -2
  310. data/spec/unit/indirector/file_metadata/http_spec.rb +194 -0
  311. data/spec/unit/indirector/file_metadata/rest_spec.rb +110 -2
  312. data/spec/unit/indirector/node/rest_spec.rb +57 -2
  313. data/spec/unit/indirector/report/rest_spec.rb +58 -51
  314. data/spec/unit/indirector/request_spec.rb +1 -1
  315. data/spec/unit/indirector/resource/ral_spec.rb +7 -8
  316. data/spec/unit/indirector/rest_spec.rb +13 -0
  317. data/spec/unit/indirector/status/rest_spec.rb +43 -2
  318. data/spec/unit/interface_spec.rb +3 -3
  319. data/spec/unit/network/http/api/indirected_routes_spec.rb +2 -1
  320. data/spec/unit/network/http/connection_spec.rb +559 -175
  321. data/spec/unit/network/http/nocache_pool_spec.rb +25 -3
  322. data/spec/unit/network/http/pool_spec.rb +89 -11
  323. data/spec/unit/network/http_pool_spec.rb +63 -57
  324. data/spec/unit/network/http_spec.rb +1 -1
  325. data/spec/unit/node/environment_spec.rb +16 -0
  326. data/spec/unit/node/facts_spec.rb +2 -1
  327. data/spec/unit/node_spec.rb +7 -4
  328. data/spec/unit/parser/ast/block_expression_spec.rb +1 -1
  329. data/spec/unit/parser/environment_compiler_spec.rb +7 -0
  330. data/spec/unit/parser/scope_spec.rb +1 -1
  331. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +15 -1
  332. data/spec/unit/pops/loaders/loaders_spec.rb +1 -1
  333. data/spec/unit/pops/serialization/to_from_hr_spec.rb +6 -1
  334. data/spec/unit/pops/types/type_calculator_spec.rb +1 -11
  335. data/spec/unit/pops/validator/validator_spec.rb +7 -2
  336. data/spec/unit/provider/aix_object_spec.rb +16 -2
  337. data/spec/unit/provider/group/groupadd_spec.rb +181 -56
  338. data/spec/unit/provider/group/windows_adsi_spec.rb +43 -10
  339. data/spec/unit/provider/package/aix_spec.rb +29 -0
  340. data/spec/unit/provider/package/apt_spec.rb +43 -2
  341. data/spec/unit/provider/package/aptitude_spec.rb +1 -0
  342. data/spec/unit/provider/package/dnfmodule_spec.rb +76 -15
  343. data/spec/unit/provider/package/dpkg_spec.rb +28 -6
  344. data/spec/unit/provider/package/gem_spec.rb +40 -0
  345. data/spec/unit/provider/package/openbsd_spec.rb +17 -0
  346. data/spec/unit/provider/package/pacman_spec.rb +6 -21
  347. data/spec/unit/provider/package/pip_spec.rb +68 -19
  348. data/spec/unit/provider/package/pkg_spec.rb +15 -1
  349. data/spec/unit/provider/package/pkgdmg_spec.rb +1 -1
  350. data/spec/unit/provider/package/pkgng_spec.rb +38 -0
  351. data/spec/unit/provider/package/portage_spec.rb +5 -0
  352. data/spec/unit/provider/package/puppet_gem_spec.rb +8 -0
  353. data/spec/unit/provider/package/rpm_spec.rb +0 -212
  354. data/spec/unit/provider/package/yum_spec.rb +292 -0
  355. data/spec/unit/provider/package/zypper_spec.rb +84 -0
  356. data/spec/unit/provider/service/init_spec.rb +1 -0
  357. data/spec/unit/provider/service/openbsd_spec.rb +9 -0
  358. data/spec/unit/provider/service/openwrt_spec.rb +1 -0
  359. data/spec/unit/provider/service/redhat_spec.rb +9 -0
  360. data/spec/unit/provider/service/systemd_spec.rb +92 -12
  361. data/spec/unit/provider/service/windows_spec.rb +22 -14
  362. data/spec/unit/provider/user/directoryservice_spec.rb +41 -0
  363. data/spec/unit/provider/user/openbsd_spec.rb +1 -0
  364. data/spec/unit/provider/user/useradd_spec.rb +43 -24
  365. data/spec/unit/provider/user/windows_adsi_spec.rb +3 -3
  366. data/spec/unit/puppet_pal_2pec.rb +0 -26
  367. data/spec/unit/puppet_pal_catalog_spec.rb +46 -0
  368. data/spec/unit/puppet_spec.rb +47 -0
  369. data/spec/unit/reports/http_spec.rb +70 -52
  370. data/spec/unit/resource_spec.rb +3 -3
  371. data/spec/unit/settings/autosign_setting_spec.rb +1 -1
  372. data/spec/unit/settings/http_extra_headers_spec.rb +64 -0
  373. data/spec/unit/ssl/certificate_spec.rb +7 -0
  374. data/spec/unit/ssl/host_spec.rb +4 -2
  375. data/spec/unit/ssl/oids_spec.rb +1 -0
  376. data/spec/unit/ssl/ssl_provider_spec.rb +69 -43
  377. data/spec/unit/ssl/state_machine_spec.rb +99 -13
  378. data/spec/unit/test/test_helper_spec.rb +17 -0
  379. data/spec/unit/transaction/persistence_spec.rb +1 -10
  380. data/spec/unit/transaction/report_spec.rb +5 -1
  381. data/spec/unit/transaction_spec.rb +0 -2
  382. data/spec/unit/type/file/ensure_spec.rb +1 -2
  383. data/spec/unit/type/file/source_spec.rb +89 -38
  384. data/spec/unit/type/file_spec.rb +122 -96
  385. data/spec/unit/type/package_spec.rb +8 -0
  386. data/spec/unit/type/service_spec.rb +185 -8
  387. data/spec/unit/type/user_spec.rb +1 -2
  388. data/spec/unit/type_spec.rb +50 -0
  389. data/spec/unit/util/at_fork_spec.rb +3 -2
  390. data/spec/unit/util/autoload_spec.rb +2 -1
  391. data/spec/unit/util/checksums_spec.rb +16 -0
  392. data/spec/unit/util/log/destinations_spec.rb +1 -29
  393. data/spec/unit/util/package/version/debian_spec.rb +83 -0
  394. data/spec/unit/util/package/version/pip_spec.rb +464 -0
  395. data/spec/unit/util/package/version/range_spec.rb +175 -0
  396. data/spec/unit/util/package/version/rpm_spec.rb +121 -0
  397. data/spec/unit/util/pidlock_spec.rb +112 -42
  398. data/spec/unit/util/plist_spec.rb +20 -0
  399. data/spec/unit/util/rpm_compare_spec.rb +196 -0
  400. data/spec/unit/util/storage_spec.rb +1 -8
  401. data/spec/unit/util/windows/adsi_spec.rb +4 -4
  402. data/spec/unit/util/windows/api_types_spec.rb +104 -40
  403. data/spec/unit/util/windows/service_spec.rb +4 -4
  404. data/spec/unit/util/windows/sid_spec.rb +2 -2
  405. data/spec/unit/util_spec.rb +3 -3
  406. data/spec/unit/x509/cert_provider_spec.rb +1 -1
  407. data/tasks/generate_cert_fixtures.rake +15 -1
  408. data/tasks/manpages.rake +5 -35
  409. metadata +73 -12
  410. data/COMMITTERS.md +0 -244
  411. data/spec/integration/faces/plugin_spec.rb +0 -61
  412. data/spec/integration/test/test_helper_spec.rb +0 -31
@@ -0,0 +1,201 @@
1
+ require 'spec_helper'
2
+ require 'puppet/http'
3
+
4
+ # Simple "external" client to make get & post requests. This is used
5
+ # to test the old HTTP API, such as requiring use_ssl and basic_auth
6
+ # to be passed as options.
7
+ class Puppet::HTTP::TestExternal
8
+ def initialize(host, port, options = {})
9
+ @host = host
10
+ @port = port
11
+ @options = options
12
+ @factory = Puppet::Network::HTTP::Factory.new
13
+ end
14
+
15
+ def get(path, headers = {}, options = {})
16
+ request = Net::HTTP::Get.new(path, headers)
17
+ do_request(request, options)
18
+ end
19
+
20
+ def post(path, data, headers = nil, options = {})
21
+ request = Net::HTTP::Post.new(path, headers)
22
+ do_request(request, options)
23
+ end
24
+
25
+ def do_request(request, options)
26
+ if options[:basic_auth]
27
+ request.basic_auth(options[:basic_auth][:user], options[:basic_auth][:password])
28
+ end
29
+
30
+ site = Puppet::Network::HTTP::Site.new(@options[:use_ssl] ? 'https' : 'http', @host, @port)
31
+ http = @factory.create_connection(site)
32
+ http.start
33
+ begin
34
+ http.request(request)
35
+ ensure
36
+ http.finish
37
+ end
38
+ end
39
+ end
40
+
41
+ describe Puppet::HTTP::ExternalClient do
42
+ let(:uri) { URI.parse('https://www.example.com') }
43
+ let(:http_client_class) { Puppet::HTTP::TestExternal }
44
+ let(:client) { described_class.new(http_client_class) }
45
+ let(:credentials) { ['user', 'pass'] }
46
+
47
+ context "for GET requests" do
48
+ it "stringifies keys and encodes values in the query" do
49
+ stub_request(:get, uri).with(query: "foo=bar%3Dbaz")
50
+
51
+ client.get(uri, params: {:foo => "bar=baz"})
52
+ end
53
+
54
+ it "fails if a user passes in an invalid param type" do
55
+ environment = Puppet::Node::Environment.create(:testing, [])
56
+
57
+ expect{client.get(uri, params: {environment: environment})}.to raise_error(Puppet::HTTP::SerializationError, /HTTP REST queries cannot handle values of type/)
58
+ end
59
+
60
+ it "returns the response" do
61
+ stub_request(:get, uri)
62
+
63
+ response = client.get(uri)
64
+ expect(response).to be_an_instance_of(Puppet::HTTP::Response)
65
+ expect(response).to be_success
66
+ expect(response.code).to eq(200)
67
+ end
68
+
69
+ it "returns the entire response body" do
70
+ stub_request(:get, uri).to_return(body: "abc")
71
+
72
+ expect(client.get(uri).body).to eq("abc")
73
+ end
74
+
75
+ it "streams the response body when a block is given" do
76
+ stub_request(:get, uri).to_return(body: "abc")
77
+
78
+ io = StringIO.new
79
+ client.get(uri) do |response|
80
+ response.read_body do |data|
81
+ io.write(data)
82
+ end
83
+ end
84
+
85
+ expect(io.string).to eq("abc")
86
+ end
87
+
88
+ context 'when connecting' do
89
+ it 'accepts an ssl context' do
90
+ stub_request(:get, uri).to_return(body: "abc")
91
+
92
+ other_context = Puppet::SSL::SSLContext.new
93
+
94
+ client.get(uri, options: {ssl_context: other_context})
95
+ end
96
+
97
+ it 'accepts include_system_store' do
98
+ stub_request(:get, uri).to_return(body: "abc")
99
+
100
+ client.get(uri, options: {include_system_store: true})
101
+ end
102
+ end
103
+ end
104
+
105
+ context "for POST requests" do
106
+ it "stringifies keys and encodes values in the query" do
107
+ stub_request(:post, "https://www.example.com").with(query: "foo=bar%3Dbaz")
108
+
109
+ client.post(uri, "", params: {:foo => "bar=baz"}, headers: {'Content-Type' => 'text/plain'})
110
+ end
111
+
112
+ it "returns the response" do
113
+ stub_request(:post, uri)
114
+
115
+ response = client.post(uri, "", headers: {'Content-Type' => 'text/plain'})
116
+ expect(response).to be_an_instance_of(Puppet::HTTP::Response)
117
+ expect(response).to be_success
118
+ expect(response.code).to eq(200)
119
+ end
120
+
121
+ it "sets content-type for the body" do
122
+ stub_request(:post, uri).with(headers: {"Content-Type" => "text/plain"})
123
+
124
+ client.post(uri, "hello", headers: {'Content-Type' => 'text/plain'})
125
+ end
126
+
127
+ it "streams the response body when a block is given" do
128
+ stub_request(:post, uri).to_return(body: "abc")
129
+
130
+ io = StringIO.new
131
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}) do |response|
132
+ response.read_body do |data|
133
+ io.write(data)
134
+ end
135
+ end
136
+
137
+ expect(io.string).to eq("abc")
138
+ end
139
+
140
+ it 'raises an ArgumentError if `body` is missing' do
141
+ expect {
142
+ client.post(uri, nil, headers: {'Content-Type' => 'text/plain'})
143
+ }.to raise_error(ArgumentError, /'post' requires a string 'body' argument/)
144
+ end
145
+
146
+ context 'when connecting' do
147
+ it 'accepts an ssl context' do
148
+ stub_request(:post, uri)
149
+
150
+ other_context = Puppet::SSL::SSLContext.new
151
+
152
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: other_context})
153
+ end
154
+
155
+ it 'accepts include_system_store' do
156
+ stub_request(:post, uri)
157
+
158
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {include_system_store: true})
159
+ end
160
+ end
161
+ end
162
+
163
+ context "Basic Auth" do
164
+ it "submits credentials for GET requests" do
165
+ stub_request(:get, uri).with(basic_auth: credentials)
166
+
167
+ client.get(uri, options: {basic_auth: {user: 'user', password: 'pass'}})
168
+ end
169
+
170
+ it "submits credentials for POST requests" do
171
+ stub_request(:post, uri).with(basic_auth: credentials)
172
+
173
+ client.post(uri, "", options: {content_type: 'text/plain', basic_auth: {user: 'user', password: 'pass'}})
174
+ end
175
+
176
+ it "returns response containing access denied" do
177
+ stub_request(:get, uri).with(basic_auth: credentials).to_return(status: [403, "Ye Shall Not Pass"])
178
+
179
+ response = client.get(uri, options: { basic_auth: {user: 'user', password: 'pass'}})
180
+ expect(response.code).to eq(403)
181
+ expect(response.reason).to eq("Ye Shall Not Pass")
182
+ expect(response).to_not be_success
183
+ end
184
+
185
+ it 'includes basic auth if user is nil' do
186
+ stub_request(:get, uri).with do |req|
187
+ expect(req.headers).to include('Authorization')
188
+ end
189
+
190
+ client.get(uri, options: {basic_auth: {user: nil, password: 'pass'}})
191
+ end
192
+
193
+ it 'includes basic auth if password is nil' do
194
+ stub_request(:get, uri).with do |req|
195
+ expect(req.headers).to include('Authorization')
196
+ end
197
+
198
+ client.get(uri, options: {basic_auth: {user: 'user', password: nil}})
199
+ end
200
+ end
201
+ end
@@ -22,10 +22,11 @@ describe Puppet::HTTP::Resolver do
22
22
  end
23
23
 
24
24
  context 'when resolving using server_list' do
25
+ let(:subject) { Puppet::HTTP::Resolver::ServerList.new(client, server_list_setting: Puppet.settings.setting(:server_list), default_port: 8142, services: Puppet::HTTP::Service::SERVICE_NAMES) }
26
+
25
27
  before :each do
26
28
  Puppet[:server_list] = 'ca.example.com:8141,apple.example.com'
27
29
  end
28
- let(:subject) { Puppet::HTTP::Resolver::ServerList.new(client, server_list_setting: Puppet.settings.setting(:server_list), default_port: 8142, services: [:puppet, :ca]) }
29
30
 
30
31
  it 'returns a service based on the current server_list setting' do
31
32
  stub_request(:get, "https://ca.example.com:8141/status/v1/simple/master").to_return(status: 200)
@@ -43,7 +44,18 @@ describe Puppet::HTTP::Resolver do
43
44
  expect(service.url.to_s).to eq("https://ca.example.com:8141/puppet-ca/v1")
44
45
  end
45
46
 
46
- it 'falls fails if no servers in server_list are accessible' do
47
+ it 'logs unsuccessful HTTP 500 responses' do
48
+ Puppet[:log_level] = "debug"
49
+
50
+ stub_request(:get, "https://ca.example.com:8141/status/v1/simple/master").to_return(status: [500, 'Internal Server Error'])
51
+ stub_request(:get, "https://apple.example.com:8142/status/v1/simple/master").to_return(status: 200)
52
+
53
+ subject.resolve(session, :ca)
54
+
55
+ expect(@logs.map(&:message)).to include(/Puppet server ca.example.com:8141 is unavailable: 500 Internal Server Error/)
56
+ end
57
+
58
+ it 'fails if no servers in server_list are accessible' do
47
59
  stub_request(:get, "https://ca.example.com:8141/status/v1/simple/master").to_return(status: 503)
48
60
  stub_request(:get, "https://apple.example.com:8142/status/v1/simple/master").to_return(status: 503)
49
61
 
@@ -58,6 +70,26 @@ describe Puppet::HTTP::Resolver do
58
70
  expect(service).to be_an_instance_of(Puppet::HTTP::Service::Ca)
59
71
  expect(service.url.to_s).to eq("https://apple.example.com:8142/puppet-ca/v1")
60
72
  end
73
+
74
+ it 'resolves once per session' do
75
+ failed = stub_request(:get, "https://ca.example.com:8141/status/v1/simple/master").to_return(status: 503)
76
+ passed = stub_request(:get, "https://apple.example.com:8142/status/v1/simple/master").to_return(status: 200)
77
+
78
+ service = subject.resolve(session, :puppet)
79
+ expect(service).to be_a(Puppet::HTTP::Service::Compiler)
80
+ expect(service.url.to_s).to eq("https://apple.example.com:8142/puppet/v3")
81
+
82
+ service = subject.resolve(session, :fileserver)
83
+ expect(service).to be_a(Puppet::HTTP::Service::FileServer)
84
+ expect(service.url.to_s).to eq("https://apple.example.com:8142/puppet/v3")
85
+
86
+ service = subject.resolve(session, :report)
87
+ expect(service).to be_a(Puppet::HTTP::Service::Report)
88
+ expect(service.url.to_s).to eq("https://apple.example.com:8142/puppet/v3")
89
+
90
+ expect(failed).to have_been_requested
91
+ expect(passed).to have_been_requested
92
+ end
61
93
  end
62
94
 
63
95
  context 'when resolving using SRV' do
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+ require 'puppet/http'
3
+
4
+ describe Puppet::HTTP::Response do
5
+ let(:uri) { URI.parse('https://www.example.com') }
6
+ let(:client) { Puppet::HTTP::Client.new }
7
+
8
+ it "returns the request URL" do
9
+ stub_request(:get, uri)
10
+
11
+ response = client.get(uri)
12
+ expect(response.url).to eq(uri)
13
+ end
14
+
15
+ it "returns the HTTP code" do
16
+ stub_request(:get, uri)
17
+
18
+ response = client.get(uri)
19
+ expect(response.code).to eq(200)
20
+ end
21
+
22
+ it "returns the HTTP reason string" do
23
+ stub_request(:get, uri).to_return(status: [418, "I'm a teapot"])
24
+
25
+ response = client.get(uri)
26
+ expect(response.reason).to eq("I'm a teapot")
27
+ end
28
+
29
+ it "returns the response body" do
30
+ stub_request(:get, uri).to_return(status: 200, body: "I'm the body")
31
+
32
+ response = client.get(uri)
33
+ expect(response.body).to eq("I'm the body")
34
+ end
35
+
36
+ it "streams the response body" do
37
+ stub_request(:get, uri).to_return(status: 200, body: "I'm the streaming body")
38
+
39
+ content = StringIO.new
40
+ client.get(uri) do |response|
41
+ response.read_body do |data|
42
+ content << data
43
+ end
44
+ end
45
+ expect(content.string).to eq("I'm the streaming body")
46
+ end
47
+
48
+ it "raises if a block isn't given when streaming" do
49
+ stub_request(:get, uri).to_return(status: 200, body: "")
50
+
51
+ expect {
52
+ client.get(uri) do |response|
53
+ response.read_body
54
+ end
55
+ }.to raise_error(Puppet::HTTP::HTTPError, %r{Request to https://www.example.com failed after .* seconds: A block is required})
56
+ end
57
+
58
+ it "returns success for all 2xx codes" do
59
+ stub_request(:get, uri).to_return(status: 202)
60
+
61
+ expect(client.get(uri)).to be_success
62
+ end
63
+
64
+ it "returns a header value" do
65
+ stub_request(:get, uri).to_return(status: 200, headers: { 'Content-Encoding' => 'gzip' })
66
+
67
+ expect(client.get(uri)['Content-Encoding']).to eq('gzip')
68
+ end
69
+
70
+ it "enumerates headers" do
71
+ stub_request(:get, uri).to_return(status: 200, headers: { 'Content-Encoding' => 'gzip' })
72
+
73
+ expect(client.get(uri).each_header.to_a).to eq([['content-encoding', 'gzip']])
74
+ end
75
+ end
@@ -5,6 +5,7 @@ require 'puppet/http'
5
5
  describe Puppet::HTTP::Service::Ca do
6
6
  let(:ssl_context) { Puppet::SSL::SSLContext.new }
7
7
  let(:client) { Puppet::HTTP::Client.new(ssl_context: ssl_context) }
8
+ let(:session) { Puppet::HTTP::Session.new(client, []) }
8
9
  let(:subject) { client.create_session.route_to(:ca) }
9
10
 
10
11
  before :each do
@@ -23,15 +24,6 @@ describe Puppet::HTTP::Service::Ca do
23
24
 
24
25
  subject.get_certificate('ca')
25
26
  end
26
-
27
-
28
- it 'includes the X-Puppet-Profiling header when Puppet[:profile] is true' do
29
- stub_request(:get, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./, 'X-Puppet-Profiling' => 'true'})
30
-
31
- Puppet[:profile] = true
32
-
33
- subject.get_certificate('ca')
34
- end
35
27
  end
36
28
 
37
29
  context 'when routing to the CA service' do
@@ -64,10 +56,27 @@ describe Puppet::HTTP::Service::Ca do
64
56
  let(:pem) { cert.to_pem }
65
57
  let(:url) { "https://www.example.com/puppet-ca/v1/certificate/ca" }
66
58
 
59
+ it 'includes headers set via the :http_extra_headers and :profile settings' do
60
+ stub_request(:get, url).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'})
61
+
62
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
63
+ Puppet[:profile] = true
64
+
65
+ subject.get_certificate('ca')
66
+ end
67
+
67
68
  it 'gets a certificate from the "certificate" endpoint' do
68
69
  stub_request(:get, url).to_return(body: pem)
69
70
 
70
- expect(subject.get_certificate('ca')).to eq(pem)
71
+ _, body = subject.get_certificate('ca')
72
+ expect(body).to eq(pem)
73
+ end
74
+
75
+ it 'returns the request response' do
76
+ stub_request(:get, url).to_return(body: pem)
77
+
78
+ resp, _ = subject.get_certificate('ca')
79
+ expect(resp).to be_a(Puppet::HTTP::Response)
71
80
  end
72
81
 
73
82
  it 'accepts text/plain responses' do
@@ -94,10 +103,27 @@ describe Puppet::HTTP::Service::Ca do
94
103
  let(:pem) { crl.to_pem }
95
104
  let(:url) { "https://www.example.com/puppet-ca/v1/certificate_revocation_list/ca" }
96
105
 
106
+ it 'includes headers set via the :http_extra_headers and :profile settings' do
107
+ stub_request(:get, url).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'})
108
+
109
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
110
+ Puppet[:profile] = true
111
+
112
+ subject.get_certificate_revocation_list
113
+ end
114
+
97
115
  it 'gets a CRL from "certificate_revocation_list" endpoint' do
98
116
  stub_request(:get, url).to_return(body: pem)
99
117
 
100
- expect(subject.get_certificate_revocation_list).to eq(pem)
118
+ _, body = subject.get_certificate_revocation_list
119
+ expect(body).to eq(pem)
120
+ end
121
+
122
+ it 'returns the request response' do
123
+ stub_request(:get, url).to_return(body: pem)
124
+
125
+ resp, _ = subject.get_certificate_revocation_list
126
+ expect(resp).to be_a(Puppet::HTTP::Response)
101
127
  end
102
128
 
103
129
  it 'accepts text/plain responses' do
@@ -136,12 +162,28 @@ describe Puppet::HTTP::Service::Ca do
136
162
  let(:pem) { request.to_pem }
137
163
  let(:url) { "https://www.example.com/puppet-ca/v1/certificate_request/infinity" }
138
164
 
165
+ it 'includes headers set via the :http_extra_headers and :profile settings' do
166
+ stub_request(:put, url).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'})
167
+
168
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
169
+ Puppet[:profile] = true
170
+
171
+ subject.put_certificate_request('infinity', request)
172
+ end
173
+
139
174
  it 'submits a CSR to the "certificate_request" endpoint' do
140
175
  stub_request(:put, url).with(body: pem, headers: { 'Content-Type' => 'text/plain' })
141
176
 
142
177
  subject.put_certificate_request('infinity', request)
143
178
  end
144
179
 
180
+ it 'returns the request response' do
181
+ stub_request(:put, url).with(body: pem, headers: { 'Content-Type' => 'text/plain' })
182
+
183
+ resp = subject.put_certificate_request('infinity', request)
184
+ expect(resp).to be_a(Puppet::HTTP::Response)
185
+ end
186
+
145
187
  it 'raises response error if unsuccessful' do
146
188
  stub_request(:put, url).to_return(status: [400, 'Bad Request'])
147
189
 
@@ -0,0 +1,627 @@
1
+ # coding: utf-8
2
+ require 'spec_helper'
3
+ require 'webmock/rspec'
4
+ require 'puppet/http'
5
+
6
+ describe Puppet::HTTP::Service::Compiler do
7
+ let(:ssl_context) { Puppet::SSL::SSLContext.new }
8
+ let(:client) { Puppet::HTTP::Client.new(ssl_context: ssl_context) }
9
+ let(:subject) { client.create_session.route_to(:puppet) }
10
+ let(:environment) { 'testing' }
11
+ let(:certname) { 'ziggy' }
12
+ let(:node) { Puppet::Node.new(certname) }
13
+ let(:facts) { Puppet::Node::Facts.new(certname) }
14
+ let(:catalog) { Puppet::Resource::Catalog.new(certname) }
15
+ let(:status) { Puppet::Status.new }
16
+ let(:formatter) { Puppet::Network::FormatHandler.format(:json) }
17
+
18
+ before :each do
19
+ Puppet[:server] = 'compiler.example.com'
20
+ Puppet[:masterport] = 8140
21
+
22
+ Puppet::Node::Facts.indirection.terminus_class = :memory
23
+ end
24
+
25
+ context 'when making requests' do
26
+ let(:uri) {"https://compiler.example.com:8140/puppet/v3/catalog/ziggy?environment=testing"}
27
+
28
+ it 'includes default HTTP headers' do
29
+ stub_request(:post, uri).with do |request|
30
+ expect(request.headers).to include({'X-Puppet-Version' => /./, 'User-Agent' => /./})
31
+ expect(request.headers).to_not include('X-Puppet-Profiling')
32
+ end.to_return(body: formatter.render(catalog), headers: {'Content-Type' => formatter.mime })
33
+
34
+ subject.post_catalog(certname, environment: environment, facts: facts)
35
+ end
36
+ end
37
+
38
+ context 'when routing to the compiler service' do
39
+ it 'defaults the server and port based on settings' do
40
+ Puppet[:server] = 'compiler2.example.com'
41
+ Puppet[:masterport] = 8141
42
+
43
+ stub_request(:post, "https://compiler2.example.com:8141/puppet/v3/catalog/ziggy?environment=testing")
44
+ .to_return(body: formatter.render(catalog), headers: {'Content-Type' => formatter.mime })
45
+
46
+ subject.post_catalog(certname, environment: environment, facts: facts)
47
+ end
48
+ end
49
+
50
+ context 'when posting for a catalog' do
51
+ let(:uri) { %r{/puppet/v3/catalog/ziggy} }
52
+ let(:catalog_response) { { body: formatter.render(catalog), headers: {'Content-Type' => formatter.mime } } }
53
+
54
+ it 'includes puppet headers set via the :http_extra_headers and :profile settings' do
55
+ stub_request(:post, uri).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'}).
56
+ to_return(body: formatter.render(catalog), headers: {'Content-Type' => formatter.mime })
57
+
58
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
59
+ Puppet[:profile] = true
60
+
61
+ subject.post_catalog(certname, environment: environment, facts: facts)
62
+ end
63
+
64
+ it 'submits facts as application/json by default' do
65
+ stub_request(:post, uri)
66
+ .with(body: hash_including("facts_format" => /application\/json/))
67
+ .to_return(**catalog_response)
68
+
69
+ subject.post_catalog(certname, environment: environment, facts: facts)
70
+ end
71
+
72
+ it 'submits facts as pson if set as the preferred format' do
73
+ Puppet[:preferred_serialization_format] = "pson"
74
+
75
+ stub_request(:post, uri)
76
+ .with(body: hash_including("facts_format" => /pson/))
77
+ .to_return(**catalog_response)
78
+
79
+ subject.post_catalog(certname, environment: environment, facts: facts)
80
+ end
81
+
82
+ it 'includes environment as a query parameter AND in the POST body' do
83
+ stub_request(:post, uri)
84
+ .with(query: {"environment" => "outerspace"},
85
+ body: hash_including("environment" => 'outerspace'))
86
+ .to_return(**catalog_response)
87
+
88
+ subject.post_catalog(certname, environment: 'outerspace', facts: facts)
89
+ end
90
+
91
+ it 'includes configured_environment' do
92
+ stub_request(:post, uri)
93
+ .with(body: hash_including("configured_environment" => 'agent_specified'))
94
+ .to_return(**catalog_response)
95
+
96
+ subject.post_catalog(certname, environment: 'production', facts: facts, configured_environment: 'agent_specified')
97
+ end
98
+
99
+ it 'includes transaction_uuid' do
100
+ uuid = "ec3d2844-b236-4287-b0ad-632fbb4d1ff0"
101
+
102
+ stub_request(:post, uri)
103
+ .with(body: hash_including("transaction_uuid" => uuid))
104
+ .to_return(**catalog_response)
105
+
106
+ subject.post_catalog(certname, environment: 'production', facts: facts, transaction_uuid: uuid)
107
+ end
108
+
109
+ it 'includes job_uuid' do
110
+ uuid = "3dd13eec-1b6b-4b5d-867b-148193e0593e"
111
+
112
+ stub_request(:post, uri)
113
+ .with(body: hash_including("job_uuid" => uuid))
114
+ .to_return(**catalog_response)
115
+
116
+ subject.post_catalog(certname, environment: 'production', facts: facts, job_uuid: uuid)
117
+ end
118
+
119
+ it 'includes static_catalog' do
120
+ stub_request(:post, uri)
121
+ .with(body: hash_including("static_catalog" => "false"))
122
+ .to_return(**catalog_response)
123
+
124
+ subject.post_catalog(certname, environment: 'production', facts: facts, static_catalog: false)
125
+ end
126
+
127
+ it 'includes dot-separated list of checksum_types' do
128
+ stub_request(:post, uri)
129
+ .with(body: hash_including("checksum_type" => "sha256.sha384"))
130
+ .to_return(**catalog_response)
131
+
132
+ subject.post_catalog(certname, environment: 'production', facts: facts, checksum_type: %w[sha256 sha384])
133
+ end
134
+
135
+ it 'returns a deserialized catalog' do
136
+ stub_request(:post, uri)
137
+ .to_return(**catalog_response)
138
+
139
+ _, cat = subject.post_catalog(certname, environment: 'production', facts: facts)
140
+ expect(cat).to be_a(Puppet::Resource::Catalog)
141
+ expect(cat.name).to eq(certname)
142
+ end
143
+
144
+ it 'returns the request response' do
145
+ stub_request(:post, uri)
146
+ .to_return(**catalog_response)
147
+
148
+ resp, _ = subject.post_catalog(certname, environment: 'production', facts: facts)
149
+ expect(resp).to be_a(Puppet::HTTP::Response)
150
+ end
151
+
152
+ it 'raises a response error if unsuccessful' do
153
+ stub_request(:post, uri)
154
+ .to_return(status: [500, "Server Error"])
155
+
156
+ expect {
157
+ subject.post_catalog(certname, environment: 'production', facts: facts)
158
+ }.to raise_error do |err|
159
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
160
+ expect(err.message).to eq('Server Error')
161
+ expect(err.response.code).to eq(500)
162
+ end
163
+ end
164
+
165
+ it 'raises a protocol error if the content-type header is missing' do
166
+ stub_request(:post, uri)
167
+ .to_return(body: "content-type is missing")
168
+
169
+ expect {
170
+ subject.post_catalog(certname, environment: 'production', facts: facts)
171
+ }.to raise_error(Puppet::HTTP::ProtocolError, /No content type in http response; cannot parse/)
172
+ end
173
+
174
+ it 'raises a serialization error if the content is invalid' do
175
+ stub_request(:post, uri)
176
+ .to_return(body: "this isn't valid JSON", headers: {'Content-Type' => 'application/json'})
177
+
178
+ expect {
179
+ subject.post_catalog(certname, environment: 'production', facts: facts)
180
+ }.to raise_error(Puppet::HTTP::SerializationError, /Failed to deserialize Puppet::Resource::Catalog from json/)
181
+ end
182
+
183
+ context 'serializing facts' do
184
+ facts_with_special_characters = [
185
+ { :hash => { 'afact' => 'a+b' }, :encoded => 'a%2Bb' },
186
+ { :hash => { 'afact' => 'a b' }, :encoded => 'a%20b' },
187
+ { :hash => { 'afact' => 'a&b' }, :encoded => 'a%26b' },
188
+ { :hash => { 'afact' => 'a*b' }, :encoded => 'a%2Ab' },
189
+ { :hash => { 'afact' => 'a=b' }, :encoded => 'a%3Db' },
190
+ # different UTF-8 widths
191
+ # 1-byte A
192
+ # 2-byte ۿ - http://www.fileformat.info/info/unicode/char/06ff/index.htm - 0xDB 0xBF / 219 191
193
+ # 3-byte ᚠ - http://www.fileformat.info/info/unicode/char/16A0/index.htm - 0xE1 0x9A 0xA0 / 225 154 160
194
+ # 4-byte 𠜎 - http://www.fileformat.info/info/unicode/char/2070E/index.htm - 0xF0 0xA0 0x9C 0x8E / 240 160 156 142
195
+ { :hash => { 'afact' => "A\u06FF\u16A0\u{2070E}" }, :encoded => 'A%DB%BF%E1%9A%A0%F0%A0%9C%8E' },
196
+ ]
197
+
198
+ facts_with_special_characters.each do |test_fact|
199
+ it "escapes special characters #{test_fact[:hash]}" do
200
+ facts = Puppet::Node::Facts.new(certname, test_fact[:hash])
201
+ Puppet::Node::Facts.indirection.save(facts)
202
+
203
+ stub_request(:post, uri)
204
+ .with(body: hash_including("facts" => /#{test_fact[:encoded]}/))
205
+ .to_return(**catalog_response)
206
+
207
+ subject.post_catalog(certname, environment: environment, facts: facts)
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ context 'when getting a node' do
214
+ let(:uri) { %r{/puppet/v3/node/ziggy} }
215
+ let(:node_response) { { body: formatter.render(node), headers: {'Content-Type' => formatter.mime } } }
216
+
217
+ it 'includes custom headers set via the :http_extra_headers and :profile settings' do
218
+ stub_request(:get, uri).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'}).
219
+ to_return(**node_response)
220
+
221
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
222
+ Puppet[:profile] = true
223
+
224
+ subject.get_node(certname, environment: 'production')
225
+ end
226
+
227
+ it 'includes environment' do
228
+ stub_request(:get, uri)
229
+ .with(query: hash_including("environment" => "outerspace"))
230
+ .to_return(**node_response)
231
+
232
+ subject.get_node(certname, environment: 'outerspace')
233
+ end
234
+
235
+ it 'includes configured_environment' do
236
+ stub_request(:get, uri)
237
+ .with(query: hash_including("configured_environment" => 'agent_specified'))
238
+ .to_return(**node_response)
239
+
240
+ subject.get_node(certname, environment: 'production', configured_environment: 'agent_specified')
241
+ end
242
+
243
+ it 'includes transaction_uuid' do
244
+ uuid = "ec3d2844-b236-4287-b0ad-632fbb4d1ff0"
245
+
246
+ stub_request(:get, uri)
247
+ .with(query: hash_including("transaction_uuid" => uuid))
248
+ .to_return(**node_response)
249
+
250
+ subject.get_node(certname, environment: 'production', transaction_uuid: uuid)
251
+ end
252
+
253
+ it 'returns a deserialized node' do
254
+ stub_request(:get, uri)
255
+ .to_return(**node_response)
256
+
257
+ _, n = subject.get_node(certname, environment: 'production')
258
+ expect(n).to be_a(Puppet::Node)
259
+ expect(n.name).to eq(certname)
260
+ end
261
+
262
+ it 'returns the request response' do
263
+ stub_request(:get, uri)
264
+ .to_return(**node_response)
265
+
266
+ resp, _ = subject.get_node(certname, environment: 'production')
267
+ expect(resp).to be_a(Puppet::HTTP::Response)
268
+ end
269
+
270
+ it 'raises a response error if unsuccessful' do
271
+ stub_request(:get, uri)
272
+ .to_return(status: [500, "Server Error"])
273
+
274
+ expect {
275
+ subject.get_node(certname, environment: 'production')
276
+ }.to raise_error do |err|
277
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
278
+ expect(err.message).to eq('Server Error')
279
+ expect(err.response.code).to eq(500)
280
+ end
281
+ end
282
+
283
+ it 'raises a protocol error if the content-type header is missing' do
284
+ stub_request(:get, uri)
285
+ .to_return(body: "content-type is missing")
286
+
287
+ expect {
288
+ subject.get_node(certname, environment: 'production')
289
+ }.to raise_error(Puppet::HTTP::ProtocolError, /No content type in http response; cannot parse/)
290
+ end
291
+
292
+ it 'raises a serialization error if the content is invalid' do
293
+ stub_request(:get, uri)
294
+ .to_return(body: "this isn't valid JSON", headers: {'Content-Type' => 'application/json'})
295
+
296
+ expect {
297
+ subject.get_node(certname, environment: 'production')
298
+ }.to raise_error(Puppet::HTTP::SerializationError, /Failed to deserialize Puppet::Node from json/)
299
+ end
300
+ end
301
+
302
+ context 'when getting facts' do
303
+ let(:uri) { %r{/puppet/v3/facts/ziggy} }
304
+ let(:facts_response) { { body: formatter.render(facts), headers: {'Content-Type' => formatter.mime } } }
305
+
306
+ it 'includes environment' do
307
+ stub_request(:get, uri)
308
+ .with(query: hash_including("environment" => "outerspace"))
309
+ .to_return(**facts_response)
310
+
311
+ subject.get_facts(certname, environment: 'outerspace')
312
+ end
313
+
314
+ it 'returns a deserialized facts object' do
315
+ stub_request(:get, uri)
316
+ .to_return(**facts_response)
317
+
318
+ _, n = subject.get_facts(certname, environment: 'production')
319
+ expect(n).to be_a(Puppet::Node::Facts)
320
+ expect(n.name).to eq(certname)
321
+ end
322
+
323
+ it 'returns the request response' do
324
+ stub_request(:get, uri)
325
+ .to_return(**facts_response)
326
+
327
+ resp, _ = subject.get_facts(certname, environment: 'production')
328
+ expect(resp).to be_a(Puppet::HTTP::Response)
329
+ end
330
+
331
+ it 'raises a response error if unsuccessful' do
332
+ stub_request(:get, uri)
333
+ .to_return(status: [500, "Server Error"])
334
+
335
+ expect {
336
+ subject.get_facts(certname, environment: 'production')
337
+ }.to raise_error do |err|
338
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
339
+ expect(err.message).to eq('Server Error')
340
+ expect(err.response.code).to eq(500)
341
+ end
342
+ end
343
+
344
+ it 'raises a protocol error if the content-type header is missing' do
345
+ stub_request(:get, uri)
346
+ .to_return(body: "content-type is missing")
347
+
348
+ expect {
349
+ subject.get_facts(certname, environment: 'production')
350
+ }.to raise_error(Puppet::HTTP::ProtocolError, /No content type in http response; cannot parse/)
351
+ end
352
+
353
+ it 'raises a serialization error if the content is invalid' do
354
+ stub_request(:get, uri)
355
+ .to_return(body: "this isn't valid JSON", headers: {'Content-Type' => 'application/json'})
356
+
357
+ expect {
358
+ subject.get_facts(certname, environment: 'production')
359
+ }.to raise_error(Puppet::HTTP::SerializationError, /Failed to deserialize Puppet::Node::Facts from json/)
360
+ end
361
+ end
362
+
363
+ context 'when putting facts' do
364
+ let(:uri) { %r{/puppet/v3/facts/ziggy} }
365
+
366
+ it 'includes custom headers set the :http_extra_headers and :profile settings' do
367
+ stub_request(:put, uri).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'})
368
+
369
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
370
+ Puppet[:profile] = true
371
+
372
+ subject.put_facts(certname, environment: environment, facts: facts)
373
+ end
374
+
375
+ it 'serializes facts in the body' do
376
+ facts = Puppet::Node::Facts.new(certname, { 'domain' => 'zork'})
377
+ Puppet::Node::Facts.indirection.save(facts)
378
+
379
+ stub_request(:put, uri)
380
+ .with(body: hash_including("name" => "ziggy", "values" => {"domain" => "zork"}))
381
+
382
+ subject.put_facts(certname, environment: environment, facts: facts)
383
+ end
384
+
385
+ it 'includes environment' do
386
+ stub_request(:put, uri)
387
+ .with(query: {"environment" => "outerspace"})
388
+
389
+ subject.put_facts(certname, environment: 'outerspace', facts: facts)
390
+ end
391
+
392
+ it 'returns the request response' do
393
+ # the REST API returns the filename, good grief
394
+ stub_request(:put, uri)
395
+ .to_return(status: 200, body: "/opt/puppetlabs/server/data/puppetserver/yaml/facts/#{certname}.yaml")
396
+
397
+ expect(subject.put_facts(certname, environment: environment, facts: facts)).to be_a(Puppet::HTTP::Response)
398
+ end
399
+
400
+ it 'raises a response error if unsuccessful' do
401
+ stub_request(:put, uri)
402
+ .to_return(status: [500, "Server Error"])
403
+
404
+ expect {
405
+ subject.put_facts(certname, environment: environment, facts: facts)
406
+ }.to raise_error do |err|
407
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
408
+ expect(err.message).to eq('Server Error')
409
+ expect(err.response.code).to eq(500)
410
+ end
411
+ end
412
+
413
+ it 'raises a serialization error if the report cannot be serialized' do
414
+ invalid_facts = Puppet::Node::Facts.new(certname, {'invalid_utf8_sequence' => "\xE2\x82".force_encoding('binary')})
415
+ expect {
416
+ subject.put_facts(certname, environment: 'production', facts: invalid_facts)
417
+ }.to raise_error(Puppet::HTTP::SerializationError, /Failed to serialize Puppet::Node::Facts to json: "\\xE2" from ASCII-8BIT to UTF-8/)
418
+ end
419
+ end
420
+
421
+ context 'when getting status' do
422
+ let(:uri) { %r{/puppet/v3/status/ziggy} }
423
+ let(:status_response) { { body: formatter.render(status), headers: {'Content-Type' => formatter.mime } } }
424
+
425
+ it 'always sends production' do
426
+ stub_request(:get, uri)
427
+ .with(query: hash_including("environment" => "production"))
428
+ .to_return(**status_response)
429
+
430
+ subject.get_status(certname)
431
+ end
432
+
433
+ it 'returns a deserialized status' do
434
+ stub_request(:get, uri)
435
+ .to_return(**status_response)
436
+
437
+ _, s = subject.get_status(certname)
438
+ expect(s).to be_a(Puppet::Status)
439
+ expect(s.status).to eq("is_alive" => true)
440
+ end
441
+
442
+ it 'returns the request response' do
443
+ stub_request(:get, uri)
444
+ .to_return(**status_response)
445
+
446
+ resp, _ = subject.get_status(certname)
447
+ expect(resp).to be_a(Puppet::HTTP::Response)
448
+ end
449
+
450
+ it 'raises a response error if unsuccessful' do
451
+ stub_request(:get, uri)
452
+ .to_return(status: [500, "Server Error"])
453
+
454
+ expect {
455
+ subject.get_status(certname)
456
+ }.to raise_error do |err|
457
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
458
+ expect(err.message).to eq('Server Error')
459
+ expect(err.response.code).to eq(500)
460
+ end
461
+ end
462
+
463
+ it 'raises a protocol error if the content-type header is missing' do
464
+ stub_request(:get, uri)
465
+ .to_return(body: "content-type is missing")
466
+
467
+ expect {
468
+ subject.get_status(certname)
469
+ }.to raise_error(Puppet::HTTP::ProtocolError, /No content type in http response; cannot parse/)
470
+ end
471
+
472
+ it 'raises a serialization error if the content is invalid' do
473
+ stub_request(:get, uri)
474
+ .to_return(body: "this isn't valid JSON", headers: {'Content-Type' => 'application/json'})
475
+
476
+ expect {
477
+ subject.get_status(certname)
478
+ }.to raise_error(Puppet::HTTP::SerializationError, /Failed to deserialize Puppet::Status from json/)
479
+ end
480
+ end
481
+
482
+ context 'filebucket' do
483
+ let(:filebucket_file) { Puppet::FileBucket::File.new('file to store') }
484
+ let(:formatter) { Puppet::Network::FormatHandler.format(:binary) }
485
+ let(:path) { "md5/4aabe1257043bd03ce4c3319c155bc55" }
486
+ let(:uri) { %r{/puppet/v3/file_bucket_file/#{path}} }
487
+
488
+ context 'when getting a file' do
489
+ let(:status_response) { { body: formatter.render(filebucket_file), headers: {'Content-Type' => 'application/octet-stream' }}}
490
+
491
+ it 'includes default HTTP headers' do
492
+ stub_request(:get, uri).with do |request|
493
+ expect(request.headers).to include({
494
+ 'X-Puppet-Version' => /./,
495
+ 'User-Agent' => /./,
496
+ 'Accept' => 'application/octet-stream'
497
+ })
498
+ expect(request.headers).to_not include('X-Puppet-Profiling')
499
+ end.to_return(**status_response)
500
+
501
+ subject.get_filebucket_file(path, environment: 'production')
502
+ end
503
+
504
+ it 'always the environment as a parameter' do
505
+ stub_request(:get, uri).with(query: hash_including('environment' => 'production')).to_return(**status_response)
506
+
507
+ subject.get_filebucket_file(path, environment: 'production')
508
+ end
509
+
510
+ {bucket_path: 'path', diff_with: '4aabe1257043bd0', list_all: 'true', fromdate: '20200404', todate: '20200404'}.each do |param, val|
511
+ it "includes #{param} as a parameter in the request if #{param} is set" do
512
+ stub_request(:get, uri).with(query: hash_including(param => val)).to_return(**status_response)
513
+
514
+ options = { param => val }
515
+ subject.get_filebucket_file(path, environment: 'production', **options)
516
+ end
517
+ end
518
+
519
+ it "doesn't include :diff_with as a query param if :bucket_path is nil" do
520
+ stub_request(:get, uri).with do |request|
521
+ expect(request.uri.query).not_to match(/diff_with/)
522
+ end.to_return(**status_response)
523
+
524
+ subject.get_filebucket_file(path, environment: 'production', diff_with: nil)
525
+ end
526
+
527
+ it 'returns a deserialized response' do
528
+ stub_request(:get, uri)
529
+ .to_return(**status_response)
530
+
531
+ _, s = subject.get_filebucket_file(path, environment: 'production')
532
+ expect(s).to be_a(Puppet::FileBucket::File)
533
+ expect(s.contents).to eq('file to store')
534
+ end
535
+
536
+ it 'returns the request response' do
537
+ stub_request(:get, uri)
538
+ .to_return(**status_response)
539
+
540
+ resp, _ = subject.get_filebucket_file(path, environment: 'production')
541
+ expect(resp).to be_a(Puppet::HTTP::Response)
542
+ end
543
+ end
544
+
545
+ context 'when putting a file' do
546
+ let(:status_response) { { status: 200, body: '' } }
547
+
548
+ it 'includes default HTTP headers' do
549
+ stub_request(:put, uri).with do |request|
550
+ expect(request.headers).to include({
551
+ 'X-Puppet-Version' => /./,
552
+ 'User-Agent' => /./,
553
+ 'Accept' => 'application/octet-stream',
554
+ 'Content-Type' => 'application/octet-stream'
555
+ })
556
+ expect(request.headers).to_not include('X-Puppet-Profiling')
557
+ end.to_return(**status_response)
558
+
559
+ subject.put_filebucket_file(path, body: filebucket_file.contents, environment: 'production')
560
+ end
561
+
562
+ it 'always the environment as a parameter' do
563
+ stub_request(:put, uri).with(query: hash_including('environment' => 'production')).to_return(**status_response)
564
+
565
+ subject.put_filebucket_file(path, body: filebucket_file.contents, environment: 'production')
566
+ end
567
+
568
+ it 'sends the file contents as the request body' do
569
+ stub_request(:put, uri).with(body: filebucket_file.contents).to_return(**status_response)
570
+
571
+ subject.put_filebucket_file(path, body: filebucket_file.contents, environment: 'production')
572
+ end
573
+
574
+ it 'returns the request response' do
575
+ stub_request(:put, uri)
576
+ .to_return(**status_response)
577
+
578
+ s = subject.put_filebucket_file(path, body: filebucket_file.contents, environment: 'production')
579
+ expect(s).to be_a(Puppet::HTTP::Response)
580
+ end
581
+ end
582
+
583
+ context 'when heading a file' do
584
+ let(:status_response) {{ status: 200 }}
585
+
586
+ it 'includes default HTTP headers' do
587
+ stub_request(:head, uri).with do |request|
588
+ expect(request.headers).to include({
589
+ 'X-Puppet-Version' => /./,
590
+ 'User-Agent' => /./,
591
+ 'Accept' => 'application/octet-stream',
592
+ })
593
+ expect(request.headers).to_not include('X-Puppet-Profiling')
594
+ end.to_return(**status_response)
595
+
596
+ subject.head_filebucket_file(path, environment: 'production')
597
+ end
598
+
599
+ it 'always the environment as a parameter' do
600
+ stub_request(:head, uri).with(query: hash_including('environment' => 'production')).to_return(**status_response)
601
+
602
+ subject.head_filebucket_file(path, environment: 'production')
603
+ end
604
+
605
+ it "includes :bucket_path as a parameter in the request if :bucket_path is set" do
606
+ stub_request(:head, uri).with(query: hash_including(:bucket_path => 'some/path')).to_return(**status_response)
607
+
608
+ subject.head_filebucket_file(path, environment: 'production', bucket_path: 'some/path')
609
+ end
610
+
611
+ it "doesn't include :bucket_path as a query param if :bucket_path is nil" do
612
+ stub_request(:head, uri).with do |request|
613
+ expect(request.uri.query).not_to match(/bucket_path/)
614
+ end.to_return(**status_response)
615
+
616
+ subject.head_filebucket_file(path, environment: 'production', bucket_path: nil)
617
+ end
618
+
619
+ it "returns the request response" do
620
+ stub_request(:head, uri).with(query: hash_including(:bucket_path => 'some/path')).to_return(**status_response)
621
+
622
+ resp = subject.head_filebucket_file(path, environment: 'production', bucket_path: 'some/path')
623
+ expect(resp).to be_a(Puppet::HTTP::Response)
624
+ end
625
+ end
626
+ end
627
+ end