puppet 6.11.1 → 6.16.0

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 (395) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +3 -8
  3. data/CONTRIBUTING.md +7 -13
  4. data/Gemfile +1 -0
  5. data/Gemfile.lock +39 -36
  6. data/README.md +17 -24
  7. data/ext/build_defaults.yaml +1 -0
  8. data/ext/project_data.yaml +1 -1
  9. data/ext/windows/service/daemon.rb +25 -20
  10. data/lib/puppet.rb +52 -13
  11. data/lib/puppet/agent.rb +20 -14
  12. data/lib/puppet/application/agent.rb +12 -14
  13. data/lib/puppet/application/describe.rb +7 -5
  14. data/lib/puppet/application/device.rb +2 -2
  15. data/lib/puppet/application/filebucket.rb +19 -15
  16. data/lib/puppet/application/plugin.rb +1 -0
  17. data/lib/puppet/application/resource.rb +1 -1
  18. data/lib/puppet/application/ssl.rb +4 -4
  19. data/lib/puppet/concurrent.rb +2 -0
  20. data/lib/puppet/concurrent/lock.rb +16 -0
  21. data/lib/puppet/concurrent/synchronized.rb +15 -0
  22. data/lib/puppet/concurrent/thread_local_singleton.rb +14 -0
  23. data/lib/puppet/configurer.rb +85 -83
  24. data/lib/puppet/configurer/plugin_handler.rb +10 -1
  25. data/lib/puppet/context/trusted_information.rb +14 -8
  26. data/lib/puppet/daemon.rb +13 -27
  27. data/lib/puppet/defaults.rb +158 -40
  28. data/lib/puppet/environments.rb +30 -20
  29. data/lib/puppet/error.rb +9 -1
  30. data/lib/puppet/face/facts.rb +8 -5
  31. data/lib/puppet/face/help.rb +29 -3
  32. data/lib/puppet/face/module/search.rb +5 -0
  33. data/lib/puppet/face/plugin.rb +2 -2
  34. data/lib/puppet/file_serving/http_metadata.rb +1 -1
  35. data/lib/puppet/file_system/file_impl.rb +13 -9
  36. data/lib/puppet/file_system/memory_file.rb +6 -0
  37. data/lib/puppet/file_system/memory_impl.rb +13 -0
  38. data/lib/puppet/file_system/uniquefile.rb +4 -0
  39. data/lib/puppet/file_system/windows.rb +7 -10
  40. data/lib/puppet/forge.rb +3 -3
  41. data/lib/puppet/forge/errors.rb +2 -2
  42. data/lib/puppet/forge/repository.rb +31 -86
  43. data/lib/puppet/functions/call.rb +1 -1
  44. data/lib/puppet/functions/camelcase.rb +2 -2
  45. data/lib/puppet/functions/epp.rb +4 -4
  46. data/lib/puppet/functions/eyaml_lookup_key.rb +13 -8
  47. data/lib/puppet/functions/filter.rb +1 -0
  48. data/lib/puppet/functions/find_file.rb +9 -9
  49. data/lib/puppet/functions/find_template.rb +63 -0
  50. data/lib/puppet/functions/inline_epp.rb +5 -5
  51. data/lib/puppet/functions/reduce.rb +2 -4
  52. data/lib/puppet/http.rb +7 -0
  53. data/lib/puppet/http/client.rb +341 -54
  54. data/lib/puppet/http/errors.rb +2 -0
  55. data/lib/puppet/http/external_client.rb +90 -0
  56. data/lib/puppet/http/redirector.rb +34 -0
  57. data/lib/puppet/http/resolver.rb +57 -1
  58. data/lib/puppet/http/resolver/server_list.rb +98 -0
  59. data/lib/puppet/http/resolver/settings.rb +23 -2
  60. data/lib/puppet/http/resolver/srv.rb +36 -4
  61. data/lib/puppet/http/response.rb +68 -1
  62. data/lib/puppet/http/retry_after_handler.rb +39 -0
  63. data/lib/puppet/http/service.rb +179 -3
  64. data/lib/puppet/http/service/ca.rb +84 -21
  65. data/lib/puppet/http/service/compiler.rb +319 -0
  66. data/lib/puppet/http/service/file_server.rb +206 -0
  67. data/lib/puppet/http/service/report.rb +66 -0
  68. data/lib/puppet/http/session.rb +106 -31
  69. data/lib/puppet/indirector/catalog/compiler.rb +10 -0
  70. data/lib/puppet/indirector/catalog/rest.rb +34 -0
  71. data/lib/puppet/indirector/facts/rest.rb +42 -0
  72. data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  73. data/lib/puppet/indirector/file_bucket_file/rest.rb +48 -0
  74. data/lib/puppet/indirector/file_content/http.rb +5 -0
  75. data/lib/puppet/indirector/file_content/rest.rb +30 -0
  76. data/lib/puppet/indirector/file_metadata/http.rb +4 -4
  77. data/lib/puppet/indirector/file_metadata/rest.rb +52 -0
  78. data/lib/puppet/indirector/json.rb +1 -1
  79. data/lib/puppet/indirector/msgpack.rb +1 -1
  80. data/lib/puppet/indirector/node/rest.rb +24 -0
  81. data/lib/puppet/indirector/report/rest.rb +19 -0
  82. data/lib/puppet/indirector/report/yaml.rb +23 -0
  83. data/lib/puppet/indirector/rest.rb +12 -0
  84. data/lib/puppet/indirector/status/rest.rb +18 -0
  85. data/lib/puppet/loaders.rb +6 -0
  86. data/lib/puppet/metatype/manager.rb +80 -80
  87. data/lib/puppet/network/http/base_pool.rb +19 -1
  88. data/lib/puppet/network/http/compression.rb +7 -0
  89. data/lib/puppet/network/http/connection.rb +6 -0
  90. data/lib/puppet/network/http/connection_adapter.rb +182 -0
  91. data/lib/puppet/network/http/nocache_pool.rb +2 -0
  92. data/lib/puppet/network/http/pool.rb +13 -6
  93. data/lib/puppet/network/http_pool.rb +2 -1
  94. data/lib/puppet/node/environment.rb +24 -8
  95. data/lib/puppet/pal/catalog_compiler.rb +5 -0
  96. data/lib/puppet/pal/pal_impl.rb +9 -29
  97. data/lib/puppet/parser/ast/pops_bridge.rb +6 -11
  98. data/lib/puppet/parser/compiler.rb +42 -32
  99. data/lib/puppet/parser/functions.rb +18 -13
  100. data/lib/puppet/parser/functions/epp.rb +3 -3
  101. data/lib/puppet/parser/functions/filter.rb +1 -0
  102. data/lib/puppet/parser/functions/inline_epp.rb +5 -5
  103. data/lib/puppet/pops/evaluator/access_operator.rb +2 -2
  104. data/lib/puppet/pops/evaluator/evaluator_impl.rb +1 -1
  105. data/lib/puppet/pops/evaluator/runtime3_support.rb +1 -1
  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/lookup/invocation.rb +10 -3
  109. data/lib/puppet/pops/model/pn_transformer.rb +5 -9
  110. data/lib/puppet/pops/parser/evaluating_parser.rb +8 -11
  111. data/lib/puppet/pops/serialization/json_path.rb +3 -3
  112. data/lib/puppet/pops/time/timespan.rb +3 -5
  113. data/lib/puppet/pops/types/p_object_type_extension.rb +10 -0
  114. data/lib/puppet/pops/types/string_converter.rb +6 -9
  115. data/lib/puppet/pops/types/type_calculator.rb +30 -10
  116. data/lib/puppet/pops/types/type_formatter.rb +9 -11
  117. data/lib/puppet/pops/types/type_parser.rb +3 -3
  118. data/lib/puppet/pops/validation/checker4_0.rb +1 -1
  119. data/lib/puppet/pops/validation/tasks_checker.rb +5 -1
  120. data/lib/puppet/provider/aix_object.rb +4 -2
  121. data/lib/puppet/provider/group/aix.rb +1 -0
  122. data/lib/puppet/provider/group/groupadd.rb +57 -24
  123. data/lib/puppet/provider/group/windows_adsi.rb +3 -3
  124. data/lib/puppet/provider/package/aix.rb +17 -2
  125. data/lib/puppet/provider/package/apt.rb +78 -4
  126. data/lib/puppet/provider/package/dnfmodule.rb +69 -15
  127. data/lib/puppet/provider/package/dpkg.rb +14 -7
  128. data/lib/puppet/provider/package/fink.rb +20 -3
  129. data/lib/puppet/provider/package/gem.rb +41 -7
  130. data/lib/puppet/provider/package/openbsd.rb +13 -1
  131. data/lib/puppet/provider/package/pacman.rb +2 -5
  132. data/lib/puppet/provider/package/pip.rb +143 -48
  133. data/lib/puppet/provider/package/pip3.rb +0 -2
  134. data/lib/puppet/provider/package/pkg.rb +18 -5
  135. data/lib/puppet/provider/package/pkgdmg.rb +1 -1
  136. data/lib/puppet/provider/package/pkgng.rb +16 -4
  137. data/lib/puppet/provider/package/portage.rb +5 -5
  138. data/lib/puppet/provider/package/puppet_gem.rb +6 -2
  139. data/lib/puppet/provider/package/rpm.rb +6 -213
  140. data/lib/puppet/provider/package/yum.rb +108 -24
  141. data/lib/puppet/provider/package/zypper.rb +59 -1
  142. data/lib/puppet/provider/package_targetable.rb +5 -4
  143. data/lib/puppet/provider/service/systemd.rb +23 -5
  144. data/lib/puppet/provider/user/aix.rb +1 -0
  145. data/lib/puppet/provider/user/directoryservice.rb +30 -5
  146. data/lib/puppet/provider/user/hpux.rb +1 -1
  147. data/lib/puppet/provider/user/useradd.rb +11 -8
  148. data/lib/puppet/reports/http.rb +13 -9
  149. data/lib/puppet/reports/store.rb +1 -1
  150. data/lib/puppet/resource/type_collection.rb +20 -16
  151. data/lib/puppet/runtime.rb +32 -1
  152. data/lib/puppet/settings.rb +4 -0
  153. data/lib/puppet/settings/http_extra_headers_setting.rb +25 -0
  154. data/lib/puppet/ssl.rb +1 -0
  155. data/lib/puppet/ssl/certificate.rb +2 -1
  156. data/lib/puppet/ssl/host.rb +4 -4
  157. data/lib/puppet/ssl/oids.rb +1 -0
  158. data/lib/puppet/ssl/ssl_provider.rb +20 -0
  159. data/lib/puppet/ssl/state_machine.rb +81 -35
  160. data/lib/puppet/ssl/verifier_adapter.rb +9 -1
  161. data/lib/puppet/test/test_helper.rb +7 -1
  162. data/lib/puppet/transaction.rb +33 -11
  163. data/lib/puppet/transaction/report.rb +2 -2
  164. data/lib/puppet/transaction/resource_harness.rb +1 -1
  165. data/lib/puppet/type.rb +7 -2
  166. data/lib/puppet/type/file.rb +13 -0
  167. data/lib/puppet/type/file/data_sync.rb +5 -1
  168. data/lib/puppet/type/file/source.rb +49 -58
  169. data/lib/puppet/type/group.rb +5 -4
  170. data/lib/puppet/type/package.rb +102 -10
  171. data/lib/puppet/type/service.rb +6 -8
  172. data/lib/puppet/type/user.rb +6 -30
  173. data/lib/puppet/util.rb +34 -11
  174. data/lib/puppet/util/at_fork.rb +1 -1
  175. data/lib/puppet/util/autoload.rb +4 -18
  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/logging.rb +30 -18
  179. data/lib/puppet/util/package/version/debian.rb +175 -0
  180. data/lib/puppet/util/package/version/gem.rb +15 -0
  181. data/lib/puppet/util/package/version/pip.rb +167 -0
  182. data/lib/puppet/util/package/version/range.rb +53 -0
  183. data/lib/puppet/util/package/version/range/eq.rb +14 -0
  184. data/lib/puppet/util/package/version/range/gt.rb +14 -0
  185. data/lib/puppet/util/package/version/range/gt_eq.rb +14 -0
  186. data/lib/puppet/util/package/version/range/lt.rb +14 -0
  187. data/lib/puppet/util/package/version/range/lt_eq.rb +14 -0
  188. data/lib/puppet/util/package/version/range/min_max.rb +21 -0
  189. data/lib/puppet/util/package/version/range/simple.rb +11 -0
  190. data/lib/puppet/util/package/version/rpm.rb +73 -0
  191. data/lib/puppet/util/pidlock.rb +36 -10
  192. data/lib/puppet/util/platform.rb +5 -0
  193. data/lib/puppet/util/plist.rb +6 -0
  194. data/lib/puppet/util/rpm_compare.rb +193 -0
  195. data/lib/puppet/util/storage.rb +0 -1
  196. data/lib/puppet/util/windows/adsi.rb +50 -20
  197. data/lib/puppet/util/windows/process.rb +15 -14
  198. data/lib/puppet/util/windows/security.rb +1 -0
  199. data/lib/puppet/util/windows/sid.rb +3 -3
  200. data/lib/puppet/util/yaml.rb +1 -1
  201. data/lib/puppet/version.rb +1 -1
  202. data/lib/puppet/x509/cert_provider.rb +9 -5
  203. data/locales/puppet.pot +640 -521
  204. data/man/man5/puppet.conf.5 +88 -9
  205. data/man/man8/puppet-agent.8 +6 -6
  206. data/man/man8/puppet-apply.8 +1 -1
  207. data/man/man8/puppet-catalog.8 +1 -1
  208. data/man/man8/puppet-config.8 +1 -1
  209. data/man/man8/puppet-describe.8 +1 -1
  210. data/man/man8/puppet-device.8 +2 -2
  211. data/man/man8/puppet-doc.8 +1 -1
  212. data/man/man8/puppet-epp.8 +1 -1
  213. data/man/man8/puppet-facts.8 +1 -1
  214. data/man/man8/puppet-filebucket.8 +17 -2
  215. data/man/man8/puppet-generate.8 +1 -1
  216. data/man/man8/puppet-help.8 +6 -3
  217. data/man/man8/puppet-key.8 +1 -1
  218. data/man/man8/puppet-lookup.8 +1 -1
  219. data/man/man8/puppet-man.8 +1 -1
  220. data/man/man8/puppet-module.8 +4 -1
  221. data/man/man8/puppet-node.8 +1 -1
  222. data/man/man8/puppet-parser.8 +1 -1
  223. data/man/man8/puppet-plugin.8 +1 -1
  224. data/man/man8/puppet-report.8 +1 -1
  225. data/man/man8/puppet-resource.8 +1 -1
  226. data/man/man8/puppet-script.8 +1 -1
  227. data/man/man8/puppet-ssl.8 +2 -2
  228. data/man/man8/puppet-status.8 +1 -1
  229. data/man/man8/puppet.8 +2 -2
  230. data/spec/fixtures/ssl/unknown-127.0.0.1-key.pem +67 -0
  231. data/spec/fixtures/ssl/unknown-127.0.0.1.pem +48 -0
  232. data/spec/fixtures/ssl/unknown-ca-key.pem +67 -0
  233. data/spec/fixtures/ssl/unknown-ca.pem +59 -0
  234. data/spec/fixtures/unit/forge/bacula.json +76 -0
  235. data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-installed.txt → dnf-module-list.txt} +8 -0
  236. data/spec/fixtures/unit/provider/package/pkgng/pkg.version +2 -0
  237. data/spec/fixtures/unit/provider/package/yum/yum-check-update-subscription-manager.txt +9 -0
  238. data/spec/fixtures/unit/provider/package/zypper/zypper-search-uninstalled.out +13 -0
  239. data/spec/fixtures/unit/provider/service/systemd/list_unit_files_services +9 -0
  240. 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
  241. 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
  242. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_update_if_content_differs_on_disk.yml +1 -106
  243. 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
  244. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_no_header_specified.yml +1 -98
  245. 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
  246. 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
  247. data/spec/integration/application/agent_spec.rb +394 -0
  248. data/spec/integration/application/apply_spec.rb +132 -3
  249. data/spec/integration/application/filebucket_spec.rb +190 -0
  250. data/spec/integration/application/plugin_spec.rb +73 -0
  251. data/spec/integration/configurer_spec.rb +26 -7
  252. data/spec/integration/http/client_spec.rb +154 -0
  253. data/spec/integration/indirector/facts/facter_spec.rb +4 -0
  254. data/spec/integration/indirector/report/yaml.rb +83 -0
  255. data/spec/integration/module_tool/forge_spec.rb +51 -0
  256. data/spec/integration/network/http_pool_spec.rb +76 -20
  257. data/spec/integration/node/environment_spec.rb +15 -0
  258. data/spec/integration/util/windows/adsi_spec.rb +6 -1
  259. data/spec/lib/puppet/test_ca.rb +2 -2
  260. data/spec/lib/puppet_spec/https.rb +20 -9
  261. data/spec/lib/puppet_spec/puppetserver.rb +119 -0
  262. data/spec/shared_contexts/https.rb +29 -0
  263. data/spec/spec_helper.rb +6 -2
  264. data/spec/unit/agent_spec.rb +80 -26
  265. data/spec/unit/application/agent_spec.rb +9 -5
  266. data/spec/unit/application/apply_spec.rb +2 -12
  267. data/spec/unit/application/describe_spec.rb +88 -50
  268. data/spec/unit/application/device_spec.rb +2 -2
  269. data/spec/unit/application/filebucket_spec.rb +22 -2
  270. data/spec/unit/application/resource_spec.rb +2 -2
  271. data/spec/unit/concurrent/lock_spec.rb +29 -0
  272. data/spec/unit/configurer/fact_handler_spec.rb +0 -4
  273. data/spec/unit/configurer/plugin_handler_spec.rb +36 -19
  274. data/spec/unit/configurer_spec.rb +400 -406
  275. data/spec/unit/context/trusted_information_spec.rb +17 -0
  276. data/spec/unit/daemon_spec.rb +5 -64
  277. data/spec/unit/defaults_spec.rb +38 -4
  278. data/spec/unit/environments_spec.rb +65 -28
  279. data/spec/unit/face/facts_spec.rb +24 -20
  280. data/spec/unit/face/module/search_spec.rb +17 -0
  281. data/spec/unit/face/plugin_spec.rb +12 -10
  282. data/spec/unit/file_system/uniquefile_spec.rb +11 -0
  283. data/spec/unit/file_system_spec.rb +26 -2
  284. data/spec/unit/forge/errors_spec.rb +1 -1
  285. data/spec/unit/forge/forge_spec.rb +12 -54
  286. data/spec/unit/forge/module_release_spec.rb +19 -6
  287. data/spec/unit/forge/repository_spec.rb +63 -157
  288. data/spec/unit/forge_spec.rb +46 -116
  289. data/spec/unit/functions/find_template_spec.rb +69 -0
  290. data/spec/unit/functions/lookup_spec.rb +13 -0
  291. data/spec/unit/http/client_spec.rb +395 -27
  292. data/spec/unit/http/external_client_spec.rb +201 -0
  293. data/spec/unit/http/resolver_spec.rb +81 -12
  294. data/spec/unit/http/response_spec.rb +69 -0
  295. data/spec/unit/http/service/ca_spec.rb +100 -7
  296. data/spec/unit/http/service/compiler_spec.rb +627 -0
  297. data/spec/unit/http/service/file_server_spec.rb +308 -0
  298. data/spec/unit/http/service/report_spec.rb +118 -0
  299. data/spec/unit/http/service_spec.rb +117 -4
  300. data/spec/unit/http/session_spec.rb +237 -19
  301. data/spec/unit/indirector/catalog/compiler_spec.rb +47 -29
  302. data/spec/unit/indirector/catalog/rest_spec.rb +59 -2
  303. data/spec/unit/indirector/facts/rest_spec.rb +79 -24
  304. data/spec/unit/indirector/file_bucket_file/rest_spec.rb +82 -2
  305. data/spec/unit/indirector/file_content/rest_spec.rb +53 -2
  306. data/spec/unit/indirector/file_metadata/http_spec.rb +167 -0
  307. data/spec/unit/indirector/file_metadata/rest_spec.rb +110 -2
  308. data/spec/unit/indirector/node/rest_spec.rb +57 -2
  309. data/spec/unit/indirector/report/rest_spec.rb +58 -51
  310. data/spec/unit/indirector/resource/ral_spec.rb +7 -8
  311. data/spec/unit/indirector/rest_spec.rb +13 -0
  312. data/spec/unit/indirector/status/rest_spec.rb +43 -2
  313. data/spec/unit/network/http/connection_spec.rb +549 -176
  314. data/spec/unit/network/http/nocache_pool_spec.rb +25 -3
  315. data/spec/unit/network/http/pool_spec.rb +89 -11
  316. data/spec/unit/network/http_pool_spec.rb +63 -57
  317. data/spec/unit/network/http_spec.rb +1 -1
  318. data/spec/unit/node/environment_spec.rb +16 -0
  319. data/spec/unit/node/facts_spec.rb +2 -1
  320. data/spec/unit/node_spec.rb +7 -4
  321. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +8 -3
  322. data/spec/unit/pops/serialization/to_from_hr_spec.rb +6 -1
  323. data/spec/unit/pops/validator/validator_spec.rb +7 -2
  324. data/spec/unit/provider/aix_object_spec.rb +16 -2
  325. data/spec/unit/provider/group/groupadd_spec.rb +181 -56
  326. data/spec/unit/provider/group/windows_adsi_spec.rb +43 -10
  327. data/spec/unit/provider/package/aix_spec.rb +29 -0
  328. data/spec/unit/provider/package/apt_spec.rb +43 -2
  329. data/spec/unit/provider/package/aptitude_spec.rb +1 -0
  330. data/spec/unit/provider/package/dnfmodule_spec.rb +76 -15
  331. data/spec/unit/provider/package/dpkg_spec.rb +28 -6
  332. data/spec/unit/provider/package/gem_spec.rb +40 -0
  333. data/spec/unit/provider/package/openbsd_spec.rb +17 -0
  334. data/spec/unit/provider/package/pacman_spec.rb +6 -21
  335. data/spec/unit/provider/package/pip_spec.rb +68 -19
  336. data/spec/unit/provider/package/pkg_spec.rb +15 -1
  337. data/spec/unit/provider/package/pkgdmg_spec.rb +1 -1
  338. data/spec/unit/provider/package/pkgng_spec.rb +38 -0
  339. data/spec/unit/provider/package/portage_spec.rb +9 -4
  340. data/spec/unit/provider/package/puppet_gem_spec.rb +8 -0
  341. data/spec/unit/provider/package/rpm_spec.rb +0 -212
  342. data/spec/unit/provider/package/yum_spec.rb +292 -0
  343. data/spec/unit/provider/package/zypper_spec.rb +84 -0
  344. data/spec/unit/provider/package_targetable_spec.rb +60 -0
  345. data/spec/unit/provider/service/init_spec.rb +1 -0
  346. data/spec/unit/provider/service/openbsd_spec.rb +9 -0
  347. data/spec/unit/provider/service/openwrt_spec.rb +1 -0
  348. data/spec/unit/provider/service/redhat_spec.rb +9 -0
  349. data/spec/unit/provider/service/systemd_spec.rb +92 -12
  350. data/spec/unit/provider/user/directoryservice_spec.rb +41 -0
  351. data/spec/unit/provider/user/hpux_spec.rb +2 -2
  352. data/spec/unit/provider/user/useradd_spec.rb +21 -8
  353. data/spec/unit/provider/user/windows_adsi_spec.rb +3 -3
  354. data/spec/unit/puppet_pal_2pec.rb +0 -26
  355. data/spec/unit/puppet_pal_catalog_spec.rb +46 -0
  356. data/spec/unit/puppet_spec.rb +47 -0
  357. data/spec/unit/reports/http_spec.rb +70 -52
  358. data/spec/unit/settings/autosign_setting_spec.rb +1 -1
  359. data/spec/unit/settings/http_extra_headers_spec.rb +64 -0
  360. data/spec/unit/ssl/certificate_spec.rb +7 -0
  361. data/spec/unit/ssl/host_spec.rb +4 -2
  362. data/spec/unit/ssl/oids_spec.rb +1 -0
  363. data/spec/unit/ssl/ssl_provider_spec.rb +71 -0
  364. data/spec/unit/ssl/state_machine_spec.rb +99 -13
  365. data/spec/unit/transaction/persistence_spec.rb +1 -10
  366. data/spec/unit/transaction/report_spec.rb +4 -0
  367. data/spec/unit/transaction_spec.rb +45 -1
  368. data/spec/unit/type/file/content_spec.rb +9 -3
  369. data/spec/unit/type/file/ensure_spec.rb +1 -2
  370. data/spec/unit/type/file/source_spec.rb +86 -35
  371. data/spec/unit/type/package_spec.rb +8 -0
  372. data/spec/unit/type/service_spec.rb +9 -8
  373. data/spec/unit/type/user_spec.rb +1 -2
  374. data/spec/unit/util/at_fork_spec.rb +3 -2
  375. data/spec/unit/util/autoload_spec.rb +2 -1
  376. data/spec/unit/util/log/destinations_spec.rb +1 -29
  377. data/spec/unit/util/log_spec.rb +0 -138
  378. data/spec/unit/util/logging_spec.rb +200 -0
  379. data/spec/unit/util/package/version/debian_spec.rb +83 -0
  380. data/spec/unit/util/package/version/pip_spec.rb +464 -0
  381. data/spec/unit/util/package/version/range_spec.rb +175 -0
  382. data/spec/unit/util/package/version/rpm_spec.rb +121 -0
  383. data/spec/unit/util/pidlock_spec.rb +112 -42
  384. data/spec/unit/util/plist_spec.rb +20 -0
  385. data/spec/unit/util/rpm_compare_spec.rb +196 -0
  386. data/spec/unit/util/storage_spec.rb +1 -8
  387. data/spec/unit/util/windows/adsi_spec.rb +55 -4
  388. data/spec/unit/util/windows/sid_spec.rb +2 -2
  389. data/spec/unit/x509/cert_provider_spec.rb +24 -4
  390. data/tasks/generate_cert_fixtures.rake +15 -1
  391. data/tasks/manpages.rake +6 -35
  392. metadata +92 -12
  393. data/COMMITTERS.md +0 -244
  394. data/spec/integration/faces/plugin_spec.rb +0 -61
  395. data/spec/lib/puppet_spec/validators.rb +0 -37
@@ -1,88 +1,13 @@
1
1
  require 'spec_helper'
2
- require 'puppet/forge'
2
+ require 'spec_helper'
3
3
  require 'net/http'
4
+ require 'puppet/forge'
4
5
  require 'puppet/module_tool'
5
6
 
6
7
  describe Puppet::Forge do
8
+
7
9
  let(:http_response) do
8
- <<-EOF
9
- {
10
- "pagination": {
11
- "limit": 1,
12
- "offset": 0,
13
- "first": "/v3/modules?limit=1&offset=0",
14
- "previous": null,
15
- "current": "/v3/modules?limit=1&offset=0",
16
- "next": null,
17
- "total": 1832
18
- },
19
- "results": [
20
- {
21
- "uri": "/v3/modules/puppetlabs-bacula",
22
- "name": "bacula",
23
- "downloads": 640274,
24
- "created_at": "2011-05-24 18:34:58 -0700",
25
- "updated_at": "2013-12-03 15:24:20 -0800",
26
- "owner": {
27
- "uri": "/v3/users/puppetlabs",
28
- "username": "puppetlabs",
29
- "gravatar_id": "fdd009b7c1ec96e088b389f773e87aec"
30
- },
31
- "current_release": {
32
- "uri": "/v3/releases/puppetlabs-bacula-0.0.2",
33
- "module": {
34
- "uri": "/v3/modules/puppetlabs-bacula",
35
- "name": "bacula",
36
- "owner": {
37
- "uri": "/v3/users/puppetlabs",
38
- "username": "puppetlabs",
39
- "gravatar_id": "fdd009b7c1ec96e088b389f773e87aec"
40
- }
41
- },
42
- "version": "0.0.2",
43
- "metadata": {
44
- "types": [],
45
- "license": "Apache 2.0",
46
- "checksums": { },
47
- "version": "0.0.2",
48
- "source": "git://github.com/puppetlabs/puppetlabs-bacula.git",
49
- "project_page": "https://github.com/puppetlabs/puppetlabs-bacula",
50
- "summary": "bacula",
51
- "dependencies": [ ],
52
- "author": "puppetlabs",
53
- "name": "puppetlabs-bacula"
54
- },
55
- "tags": [
56
- "backup",
57
- "bacula"
58
- ],
59
- "file_uri": "/v3/files/puppetlabs-bacula-0.0.2.tar.gz",
60
- "file_size": 67586,
61
- "file_md5": "bbf919d7ee9d278d2facf39c25578bf8",
62
- "downloads": 565041,
63
- "readme": "",
64
- "changelog": "",
65
- "license": "",
66
- "created_at": "2013-05-13 08:31:19 -0700",
67
- "updated_at": "2013-05-13 08:31:19 -0700",
68
- "deleted_at": null
69
- },
70
- "releases": [
71
- {
72
- "uri": "/v3/releases/puppetlabs-bacula-0.0.2",
73
- "version": "0.0.2"
74
- },
75
- {
76
- "uri": "/v3/releases/puppetlabs-bacula-0.0.1",
77
- "version": "0.0.1"
78
- }
79
- ],
80
- "homepage_url": "https://github.com/puppetlabs/puppetlabs-bacula",
81
- "issues_url": "https://projects.puppetlabs.com/projects/bacula/issues"
82
- }
83
- ]
84
- }
85
- EOF
10
+ File.read(my_fixture('bacula.json'))
86
11
  end
87
12
 
88
13
  let(:search_results) do
@@ -99,76 +24,84 @@ describe Puppet::Forge do
99
24
  end
100
25
  end
101
26
 
102
- let(:forge) { Puppet::Forge.new }
103
-
104
- def repository_responds_with(response, &block)
105
- if block_given?
106
- allow_any_instance_of(Puppet::Forge::Repository).to receive(:make_http_request, &block).and_return(response)
107
- else
108
- allow_any_instance_of(Puppet::Forge::Repository).to receive(:make_http_request).and_return(response)
109
- end
27
+ let(:release_response) do
28
+ releases = JSON.parse(http_response)
29
+ releases['results'] = []
30
+ JSON.dump(releases)
110
31
  end
111
32
 
33
+ let(:forge) { Puppet::Forge.new }
34
+
112
35
  it "returns a list of matches from the forge when there are matches for the search term" do
113
- repository_responds_with(double(:body => http_response, :code => '200'))
36
+ stub_request(:get, "https://forgeapi.puppet.com/v3/modules?query=bacula").to_return(status: 200, body: http_response)
37
+
114
38
  expect(forge.search('bacula')).to eq(search_results)
115
39
  end
116
40
 
117
41
  context "when module_groups are defined" do
118
- let(:release_response) do
119
- releases = JSON.parse(http_response)
120
- releases['results'] = []
121
- JSON.dump(releases)
122
- end
123
-
124
42
  before :each do
125
- repository_responds_with(double(:body => release_response, :code => '200')) {|uri| uri =~ /module_groups=foo/}
126
43
  Puppet[:module_groups] = "foo"
127
44
  end
128
45
 
129
46
  it "passes module_groups with search" do
47
+ stub_request(:get, "https://forgeapi.puppet.com/v3/modules")
48
+ .with(query: hash_including("module_groups" => "foo"))
49
+ .to_return(status: 200, body: release_response)
50
+
130
51
  forge.search('bacula')
131
52
  end
132
53
 
133
54
  it "passes module_groups with fetch" do
55
+ stub_request(:get, "https://forgeapi.puppet.com/v3/releases")
56
+ .with(query: hash_including("module_groups" => "foo"))
57
+ .to_return(status: 200, body: release_response)
58
+
134
59
  forge.fetch('puppetlabs-bacula')
135
60
  end
136
61
  end
137
62
 
138
63
  # See PUP-8008
139
64
  context "when multiple module_groups are defined" do
140
- let(:release_response) do
141
- releases = JSON.parse(http_response)
142
- releases['results'] = []
143
- JSON.dump(releases)
144
- end
145
-
146
65
  context "with space seperator" do
147
66
  before :each do
148
- repository_responds_with(double(:body => release_response, :code => '200')) {|uri| uri =~ /module_groups=foo bar/}
149
67
  Puppet[:module_groups] = "foo bar"
150
68
  end
151
69
 
152
70
  it "passes module_groups with search" do
71
+ stub_request(:get, %r{forgeapi.puppet.com/v3/modules}).with do |req|
72
+ expect(req.uri.query).to match(/module_groups=foo%20bar/)
73
+ end.to_return(status: 200, body: release_response)
74
+
153
75
  forge.search('bacula')
154
76
  end
155
77
 
156
78
  it "passes module_groups with fetch" do
79
+ stub_request(:get, %r{forgeapi.puppet.com/v3/releases}).with do |req|
80
+ expect(req.uri.query).to match(/module_groups=foo%20bar/)
81
+ end.to_return(status: 200, body: release_response)
82
+
157
83
  forge.fetch('puppetlabs-bacula')
158
84
  end
159
85
  end
160
86
 
161
87
  context "with plus seperator" do
162
88
  before :each do
163
- repository_responds_with(double(:body => release_response, :code => '200')) {|uri| uri =~ /module_groups=foo bar/}
164
89
  Puppet[:module_groups] = "foo+bar"
165
90
  end
166
91
 
167
92
  it "passes module_groups with search" do
93
+ stub_request(:get, %r{forgeapi.puppet.com/v3/modules}).with do |req|
94
+ expect(req.uri.query).to match(/module_groups=foo%20bar/)
95
+ end.to_return(status: 200, body: release_response)
96
+
168
97
  forge.search('bacula')
169
98
  end
170
99
 
171
100
  it "passes module_groups with fetch" do
101
+ stub_request(:get, %r{forgeapi.puppet.com/v3/releases}).with do |req|
102
+ expect(req.uri.query).to match(/module_groups=foo%20bar/)
103
+ end.to_return(status: 200, body: release_response)
104
+
172
105
  forge.fetch('puppetlabs-bacula')
173
106
  end
174
107
  end
@@ -176,10 +109,10 @@ describe Puppet::Forge do
176
109
  # See PUP-8008
177
110
  context "when there are multiple pages of results" do
178
111
  before(:each) do
179
- expect_any_instance_of(Puppet::Forge::Repository).to receive(:make_http_request) {|_, uri| uri =~ /module_groups=foo bar/ && uri !=~ /offset/ }.and_return(double(:body => first_page, :code => '200'))
180
-
181
- # Request for second page should not have module_groups already encoded
182
- expect_any_instance_of(Puppet::Forge::Repository).to receive(:make_http_request) {|_, uri| uri =~ /module_groups=foo bar/ && uri =~ /offset=1/ }.and_return(double(:body => last_page, :code => '200'))
112
+ stub_request(:get, %r{forgeapi.puppet.com}).with do |req|
113
+ expect(req.uri.query).to match(/module_groups=foo%20bar/)
114
+ end.to_return(status: 200, body: first_page)
115
+ .to_return(status: 200, body: last_page)
183
116
  end
184
117
 
185
118
  context "with space seperator" do
@@ -242,7 +175,7 @@ describe Puppet::Forge do
242
175
 
243
176
  context "when the connection to the forge fails" do
244
177
  before :each do
245
- repository_responds_with(double(:body => '{}', :code => '404', :message => "not found"))
178
+ stub_request(:get, /forgeapi.puppet.com/).to_return(status: [404, 'not found'])
246
179
  end
247
180
 
248
181
  it "raises an error for search" do
@@ -255,25 +188,22 @@ describe Puppet::Forge do
255
188
  end
256
189
 
257
190
  context "when the API responds with an error" do
258
- before :each do
259
- repository_responds_with(double(:body => '{"error":"invalid module"}', :code => '410', :message => "Gone"))
260
- end
261
-
262
191
  it "raises an error for fetch" do
192
+ stub_request(:get, /forgeapi.puppet.com/).to_return(status: [410, 'Gone'], body: '{"error":"invalid module"}')
193
+
263
194
  expect { forge.fetch('puppetlabs/bacula') }.to raise_error Puppet::Forge::Errors::ResponseError, "Request to Puppet Forge failed. Detail: 410 Gone."
264
195
  end
265
196
  end
266
197
 
267
198
  context "when the forge returns a module with unparseable dependencies" do
268
- before :each do
199
+ it "ignores modules with unparseable dependencies" do
269
200
  response = JSON.parse(http_response)
270
201
  release = response['results'][0]['current_release']
271
202
  release['metadata']['dependencies'] = [{'name' => 'broken-garbage >= 1.0.0', 'version_requirement' => 'banana'}]
272
203
  response['results'] = [release]
273
- repository_responds_with(double(:body => JSON.dump(response), :code => '200'))
274
- end
275
204
 
276
- it "ignores modules with unparseable dependencies" do
205
+ stub_request(:get, /forgeapi.puppet.com/).to_return(status: 200, body: JSON.dump(response))
206
+
277
207
  expect(forge.fetch('puppetlabs/bacula')).to be_empty
278
208
  end
279
209
  end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+ require 'puppet_spec/compiler'
3
+ require 'matchers/resource'
4
+ require 'puppet_spec/files'
5
+
6
+ describe 'the find_template function' do
7
+ include PuppetSpec::Compiler
8
+ include Matchers::Resource
9
+ include PuppetSpec::Files
10
+
11
+ def with_file_content(content)
12
+ path = tmpfile('find-file-function')
13
+ file = File.new(path, 'wb')
14
+ file.sync = true
15
+ file.print content
16
+ yield path
17
+ end
18
+
19
+ it 'finds an existing absolute file when given arguments individually' do
20
+ with_file_content('one') do |one|
21
+ with_file_content('two') do |two|
22
+ expect(compile_to_catalog("notify { find_template('#{one}', '#{two}'):}")).to have_resource("Notify[#{one}]")
23
+ end
24
+ end
25
+ end
26
+
27
+ it 'skips non existing files' do
28
+ with_file_content('one') do |one|
29
+ with_file_content('two') do |two|
30
+ expect(compile_to_catalog("notify { find_template('#{one}/nope', '#{two}'):}")).to have_resource("Notify[#{two}]")
31
+ end
32
+ end
33
+ end
34
+
35
+ it 'accepts arguments given as an array' do
36
+ with_file_content('one') do |one|
37
+ with_file_content('two') do |two|
38
+ expect(compile_to_catalog("notify { find_template(['#{one}', '#{two}']):}")).to have_resource("Notify[#{one}]")
39
+ end
40
+ end
41
+ end
42
+
43
+ it 'finds an existing file in a module' do
44
+ with_file_content('file content') do |name|
45
+ mod = double('module')
46
+ allow(mod).to receive(:template).with('myfile').and_return(name)
47
+ Puppet[:code] = "notify { find_template('mymod/myfile'):}"
48
+ node = Puppet::Node.new('localhost')
49
+ compiler = Puppet::Parser::Compiler.new(node)
50
+ allow(compiler.environment).to receive(:module).with('mymod').and_return(mod)
51
+
52
+ expect(compiler.compile().filter { |r| r.virtual? }).to have_resource("Notify[#{name}]")
53
+ end
54
+ end
55
+
56
+ it 'returns undef when none of the paths were found' do
57
+ mod = double('module')
58
+ allow(mod).to receive(:template).with('myfile').and_return(nil)
59
+ Puppet[:code] = "notify { String(type(find_template('mymod/myfile', 'nomod/nofile'))):}"
60
+ node = Puppet::Node.new('localhost')
61
+ compiler = Puppet::Parser::Compiler.new(node)
62
+ # For a module that does not have the file
63
+ allow(compiler.environment).to receive(:module).with('mymod').and_return(mod)
64
+ # For a module that does not exist
65
+ allow(compiler.environment).to receive(:module).with('nomod').and_return(nil)
66
+
67
+ expect(compiler.compile().filter { |r| r.virtual? }).to have_resource("Notify[Undef]")
68
+ end
69
+ end
@@ -3082,6 +3082,19 @@ describe "The lookup function" do
3082
3082
 
3083
3083
  let(:env_data) { data_files }
3084
3084
 
3085
+ context 'with unencryptable eyaml' do
3086
+ let(:data_files) do
3087
+ {
3088
+ 'common.eyaml' => <<-YAML.unindent
3089
+ key_with_invalid_eyaml: ENC[PKCS7,INVALID]
3090
+ YAML
3091
+ }
3092
+ end
3093
+
3094
+ it 'fails and reports error with ENC value, key being looked up and filename' do
3095
+ expect { lookup('key_with_invalid_eyaml') }.to raise_error(Puppet::DataBinding::LookupError, /hiera-eyaml backend error decrypting ENC\[PKCS7,INVALID\] when looking up key_with_invalid_eyaml in .*common\.eyaml\. Error was/)
3096
+ end
3097
+ end
3085
3098
  context 'and a module using eyaml with different options' do
3086
3099
 
3087
3100
  let(:private_module_key) do
@@ -4,7 +4,9 @@ require 'puppet/http'
4
4
 
5
5
  describe Puppet::HTTP::Client do
6
6
  let(:uri) { URI.parse('https://www.example.com') }
7
- let(:client) { described_class.new }
7
+ let(:puppet_context) { Puppet::SSL::SSLContext.new }
8
+ let(:system_context) { Puppet::SSL::SSLContext.new }
9
+ let(:client) { described_class.new(ssl_context: puppet_context, system_ssl_context: system_context) }
8
10
  let(:credentials) { ['user', 'pass'] }
9
11
 
10
12
  it 'creates unique sessions' do
@@ -35,7 +37,55 @@ describe Puppet::HTTP::Client do
35
37
 
36
38
  expect {
37
39
  client.connect(uri)
38
- }.to raise_error(Puppet::HTTP::ConnectionError, %r{Failed to connect to https://www.example.com:})
40
+ }.to raise_error(Puppet::HTTP::ConnectionError, %r{^Request to https://www.example.com failed after .* seconds: (Connection refused|No connection could be made because the target machine actively refused it)})
41
+ end
42
+
43
+ it 'raises ConnectionError if the connect times out' do
44
+ allow_any_instance_of(Net::HTTP).to receive(:start).and_raise(Net::OpenTimeout)
45
+
46
+ expect {
47
+ client.connect(uri)
48
+ }.to raise_error(Puppet::HTTP::ConnectionError, %r{^Request to https://www.example.com timed out connect operation after .* seconds})
49
+ end
50
+
51
+ it 'connects using the default ssl context' do
52
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
53
+ expect(verifier.ssl_context).to equal(puppet_context)
54
+ end
55
+
56
+ client.connect(uri)
57
+ end
58
+
59
+ it 'connects using a specified ssl context' do
60
+ other_context = Puppet::SSL::SSLContext.new
61
+
62
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
63
+ expect(verifier.ssl_context).to equal(other_context)
64
+ end
65
+
66
+ client.connect(uri, options: {ssl_context: other_context})
67
+ end
68
+
69
+ it 'connects using the system store' do
70
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
71
+ expect(verifier.ssl_context).to equal(system_context)
72
+ end
73
+
74
+ client.connect(uri, options: {include_system_store: true})
75
+ end
76
+
77
+ it 'does not create a verifier for HTTP connections' do
78
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
79
+ expect(verifier).to be_nil
80
+ end
81
+
82
+ client.connect(URI.parse('http://www.example.com'))
83
+ end
84
+
85
+ it 'raises an HTTPError if both are specified' do
86
+ expect {
87
+ client.connect(uri, options: {ssl_context: puppet_context, include_system_store: true})
88
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
39
89
  end
40
90
  end
41
91
 
@@ -53,31 +103,32 @@ describe Puppet::HTTP::Client do
53
103
  end
54
104
 
55
105
  it 'raises HTTPError if connection is interrupted while reading' do
56
- expect_http_error(EOFError, %r{Request to https://www.example.com interrupted after .* seconds})
106
+ expect_http_error(EOFError, %r{^Request to https://www.example.com interrupted after .* seconds})
57
107
  end
58
108
 
59
109
  it 'raises HTTPError if connection times out' do
60
- expect_http_error(Net::ReadTimeout, %r{Request to https://www.example.com timed out after .* seconds})
110
+ expect_http_error(Net::ReadTimeout, %r{^Request to https://www.example.com timed out read operation after .* seconds})
61
111
  end
62
112
 
63
113
  it 'raises HTTPError if connection fails' do
64
- expect_http_error(ArgumentError, %r{Request to https://www.example.com failed after .* seconds})
114
+ expect_http_error(ArgumentError, %r{^Request to https://www.example.com failed after .* seconds})
65
115
  end
66
116
  end
67
117
 
68
118
  context "when closing" do
69
119
  it "closes all connections in the pool" do
70
- pool = double('pool')
71
- expect(pool).to receive(:close)
120
+ expect(client.pool).to receive(:close)
72
121
 
73
- client = described_class.new(pool: pool)
74
122
  client.close
75
123
  end
76
124
  end
77
125
 
78
126
  context "for GET requests" do
79
127
  it "includes default HTTP headers" do
80
- stub_request(:get, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./})
128
+ stub_request(:get, uri).with do |request|
129
+ expect(request.headers).to include({'X-Puppet-Version' => /./, 'User-Agent' => /./})
130
+ expect(request.headers).to_not include('X-Puppet-Profiling')
131
+ end
81
132
 
82
133
  client.get(uri)
83
134
  end
@@ -88,6 +139,12 @@ describe Puppet::HTTP::Client do
88
139
  client.get(uri, params: {:foo => "bar=baz"})
89
140
  end
90
141
 
142
+ it "fails if a user passes in an invalid param type" do
143
+ environment = Puppet::Node::Environment.create(:testing, [])
144
+
145
+ expect{client.get(uri, params: {environment: environment})}.to raise_error(Puppet::HTTP::SerializationError, /HTTP REST queries cannot handle values of type/)
146
+ end
147
+
91
148
  it "merges custom headers with default ones" do
92
149
  stub_request(:get, uri).with(headers: { 'X-Foo' => 'Bar', 'X-Puppet-Version' => /./, 'User-Agent' => /./ })
93
150
 
@@ -121,31 +178,113 @@ describe Puppet::HTTP::Client do
121
178
 
122
179
  expect(io.string).to eq("abc")
123
180
  end
181
+
182
+ context 'when connecting' do
183
+ it 'uses a specified ssl context' do
184
+ stub_request(:get, uri).to_return(body: "abc")
185
+
186
+ other_context = Puppet::SSL::SSLContext.new
187
+
188
+ client.get(uri, options: {ssl_context: other_context})
189
+ end
190
+
191
+ it 'uses the system store' do
192
+ stub_request(:get, uri).to_return(body: "abc")
193
+
194
+ client.get(uri, options: {include_system_store: true})
195
+ end
196
+
197
+ it 'raises an HTTPError if both are specified' do
198
+ expect {
199
+ client.get(uri, options: {ssl_context: puppet_context, include_system_store: true})
200
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
201
+ end
202
+ end
203
+ end
204
+
205
+ context "for HEAD requests" do
206
+ it "includes default HTTP headers" do
207
+ stub_request(:head, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./})
208
+
209
+ client.head(uri)
210
+ end
211
+
212
+ it "stringifies keys and encodes values in the query" do
213
+ stub_request(:head, uri).with(query: "foo=bar%3Dbaz")
214
+
215
+ client.head(uri, params: {:foo => "bar=baz"})
216
+ end
217
+
218
+ it "merges custom headers with default ones" do
219
+ stub_request(:head, uri).with(headers: { 'X-Foo' => 'Bar', 'X-Puppet-Version' => /./, 'User-Agent' => /./ })
220
+
221
+ client.head(uri, headers: {'X-Foo' => 'Bar'})
222
+ end
223
+
224
+ it "returns the response" do
225
+ stub_request(:head, uri)
226
+
227
+ response = client.head(uri)
228
+ expect(response).to be_an_instance_of(Puppet::HTTP::Response)
229
+ expect(response).to be_success
230
+ expect(response.code).to eq(200)
231
+ end
232
+
233
+ it "returns the entire response body" do
234
+ stub_request(:head, uri).to_return(body: "abc")
235
+
236
+ expect(client.head(uri).body).to eq("abc")
237
+ end
238
+
239
+ context 'when connecting' do
240
+ it 'uses a specified ssl context' do
241
+ stub_request(:head, uri)
242
+
243
+ other_context = Puppet::SSL::SSLContext.new
244
+
245
+ client.head(uri, options: {ssl_context: other_context})
246
+ end
247
+
248
+ it 'uses the system store' do
249
+ stub_request(:head, uri)
250
+
251
+ client.head(uri, options: {include_system_store: true})
252
+ end
253
+
254
+ it 'raises an HTTPError if both are specified' do
255
+ expect {
256
+ client.head(uri, options: {ssl_context: puppet_context, include_system_store: true})
257
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
258
+ end
259
+ end
124
260
  end
125
261
 
126
262
  context "for PUT requests" do
127
263
  it "includes default HTTP headers" do
128
- stub_request(:put, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./})
264
+ stub_request(:put, uri).with do |request|
265
+ expect(request.headers).to include({'X-Puppet-Version' => /./, 'User-Agent' => /./})
266
+ expect(request.headers).to_not include('X-Puppet-Profiling')
267
+ end
129
268
 
130
- client.put(uri, content_type: 'text/plain', body: "")
269
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'})
131
270
  end
132
271
 
133
272
  it "stringifies keys and encodes values in the query" do
134
273
  stub_request(:put, "https://www.example.com").with(query: "foo=bar%3Dbaz")
135
274
 
136
- client.put(uri, params: {:foo => "bar=baz"}, content_type: 'text/plain', body: "")
275
+ client.put(uri, "", params: {:foo => "bar=baz"}, headers: {'Content-Type' => 'text/plain'})
137
276
  end
138
277
 
139
278
  it "includes custom headers" do
140
279
  stub_request(:put, "https://www.example.com").with(headers: { 'X-Foo' => 'Bar' })
141
280
 
142
- client.put(uri, headers: {'X-Foo' => 'Bar'}, content_type: 'text/plain', body: "")
281
+ client.put(uri, "", headers: {'X-Foo' => 'Bar', 'Content-Type' => 'text/plain'})
143
282
  end
144
283
 
145
284
  it "returns the response" do
146
285
  stub_request(:put, uri)
147
286
 
148
- response = client.put(uri, content_type: 'text/plain', body: "")
287
+ response = client.put(uri, "", headers: {'Content-Type' => 'text/plain'})
149
288
  expect(response).to be_an_instance_of(Puppet::HTTP::Response)
150
289
  expect(response).to be_success
151
290
  expect(response.code).to eq(200)
@@ -154,7 +293,180 @@ describe Puppet::HTTP::Client do
154
293
  it "sets content-length and content-type for the body" do
155
294
  stub_request(:put, uri).with(headers: {"Content-Length" => "5", "Content-Type" => "text/plain"})
156
295
 
157
- client.put(uri, content_type: 'text/plain', body: "hello")
296
+ client.put(uri, "hello", headers: {'Content-Type' => 'text/plain'})
297
+ end
298
+
299
+ it 'raises an ArgumentError if `body` is missing' do
300
+ expect {
301
+ client.put(uri, nil, headers: {'Content-Type' => 'text/plain'})
302
+ }.to raise_error(ArgumentError, /'put' requires a string 'body' argument/)
303
+ end
304
+
305
+ it 'raises an ArgumentError if `content_type` is missing from the headers hash' do
306
+ expect {
307
+ client.put(uri, '')
308
+ }.to raise_error(ArgumentError, /'put' requires a 'content-type' header/)
309
+ end
310
+
311
+ context 'when connecting' do
312
+ it 'uses a specified ssl context' do
313
+ stub_request(:put, uri)
314
+
315
+ other_context = Puppet::SSL::SSLContext.new
316
+
317
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: other_context})
318
+ end
319
+
320
+ it 'uses the system store' do
321
+ stub_request(:put, uri)
322
+
323
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {include_system_store: true})
324
+ end
325
+
326
+ it 'raises an HTTPError if both are specified' do
327
+ expect {
328
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: puppet_context, include_system_store: true})
329
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
330
+ end
331
+ end
332
+ end
333
+
334
+ context "for POST requests" do
335
+ it "includes default HTTP headers" do
336
+ stub_request(:post, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./})
337
+
338
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'})
339
+ end
340
+
341
+ it "stringifies keys and encodes values in the query" do
342
+ stub_request(:post, "https://www.example.com").with(query: "foo=bar%3Dbaz")
343
+
344
+ client.post(uri, "", params: {:foo => "bar=baz"}, headers: {'Content-Type' => 'text/plain'})
345
+ end
346
+
347
+ it "includes custom headers" do
348
+ stub_request(:post, "https://www.example.com").with(headers: { 'X-Foo' => 'Bar' })
349
+
350
+ client.post(uri, "", headers: {'X-Foo' => 'Bar', 'Content-Type' => 'text/plain'})
351
+ end
352
+
353
+ it "returns the response" do
354
+ stub_request(:post, uri)
355
+
356
+ response = client.post(uri, "", headers: {'Content-Type' => 'text/plain'})
357
+ expect(response).to be_an_instance_of(Puppet::HTTP::Response)
358
+ expect(response).to be_success
359
+ expect(response.code).to eq(200)
360
+ end
361
+
362
+ it "sets content-length and content-type for the body" do
363
+ stub_request(:post, uri).with(headers: {"Content-Length" => "5", "Content-Type" => "text/plain"})
364
+
365
+ client.post(uri, "hello", headers: {'Content-Type' => 'text/plain'})
366
+ end
367
+
368
+ it "streams the response body when a block is given" do
369
+ stub_request(:post, uri).to_return(body: "abc")
370
+
371
+ io = StringIO.new
372
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}) do |response|
373
+ response.read_body do |data|
374
+ io.write(data)
375
+ end
376
+ end
377
+
378
+ expect(io.string).to eq("abc")
379
+ end
380
+
381
+ it 'raises an ArgumentError if `body` is missing' do
382
+ expect {
383
+ client.post(uri, nil, headers: {'Content-Type' => 'text/plain'})
384
+ }.to raise_error(ArgumentError, /'post' requires a string 'body' argument/)
385
+ end
386
+
387
+ it 'raises an ArgumentError if `content_type` is missing from the headers hash' do
388
+ expect {
389
+ client.post(uri, "")
390
+ }.to raise_error(ArgumentError, /'post' requires a 'content-type' header/)
391
+ end
392
+
393
+ context 'when connecting' do
394
+ it 'uses a specified ssl context' do
395
+ stub_request(:post, uri)
396
+
397
+ other_context = Puppet::SSL::SSLContext.new
398
+
399
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {body: "", ssl_context: other_context})
400
+ end
401
+
402
+ it 'uses the system store' do
403
+ stub_request(:post, uri)
404
+
405
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {include_system_store: true})
406
+ end
407
+
408
+ it 'raises an HTTPError if both are specified' do
409
+ expect {
410
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: puppet_context, include_system_store: true})
411
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
412
+ end
413
+ end
414
+ end
415
+
416
+ context "for DELETE requests" do
417
+ it "includes default HTTP headers" do
418
+ stub_request(:delete, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./})
419
+
420
+ client.delete(uri)
421
+ end
422
+
423
+ it "merges custom headers with default ones" do
424
+ stub_request(:delete, uri).with(headers: { 'X-Foo' => 'Bar', 'X-Puppet-Version' => /./, 'User-Agent' => /./ })
425
+
426
+ client.delete(uri, headers: {'X-Foo' => 'Bar'})
427
+ end
428
+
429
+ it "stringifies keys and encodes values in the query" do
430
+ stub_request(:delete, "https://www.example.com").with(query: "foo=bar%3Dbaz")
431
+
432
+ client.delete(uri, params: {:foo => "bar=baz"})
433
+ end
434
+
435
+ it "returns the response" do
436
+ stub_request(:delete, uri)
437
+
438
+ response = client.delete(uri)
439
+ expect(response).to be_an_instance_of(Puppet::HTTP::Response)
440
+ expect(response).to be_success
441
+ expect(response.code).to eq(200)
442
+ end
443
+
444
+ it "returns the entire response body" do
445
+ stub_request(:delete, uri).to_return(body: "abc")
446
+
447
+ expect(client.delete(uri).body).to eq("abc")
448
+ end
449
+
450
+ context 'when connecting' do
451
+ it 'uses a specified ssl context' do
452
+ stub_request(:delete, uri)
453
+
454
+ other_context = Puppet::SSL::SSLContext.new
455
+
456
+ client.delete(uri, options: {ssl_context: other_context})
457
+ end
458
+
459
+ it 'uses the system store' do
460
+ stub_request(:delete, uri)
461
+
462
+ client.delete(uri, options: {include_system_store: true})
463
+ end
464
+
465
+ it 'raises an HTTPError if both are specified' do
466
+ expect {
467
+ client.delete(uri, options: {ssl_context: puppet_context, include_system_store: true})
468
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
469
+ end
158
470
  end
159
471
  end
160
472
 
@@ -162,38 +474,38 @@ describe Puppet::HTTP::Client do
162
474
  it "submits credentials for GET requests" do
163
475
  stub_request(:get, uri).with(basic_auth: credentials)
164
476
 
165
- client.get(uri, user: 'user', password: 'pass')
477
+ client.get(uri, options: {basic_auth: {user: 'user', password: 'pass'}})
166
478
  end
167
479
 
168
480
  it "submits credentials for PUT requests" do
169
481
  stub_request(:put, uri).with(basic_auth: credentials)
170
482
 
171
- client.put(uri, content_type: 'text/plain', body: "hello", user: 'user', password: 'pass')
483
+ client.put(uri, "hello", headers: {'Content-Type' => 'text/plain'}, options: {basic_auth: {user: 'user', password: 'pass'}})
172
484
  end
173
485
 
174
486
  it "returns response containing access denied" do
175
487
  stub_request(:get, uri).with(basic_auth: credentials).to_return(status: [403, "Ye Shall Not Pass"])
176
488
 
177
- response = client.get(uri, user: 'user', password: 'pass')
489
+ response = client.get(uri, options: {basic_auth: {user: 'user', password: 'pass'}})
178
490
  expect(response.code).to eq(403)
179
491
  expect(response.reason).to eq("Ye Shall Not Pass")
180
492
  expect(response).to_not be_success
181
493
  end
182
494
 
183
- it 'omits basic auth if user is nil' do
495
+ it 'includes basic auth if user is nil' do
184
496
  stub_request(:get, uri).with do |req|
185
- expect(req.headers).to_not include('Authorization')
497
+ expect(req.headers).to include('Authorization')
186
498
  end
187
499
 
188
- client.get(uri, user: nil, password: 'pass')
500
+ client.get(uri, options: {basic_auth: {user: nil, password: 'pass'}})
189
501
  end
190
502
 
191
- it 'omits basic auth if password is nil' do
503
+ it 'includes basic auth if password is nil' do
192
504
  stub_request(:get, uri).with do |req|
193
- expect(req.headers).to_not include('Authorization')
505
+ expect(req.headers).to include('Authorization')
194
506
  end
195
507
 
196
- client.get(uri, user: 'user', password: nil)
508
+ client.get(uri, options: {basic_auth: {user: 'user', password: nil}})
197
509
  end
198
510
  end
199
511
 
@@ -219,7 +531,7 @@ describe Puppet::HTTP::Client do
219
531
  stub_request(:put, start_url).to_return(redirect_to(url: bar_url))
220
532
  stub_request(:put, bar_url).to_return(status: 200)
221
533
 
222
- response = client.put(start_url, body: "", content_type: 'text/plain')
534
+ response = client.put(start_url, "", headers: {'Content-Type' => 'text/plain'})
223
535
  expect(response).to be_success
224
536
  end
225
537
 
@@ -245,7 +557,7 @@ describe Puppet::HTTP::Client do
245
557
  stub_request(:get, start_url).with(basic_auth: credentials).to_return(redirect_to(url: bar_url))
246
558
  stub_request(:get, bar_url).with(basic_auth: credentials).to_return(status: 200)
247
559
 
248
- client.get(start_url, user: 'user', password: 'pass')
560
+ client.get(start_url, options: {basic_auth: {user: 'user', password: 'pass'}})
249
561
  end
250
562
 
251
563
  it "redirects given a relative location" do
@@ -272,7 +584,7 @@ describe Puppet::HTTP::Client do
272
584
  stub_request(:put, start_url).with(body: data).to_return(redirect_to(url: bar_url))
273
585
  stub_request(:put, bar_url).with(body: data).to_return(status: 200)
274
586
 
275
- response = client.put(start_url, body: data, content_type: 'text/plain')
587
+ response = client.put(start_url, data, headers: {'Content-Type' => 'text/plain'})
276
588
  expect(response).to be_success
277
589
  end
278
590
 
@@ -401,6 +713,32 @@ describe Puppet::HTTP::Client do
401
713
  }.to raise_error(Puppet::HTTP::ProtocolError, /Failed to parse Retry-After header 'foo' as an integer or RFC 2822 date/)
402
714
  end
403
715
 
716
+ it "should close the connection before sleeping" do
717
+ retry_after('42')
718
+
719
+ site = Puppet::Network::HTTP::Site.from_uri(uri)
720
+
721
+ http1 = Net::HTTP.new(site.host, site.port)
722
+ http1.use_ssl = true
723
+ allow(http1).to receive(:started?).and_return(true)
724
+
725
+ http2 = Net::HTTP.new(site.host, site.port)
726
+ http2.use_ssl = true
727
+ allow(http2).to receive(:started?).and_return(true)
728
+
729
+
730
+ pool = Puppet::Network::HTTP::Pool.new(15)
731
+ client = Puppet::HTTP::Client.new(pool: pool)
732
+
733
+ # The "with_connection" method is required to yield started connections
734
+ allow(pool).to receive(:with_connection).and_yield(http1).and_yield(http2)
735
+
736
+ expect(http1).to receive(:finish).ordered
737
+ expect(::Kernel).to receive(:sleep).with(42).ordered
738
+
739
+ client.get(uri)
740
+ end
741
+
404
742
  it "should sleep and retry if Retry-After is an Integer" do
405
743
  retry_after('42')
406
744
 
@@ -437,4 +775,34 @@ describe Puppet::HTTP::Client do
437
775
  client.get(uri)
438
776
  end
439
777
  end
778
+
779
+ context "persistent connections" do
780
+ before :each do
781
+ stub_request(:get, uri)
782
+ end
783
+
784
+ it 'defaults keepalive to http_keepalive_timeout' do
785
+ expect(client.pool.keepalive_timeout).to eq(Puppet[:http_keepalive_timeout])
786
+ end
787
+
788
+ it 'reuses a cached connection' do
789
+ allow(Puppet).to receive(:debug)
790
+ expect(Puppet).to receive(:debug).with(/^Creating new connection/)
791
+ expect(Puppet).to receive(:debug).with(/^Using cached connection/)
792
+
793
+ client.get(uri)
794
+ client.get(uri)
795
+ end
796
+
797
+ it 'can be disabled' do
798
+ Puppet[:http_keepalive_timeout] = 0
799
+
800
+ allow(Puppet).to receive(:debug)
801
+ expect(Puppet).to receive(:debug).with(/^Creating new connection/).twice
802
+ expect(Puppet).to receive(:debug).with(/^Using cached connection/).never
803
+
804
+ client.get(uri)
805
+ client.get(uri)
806
+ end
807
+ end
440
808
  end