puppet 3.2.4 → 3.3.0.rc2

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 (562) hide show
  1. data/COMMITTERS.md +101 -42
  2. data/Gemfile +15 -4
  3. data/README.md +5 -1
  4. data/README_DEVELOPER.md +117 -54
  5. data/Rakefile +4 -0
  6. data/ext/build_defaults.yaml +3 -2
  7. data/ext/debian/puppet-common.manpages +33 -1
  8. data/ext/gentoo/init.d/puppet +1 -1
  9. data/ext/gentoo/init.d/puppetmaster +1 -1
  10. data/ext/redhat/puppet.spec.erb +0 -1
  11. data/install.rb +2 -1
  12. data/lib/hiera/backend/puppet_backend.rb +1 -1
  13. data/lib/puppet/application.rb +10 -9
  14. data/lib/puppet/application/agent.rb +87 -93
  15. data/lib/puppet/application/apply.rb +0 -2
  16. data/lib/puppet/application/device.rb +3 -3
  17. data/lib/puppet/application/kick.rb +2 -2
  18. data/lib/puppet/application/master.rb +41 -19
  19. data/lib/puppet/application/queue.rb +5 -3
  20. data/lib/puppet/bindings.rb +147 -0
  21. data/lib/puppet/configurer.rb +25 -15
  22. data/lib/puppet/configurer/fact_handler.rb +2 -9
  23. data/lib/puppet/daemon.rb +44 -33
  24. data/lib/puppet/defaults.rb +57 -26
  25. data/lib/puppet/error.rb +1 -1
  26. data/lib/puppet/external/dot.rb +2 -2
  27. data/lib/puppet/external/nagios/base.rb +1 -6
  28. data/lib/puppet/external/pson/common.rb +2 -2
  29. data/lib/puppet/external/pson/pure/generator.rb +2 -2
  30. data/lib/puppet/external/pson/pure/parser.rb +1 -1
  31. data/lib/puppet/face/ca.rb +1 -1
  32. data/lib/puppet/face/config.rb +1 -1
  33. data/lib/puppet/face/help.rb +2 -2
  34. data/lib/puppet/face/module/list.rb +2 -2
  35. data/lib/puppet/feature/rails.rb +1 -1
  36. data/lib/puppet/file_bucket/dipper.rb +0 -1
  37. data/lib/puppet/file_serving/base.rb +1 -1
  38. data/lib/puppet/file_serving/configuration/parser.rb +20 -14
  39. data/lib/puppet/forge.rb +0 -32
  40. data/lib/puppet/forge/cache.rb +1 -1
  41. data/lib/puppet/forge/errors.rb +3 -3
  42. data/lib/puppet/forge/repository.rb +7 -42
  43. data/lib/puppet/graph.rb +11 -0
  44. data/lib/puppet/graph/key.rb +26 -0
  45. data/lib/puppet/graph/prioritizer.rb +29 -0
  46. data/lib/puppet/graph/random_prioritizer.rb +16 -0
  47. data/lib/puppet/{rb_tree_map.rb → graph/rb_tree_map.rb} +3 -3
  48. data/lib/puppet/graph/relationship_graph.rb +246 -0
  49. data/lib/puppet/graph/sequential_prioritizer.rb +31 -0
  50. data/lib/puppet/{simple_graph.rb → graph/simple_graph.rb} +22 -3
  51. data/lib/puppet/graph/title_hash_prioritizer.rb +16 -0
  52. data/lib/puppet/indirector.rb +2 -2
  53. data/lib/puppet/indirector/catalog/compiler.rb +10 -7
  54. data/lib/puppet/indirector/catalog/static_compiler.rb +50 -0
  55. data/lib/puppet/indirector/certificate/rest.rb +1 -1
  56. data/lib/puppet/indirector/exec.rb +1 -1
  57. data/lib/puppet/indirector/facts/facter.rb +2 -2
  58. data/lib/puppet/indirector/facts/inventory_active_record.rb +0 -1
  59. data/lib/puppet/indirector/facts/network_device.rb +1 -1
  60. data/lib/puppet/indirector/file_bucket_file/file.rb +0 -1
  61. data/lib/puppet/indirector/indirection.rb +2 -2
  62. data/lib/puppet/indirector/memory.rb +9 -0
  63. data/lib/puppet/indirector/node/ldap.rb +2 -4
  64. data/lib/puppet/indirector/report/processor.rb +1 -2
  65. data/lib/puppet/indirector/report/rest.rb +1 -1
  66. data/lib/puppet/indirector/request.rb +32 -10
  67. data/lib/puppet/indirector/resource/rest.rb +1 -1
  68. data/lib/puppet/indirector/resource_type/parser.rb +31 -12
  69. data/lib/puppet/interface.rb +1 -1
  70. data/lib/puppet/interface/documentation.rb +7 -11
  71. data/lib/puppet/interface/option.rb +1 -1
  72. data/lib/puppet/interface/option_builder.rb +1 -1
  73. data/lib/puppet/metatype/manager.rb +2 -2
  74. data/lib/puppet/module.rb +7 -1
  75. data/lib/puppet/module_tool.rb +1 -1
  76. data/lib/puppet/module_tool/applications/application.rb +10 -0
  77. data/lib/puppet/module_tool/applications/installer.rb +6 -3
  78. data/lib/puppet/module_tool/dependency.rb +2 -0
  79. data/lib/puppet/module_tool/errors/upgrader.rb +1 -1
  80. data/lib/puppet/module_tool/metadata.rb +25 -13
  81. data/lib/puppet/module_tool/modulefile.rb +7 -7
  82. data/lib/puppet/module_tool/shared_behaviors.rb +4 -2
  83. data/lib/puppet/module_tool/skeleton.rb +1 -1
  84. data/lib/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb +5 -5
  85. data/lib/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb +5 -4
  86. data/lib/puppet/network/auth_config_parser.rb +3 -0
  87. data/lib/puppet/network/authconfig.rb +0 -1
  88. data/lib/puppet/network/authorization.rb +1 -1
  89. data/lib/puppet/network/authstore.rb +2 -2
  90. data/lib/puppet/network/format_handler.rb +25 -114
  91. data/lib/puppet/network/format_support.rb +106 -0
  92. data/lib/puppet/network/formats.rb +10 -4
  93. data/lib/puppet/network/http/compression.rb +1 -1
  94. data/lib/puppet/network/http/connection.rb +76 -32
  95. data/lib/puppet/network/http/handler.rb +122 -61
  96. data/lib/puppet/network/http/rack/rest.rb +1 -1
  97. data/lib/puppet/network/http/webrick/rest.rb +9 -3
  98. data/lib/puppet/network/http_pool.rb +2 -2
  99. data/lib/puppet/network/resolver.rb +1 -0
  100. data/lib/puppet/network/server.rb +5 -81
  101. data/lib/puppet/node/environment.rb +256 -13
  102. data/lib/puppet/node/facts.rb +28 -2
  103. data/lib/puppet/parameter.rb +27 -18
  104. data/lib/puppet/parameter/boolean.rb +20 -0
  105. data/lib/puppet/parameter/path.rb +1 -1
  106. data/lib/puppet/parameter/value.rb +1 -1
  107. data/lib/puppet/parameter/value_collection.rb +1 -1
  108. data/lib/puppet/parser/ast/arithmetic_operator.rb +8 -0
  109. data/lib/puppet/parser/ast/casestatement.rb +0 -3
  110. data/lib/puppet/parser/ast/lambda.rb +25 -6
  111. data/lib/puppet/parser/ast/leaf.rb +10 -3
  112. data/lib/puppet/parser/ast/nop.rb +1 -1
  113. data/lib/puppet/parser/ast/resource_override.rb +0 -2
  114. data/lib/puppet/parser/compiler.rb +92 -34
  115. data/lib/puppet/parser/files.rb +0 -5
  116. data/lib/puppet/parser/functions/create_resources.rb +23 -46
  117. data/lib/puppet/parser/functions/each.rb +0 -2
  118. data/lib/puppet/parser/functions/extlookup.rb +2 -2
  119. data/lib/puppet/parser/functions/foreach.rb +0 -2
  120. data/lib/puppet/parser/functions/hiera_include.rb +1 -1
  121. data/lib/puppet/parser/functions/lookup.rb +44 -0
  122. data/lib/puppet/parser/functions/slice.rb +1 -1
  123. data/lib/puppet/parser/grammar.ra +0 -1
  124. data/lib/puppet/parser/lexer.rb +0 -1
  125. data/lib/puppet/parser/parser.rb +0 -1
  126. data/lib/puppet/parser/parser_factory.rb +3 -2
  127. data/lib/puppet/parser/parser_support.rb +1 -1
  128. data/lib/puppet/parser/relationship.rb +1 -1
  129. data/lib/puppet/parser/scope.rb +49 -24
  130. data/lib/puppet/parser/type_loader.rb +13 -18
  131. data/lib/puppet/pops.rb +45 -0
  132. data/lib/puppet/pops/adaptable.rb +2 -2
  133. data/lib/puppet/pops/adapters.rb +4 -0
  134. data/lib/puppet/pops/binder/binder.rb +421 -0
  135. data/lib/puppet/pops/binder/binder_issues.rb +142 -0
  136. data/lib/puppet/pops/binder/bindings_checker.rb +217 -0
  137. data/lib/puppet/pops/binder/bindings_composer.rb +241 -0
  138. data/lib/puppet/pops/binder/bindings_factory.rb +847 -0
  139. data/lib/puppet/pops/binder/bindings_label_provider.rb +46 -0
  140. data/lib/puppet/pops/binder/bindings_loader.rb +79 -0
  141. data/lib/puppet/pops/binder/bindings_model.rb +215 -0
  142. data/lib/puppet/pops/binder/bindings_model_dumper.rb +205 -0
  143. data/lib/puppet/pops/binder/bindings_validator_factory.rb +28 -0
  144. data/lib/puppet/pops/binder/config/binder_config.rb +139 -0
  145. data/lib/puppet/pops/binder/config/binder_config_checker.rb +183 -0
  146. data/lib/puppet/pops/binder/config/diagnostic_producer.rb +32 -0
  147. data/lib/puppet/pops/binder/config/issues.rb +106 -0
  148. data/lib/puppet/pops/binder/hiera2.rb +10 -0
  149. data/lib/puppet/pops/binder/hiera2/bindings_provider.rb +148 -0
  150. data/lib/puppet/pops/binder/hiera2/config.rb +69 -0
  151. data/lib/puppet/pops/binder/hiera2/config_checker.rb +68 -0
  152. data/lib/puppet/pops/binder/hiera2/diagnostic_producer.rb +36 -0
  153. data/lib/puppet/pops/binder/hiera2/issues.rb +67 -0
  154. data/lib/puppet/pops/binder/hiera2/json_backend.rb +18 -0
  155. data/lib/puppet/pops/binder/hiera2/yaml_backend.rb +21 -0
  156. data/lib/puppet/pops/binder/injector.rb +688 -0
  157. data/lib/puppet/pops/binder/injector_entry.rb +53 -0
  158. data/lib/puppet/pops/binder/key_factory.rb +61 -0
  159. data/lib/puppet/pops/binder/producers.rb +829 -0
  160. data/lib/puppet/pops/binder/scheme_handler/confdir_hiera_scheme.rb +67 -0
  161. data/lib/puppet/pops/binder/scheme_handler/confdir_scheme.rb +34 -0
  162. data/lib/puppet/pops/binder/scheme_handler/module_hiera_scheme.rb +92 -0
  163. data/lib/puppet/pops/binder/scheme_handler/module_scheme.rb +84 -0
  164. data/lib/puppet/pops/binder/scheme_handler/symbolic_scheme.rb +54 -0
  165. data/lib/puppet/pops/binder/system_bindings.rb +72 -0
  166. data/lib/puppet/pops/issue_reporter.rb +75 -0
  167. data/lib/puppet/pops/issues.rb +9 -5
  168. data/lib/puppet/pops/model/ast_transformer.rb +4 -4
  169. data/lib/puppet/pops/model/ast_tree_dumper.rb +1 -1
  170. data/lib/puppet/pops/model/factory.rb +25 -13
  171. data/lib/puppet/pops/model/model.rb +1 -1
  172. data/lib/puppet/pops/model/tree_dumper.rb +2 -2
  173. data/lib/puppet/pops/parser/egrammar.ra +0 -1
  174. data/lib/puppet/pops/parser/eparser.rb +1 -2
  175. data/lib/puppet/pops/parser/evaluating_parser.rb +162 -0
  176. data/lib/puppet/pops/parser/lexer.rb +8 -6
  177. data/lib/puppet/pops/types/class_loader.rb +118 -0
  178. data/lib/puppet/pops/types/type_calculator.rb +557 -0
  179. data/lib/puppet/pops/types/type_factory.rb +147 -0
  180. data/lib/puppet/pops/types/type_parser.rb +117 -0
  181. data/lib/puppet/pops/types/types.rb +132 -0
  182. data/lib/puppet/pops/validation.rb +146 -17
  183. data/lib/puppet/pops/validation/checker3_1.rb +1 -1
  184. data/lib/puppet/pops/validation/validator_factory_3_1.rb +6 -16
  185. data/lib/puppet/property.rb +3 -3
  186. data/lib/puppet/property/keyvalue.rb +1 -1
  187. data/lib/puppet/provider.rb +2 -2
  188. data/lib/puppet/provider/aixobject.rb +19 -21
  189. data/lib/puppet/provider/augeas/augeas.rb +3 -1
  190. data/lib/puppet/provider/command.rb +2 -2
  191. data/lib/puppet/provider/group/aix.rb +1 -1
  192. data/lib/puppet/provider/group/ldap.rb +1 -1
  193. data/lib/puppet/provider/macauthorization/macauthorization.rb +1 -1
  194. data/lib/puppet/provider/mailalias/aliases.rb +3 -8
  195. data/lib/puppet/provider/mcx/mcxcontent.rb +7 -1
  196. data/lib/puppet/provider/mount.rb +8 -3
  197. data/lib/puppet/provider/nameservice.rb +1 -1
  198. data/lib/puppet/provider/nameservice/directoryservice.rb +5 -5
  199. data/lib/puppet/provider/package/appdmg.rb +1 -1
  200. data/lib/puppet/provider/package/apt.rb +0 -1
  201. data/lib/puppet/provider/package/dpkg.rb +86 -32
  202. data/lib/puppet/provider/package/fink.rb +0 -2
  203. data/lib/puppet/provider/package/freebsd.rb +0 -2
  204. data/lib/puppet/provider/package/openbsd.rb +57 -10
  205. data/lib/puppet/provider/package/opkg.rb +0 -1
  206. data/lib/puppet/provider/package/pacman.rb +0 -1
  207. data/lib/puppet/provider/package/pip.rb +1 -1
  208. data/lib/puppet/provider/package/pkgdmg.rb +17 -6
  209. data/lib/puppet/provider/package/pkgutil.rb +1 -1
  210. data/lib/puppet/provider/package/portage.rb +9 -1
  211. data/lib/puppet/provider/package/ports.rb +2 -2
  212. data/lib/puppet/provider/package/rpm.rb +29 -12
  213. data/lib/puppet/provider/package/rug.rb +1 -1
  214. data/lib/puppet/provider/package/urpmi.rb +11 -15
  215. data/lib/puppet/provider/package/windows/exe_package.rb +1 -1
  216. data/lib/puppet/provider/package/windows/package.rb +1 -26
  217. data/lib/puppet/provider/package/yum.rb +1 -1
  218. data/lib/puppet/provider/package/zypper.rb +22 -3
  219. data/lib/puppet/provider/parsedfile.rb +1 -12
  220. data/lib/puppet/provider/scheduled_task/win32_taskscheduler.rb +1 -1
  221. data/lib/puppet/provider/service/base.rb +1 -1
  222. data/lib/puppet/provider/service/daemontools.rb +3 -3
  223. data/lib/puppet/provider/service/debian.rb +1 -1
  224. data/lib/puppet/provider/service/init.rb +14 -20
  225. data/lib/puppet/provider/service/openrc.rb +3 -1
  226. data/lib/puppet/provider/service/redhat.rb +5 -8
  227. data/lib/puppet/provider/service/runit.rb +3 -2
  228. data/lib/puppet/provider/service/systemd.rb +1 -1
  229. data/lib/puppet/provider/ssh_authorized_key/parsed.rb +1 -1
  230. data/lib/puppet/provider/sshkey/parsed.rb +0 -2
  231. data/lib/puppet/provider/user/aix.rb +25 -12
  232. data/lib/puppet/provider/user/directoryservice.rb +4 -7
  233. data/lib/puppet/provider/user/ldap.rb +0 -1
  234. data/lib/puppet/provider/user/user_role_add.rb +2 -0
  235. data/lib/puppet/provider/user/useradd.rb +1 -1
  236. data/lib/puppet/provider/zone/solaris.rb +1 -2
  237. data/lib/puppet/reference/metaparameter.rb +1 -1
  238. data/lib/puppet/reference/type.rb +1 -1
  239. data/lib/puppet/reports/rrdgraph.rb +1 -1
  240. data/lib/puppet/reports/tagmail.rb +1 -1
  241. data/lib/puppet/resource.rb +16 -4
  242. data/lib/puppet/resource/catalog.rb +111 -173
  243. data/lib/puppet/resource/status.rb +42 -3
  244. data/lib/puppet/resource/type.rb +33 -46
  245. data/lib/puppet/resource/type_collection.rb +19 -15
  246. data/lib/puppet/run.rb +5 -1
  247. data/lib/puppet/scheduler/scheduler.rb +14 -15
  248. data/lib/puppet/settings.rb +78 -41
  249. data/lib/puppet/settings/boolean_setting.rb +0 -2
  250. data/lib/puppet/settings/config_file.rb +0 -2
  251. data/lib/puppet/settings/directory_setting.rb +0 -2
  252. data/lib/puppet/settings/duration_setting.rb +0 -2
  253. data/lib/puppet/settings/enum_setting.rb +16 -0
  254. data/lib/puppet/settings/file_setting.rb +0 -2
  255. data/lib/puppet/settings/path_setting.rb +0 -2
  256. data/lib/puppet/settings/string_setting.rb +0 -3
  257. data/lib/puppet/settings/terminus_setting.rb +0 -2
  258. data/lib/puppet/ssl/certificate_authority.rb +102 -9
  259. data/lib/puppet/test/test_helper.rb +1 -0
  260. data/lib/puppet/transaction.rb +130 -292
  261. data/lib/puppet/transaction/additional_resource_generator.rb +126 -0
  262. data/lib/puppet/transaction/event.rb +16 -1
  263. data/lib/puppet/transaction/report.rb +34 -14
  264. data/lib/puppet/transaction/resource_harness.rb +16 -19
  265. data/lib/puppet/type.rb +59 -53
  266. data/lib/puppet/type/component.rb +0 -2
  267. data/lib/puppet/type/cron.rb +13 -2
  268. data/lib/puppet/type/exec.rb +5 -7
  269. data/lib/puppet/type/file.rb +9 -32
  270. data/lib/puppet/type/file/content.rb +4 -1
  271. data/lib/puppet/type/file/ctime.rb +3 -1
  272. data/lib/puppet/type/file/ensure.rb +1 -1
  273. data/lib/puppet/type/file/mode.rb +0 -1
  274. data/lib/puppet/type/file/mtime.rb +2 -1
  275. data/lib/puppet/type/group.rb +7 -9
  276. data/lib/puppet/type/host.rb +1 -2
  277. data/lib/puppet/type/mcx.rb +0 -1
  278. data/lib/puppet/type/mount.rb +38 -6
  279. data/lib/puppet/type/package.rb +2 -2
  280. data/lib/puppet/type/resources.rb +5 -4
  281. data/lib/puppet/type/schedule.rb +1 -4
  282. data/lib/puppet/type/selmodule.rb +1 -1
  283. data/lib/puppet/type/service.rb +1 -3
  284. data/lib/puppet/type/tidy.rb +3 -3
  285. data/lib/puppet/type/user.rb +9 -13
  286. data/lib/puppet/type/yumrepo.rb +11 -7
  287. data/lib/puppet/util.rb +14 -7
  288. data/lib/puppet/util/autoload.rb +0 -1
  289. data/lib/puppet/util/backups.rb +1 -3
  290. data/lib/puppet/util/classgen.rb +1 -1
  291. data/lib/puppet/util/command_line/puppet_option_parser.rb +1 -3
  292. data/lib/puppet/util/command_line/trollop.rb +1 -1
  293. data/lib/puppet/util/constant_inflector.rb +1 -2
  294. data/lib/puppet/util/errors.rb +1 -0
  295. data/lib/puppet/util/file_watcher.rb +28 -0
  296. data/lib/puppet/util/fileparsing.rb +1 -3
  297. data/lib/puppet/util/filetype.rb +0 -1
  298. data/lib/puppet/util/http_proxy.rb +38 -0
  299. data/lib/puppet/util/ldap/manager.rb +1 -2
  300. data/lib/puppet/util/log.rb +31 -10
  301. data/lib/puppet/util/log/destinations.rb +0 -50
  302. data/lib/puppet/util/metric.rb +8 -1
  303. data/lib/puppet/util/monkey_patches.rb +14 -148
  304. data/lib/puppet/util/network_device/cisco/facts.rb +1 -1
  305. data/lib/puppet/util/network_device/config.rb +6 -9
  306. data/lib/puppet/util/network_device/transport/ssh.rb +1 -1
  307. data/lib/puppet/util/pidlock.rb +3 -0
  308. data/lib/puppet/util/posix.rb +1 -1
  309. data/lib/puppet/util/profiler.rb +1 -1
  310. data/lib/puppet/util/rdoc.rb +1 -1
  311. data/lib/puppet/util/rdoc/generators/puppet_generator.rb +0 -1
  312. data/lib/puppet/util/rdoc/generators/template/puppet/puppet.rb +50 -42
  313. data/lib/puppet/util/retryaction.rb +0 -1
  314. data/lib/puppet/util/symbolic_file_mode.rb +5 -1
  315. data/lib/puppet/util/tagging.rb +0 -2
  316. data/lib/puppet/util/warnings.rb +3 -0
  317. data/lib/puppet/util/watched_file.rb +37 -0
  318. data/lib/puppet/util/watcher.rb +17 -0
  319. data/lib/puppet/util/watcher/change_watcher.rb +33 -0
  320. data/lib/puppet/util/watcher/periodic_watcher.rb +37 -0
  321. data/lib/puppet/util/watcher/timer.rb +19 -0
  322. data/lib/puppet/util/windows/user.rb +1 -1
  323. data/lib/puppet/version.rb +1 -1
  324. data/lib/puppetx.rb +109 -0
  325. data/lib/puppetx/puppet/bindings_scheme_handler.rb +130 -0
  326. data/lib/puppetx/puppet/hiera2_backend.rb +31 -0
  327. data/lib/puppetx/puppet/syntax_checker.rb +91 -0
  328. data/lib/puppetx/puppetlabs/syntax_checkers/json.rb +39 -0
  329. data/lib/semver.rb +1 -1
  330. data/man/man8/puppet-kick.8 +1 -1
  331. data/spec/fixtures/integration/provider/cron/crontab/unspecialized +15 -0
  332. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/binder_config.yaml +18 -0
  333. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/hiera.yaml +8 -0
  334. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/modules/good/common.yaml +1 -0
  335. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/modules/good/hiera.yaml +10 -0
  336. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/binder_config.yaml +19 -0
  337. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/common.yaml +1 -0
  338. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/hiera.yaml +11 -0
  339. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/localhost.yaml +1 -0
  340. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/common.yaml +3 -0
  341. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/hiera.yaml +13 -0
  342. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/lib/puppet/bindings/awesome/default.rb +4 -0
  343. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/lib/puppetx/awesome/echo_backend.rb +11 -0
  344. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/lib/puppetx/awesome/echo_scheme_handler.rb +18 -0
  345. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/localhost.yaml +1 -0
  346. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/bad/common.yaml +3 -0
  347. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/bad/hiera_config.yaml +9 -0
  348. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/good/common.yaml +2 -0
  349. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/good/hiera.yaml +11 -0
  350. data/spec/fixtures/unit/pops/binder/config/binder_config/ok/binder_config.yaml +9 -0
  351. data/spec/fixtures/unit/pops/binder/hiera2/bindings_provider/ok/hiera.yaml +9 -0
  352. data/spec/fixtures/unit/pops/binder/hiera2/bindings_provider/ok/node.example.com.json +9 -0
  353. data/spec/fixtures/unit/pops/binder/hiera2/bindings_provider/ok/node.example.com.yaml +5 -0
  354. data/spec/fixtures/unit/pops/binder/hiera2/config/bad_syntax/hiera.yaml +10 -0
  355. data/spec/fixtures/unit/pops/binder/hiera2/config/malformed_hierarchy/hiera.yaml +8 -0
  356. data/spec/fixtures/unit/pops/binder/hiera2/config/missing/foo.txt +1 -0
  357. data/spec/fixtures/unit/pops/binder/hiera2/config/no_backends/hiera.yaml +7 -0
  358. data/spec/fixtures/unit/pops/binder/hiera2/config/no_hierarchy/hiera.yaml +4 -0
  359. data/spec/fixtures/unit/pops/binder/hiera2/config/not_a_hash/hiera.yaml +2 -0
  360. data/spec/fixtures/unit/pops/binder/hiera2/config/ok/hiera.yaml +8 -0
  361. data/spec/fixtures/unit/pops/binder/hiera2/yaml_backend/empty/common.yaml +0 -0
  362. data/spec/fixtures/unit/pops/binder/hiera2/yaml_backend/invalid/common.yaml +1 -0
  363. data/spec/fixtures/unit/pops/binder/hiera2/yaml_backend/ok/common.yaml +2 -0
  364. data/spec/fixtures/unit/provider/package/openbsd/pkginfo_flavors.list +2 -0
  365. data/spec/integration/agent/logging_spec.rb +178 -0
  366. data/spec/integration/configurer_spec.rb +1 -1
  367. data/spec/integration/defaults_spec.rb +0 -6
  368. data/spec/integration/network/authconfig_spec.rb +19 -0
  369. data/spec/integration/network/server/webrick_spec.rb +10 -11
  370. data/spec/integration/parser/catalog_spec.rb +85 -0
  371. data/spec/integration/provider/cron/crontab_spec.rb +11 -0
  372. data/spec/integration/provider/mount_spec.rb +1 -0
  373. data/spec/integration/transaction_spec.rb +8 -8
  374. data/spec/integration/type/file_spec.rb +1 -1
  375. data/spec/integration/util/settings_spec.rb +58 -11
  376. data/spec/lib/matchers/include_in_order.rb +21 -0
  377. data/spec/lib/matchers/include_in_order_spec.rb +30 -0
  378. data/spec/lib/matchers/relationship_graph_matchers.rb +48 -0
  379. data/spec/lib/puppet_spec/compiler.rb +24 -0
  380. data/spec/lib/puppet_spec/pops.rb +16 -0
  381. data/spec/spec_helper.rb +0 -1
  382. data/spec/unit/application/agent_spec.rb +145 -145
  383. data/spec/unit/application/apply_spec.rb +1 -1
  384. data/spec/unit/application/doc_spec.rb +1 -1
  385. data/spec/unit/application/face_base_spec.rb +3 -3
  386. data/spec/unit/application/facts_spec.rb +1 -0
  387. data/spec/unit/application/master_spec.rb +0 -15
  388. data/spec/unit/application/queue_spec.rb +6 -12
  389. data/spec/unit/application/resource_spec.rb +1 -1
  390. data/spec/unit/configurer/fact_handler_spec.rb +19 -50
  391. data/spec/unit/configurer_spec.rb +23 -7
  392. data/spec/unit/daemon_spec.rb +97 -121
  393. data/spec/unit/defaults_spec.rb +44 -0
  394. data/spec/unit/face/node_spec.rb +2 -2
  395. data/spec/unit/file_serving/configuration/parser_spec.rb +23 -33
  396. data/spec/unit/file_serving/configuration_spec.rb +2 -2
  397. data/spec/unit/file_serving/mount/file_spec.rb +4 -4
  398. data/spec/unit/forge/repository_spec.rb +9 -29
  399. data/spec/unit/graph/key_spec.rb +41 -0
  400. data/spec/unit/{rb_tree_map_spec.rb → graph/rb_tree_map_spec.rb} +7 -7
  401. data/spec/unit/graph/relationship_graph_spec.rb +393 -0
  402. data/spec/unit/graph/sequential_prioritizer_spec.rb +32 -0
  403. data/spec/unit/{simple_graph_spec.rb → graph/simple_graph.rb} +42 -254
  404. data/spec/unit/graph/title_hash_prioritizer_spec.rb +49 -0
  405. data/spec/unit/hiera_puppet_spec.rb +1 -1
  406. data/spec/unit/indirector/catalog/active_record_spec.rb +4 -2
  407. data/spec/unit/indirector/catalog/compiler_spec.rb +20 -26
  408. data/spec/unit/indirector/face_spec.rb +1 -1
  409. data/spec/unit/indirector/facts/facter_spec.rb +11 -1
  410. data/spec/unit/indirector/facts/network_device_spec.rb +11 -1
  411. data/spec/unit/indirector/hiera_spec.rb +1 -1
  412. data/spec/unit/indirector/instrumentation_data/local_spec.rb +1 -1
  413. data/spec/unit/indirector/instrumentation_listener/local_spec.rb +1 -1
  414. data/spec/unit/indirector/request_spec.rb +92 -39
  415. data/spec/unit/indirector/rest_spec.rb +1 -0
  416. data/spec/unit/indirector_spec.rb +2 -2
  417. data/spec/unit/interface/option_builder_spec.rb +1 -0
  418. data/spec/unit/interface/option_spec.rb +1 -0
  419. data/spec/unit/interface_spec.rb +2 -2
  420. data/spec/unit/module_tool/applications/installer_spec.rb +49 -2
  421. data/spec/unit/module_tool/metadata_spec.rb +13 -0
  422. data/spec/unit/network/authstore_spec.rb +1 -1
  423. data/spec/unit/network/format_handler_spec.rb +33 -282
  424. data/spec/unit/network/format_support_spec.rb +199 -0
  425. data/spec/unit/network/formats_spec.rb +2 -2
  426. data/spec/unit/network/http/connection_spec.rb +88 -7
  427. data/spec/unit/network/http/handler_spec.rb +271 -249
  428. data/spec/unit/network/http/rack/rest_spec.rb +1 -1
  429. data/spec/unit/network/http/webrick/rest_spec.rb +73 -22
  430. data/spec/unit/network/http_pool_spec.rb +40 -0
  431. data/spec/unit/network/server_spec.rb +18 -207
  432. data/spec/unit/node/facts_spec.rb +68 -17
  433. data/spec/unit/other/selinux_spec.rb +24 -20
  434. data/spec/unit/parameter/boolean_spec.rb +25 -0
  435. data/spec/unit/parameter/value_collection_spec.rb +7 -7
  436. data/spec/unit/parameter_spec.rb +10 -13
  437. data/spec/unit/parser/ast/function_spec.rb +4 -4
  438. data/spec/unit/parser/ast/leaf_spec.rb +45 -6
  439. data/spec/unit/parser/collector_spec.rb +3 -3
  440. data/spec/unit/parser/compiler_spec.rb +4 -3
  441. data/spec/unit/parser/functions/create_resources_spec.rb +9 -25
  442. data/spec/unit/parser/functions/extlookup_spec.rb +2 -2
  443. data/spec/unit/parser/functions/hiera_include_spec.rb +12 -0
  444. data/spec/unit/parser/functions/lookup_spec.rb +96 -0
  445. data/spec/unit/parser/functions/regsubst_spec.rb +2 -2
  446. data/spec/unit/parser/functions/split_spec.rb +2 -2
  447. data/spec/unit/parser/functions/sprintf_spec.rb +1 -1
  448. data/spec/unit/parser/functions/versioncmp_spec.rb +2 -2
  449. data/spec/unit/parser/functions_spec.rb +7 -7
  450. data/spec/unit/parser/lexer_spec.rb +1 -1
  451. data/spec/unit/parser/methods/collect_spec.rb +43 -0
  452. data/spec/unit/parser/resource_spec.rb +9 -9
  453. data/spec/unit/parser/scope_spec.rb +45 -2
  454. data/spec/unit/parser/type_loader_spec.rb +159 -175
  455. data/spec/unit/pops/binder/binder_spec.rb +62 -0
  456. data/spec/unit/pops/binder/bindings_checker_spec.rb +196 -0
  457. data/spec/unit/pops/binder/bindings_composer_spec.rb +89 -0
  458. data/spec/unit/pops/binder/bindings_validator_factory_spec.rb +18 -0
  459. data/spec/unit/pops/binder/config/binder_config_spec.rb +48 -0
  460. data/spec/unit/pops/binder/hiera2/bindings_provider_spec.rb +74 -0
  461. data/spec/unit/pops/binder/hiera2/config_spec.rb +61 -0
  462. data/spec/unit/pops/binder/hiera2/yaml_backend_spec.rb +33 -0
  463. data/spec/unit/pops/binder/injector_spec.rb +789 -0
  464. data/spec/unit/pops/containment_spec.rb +1 -0
  465. data/spec/unit/pops/issues_spec.rb +1 -1
  466. data/spec/unit/pops/parser/evaluating_parser_spec.rb +88 -0
  467. data/spec/unit/pops/parser/lexer_spec.rb +1 -1
  468. data/spec/unit/pops/parser/parse_calls_spec.rb +4 -0
  469. data/spec/unit/pops/parser/parser_spec.rb +1 -1
  470. data/spec/unit/pops/types/type_calculator_spec.rb +484 -0
  471. data/spec/unit/pops/types/type_factory_spec.rb +65 -0
  472. data/spec/unit/pops/types/type_parser_spec.rb +93 -0
  473. data/spec/unit/property/list_spec.rb +1 -1
  474. data/spec/unit/property/ordered_list_spec.rb +1 -1
  475. data/spec/unit/provider/aixobject_spec.rb +101 -0
  476. data/spec/unit/provider/augeas/augeas_spec.rb +14 -3
  477. data/spec/unit/provider/mcx/mcxcontent_spec.rb +52 -16
  478. data/spec/unit/provider/mount/parsed_spec.rb +44 -56
  479. data/spec/unit/provider/mount_spec.rb +11 -2
  480. data/spec/unit/provider/naginator_spec.rb +8 -0
  481. data/spec/unit/provider/package/apt_spec.rb +5 -1
  482. data/spec/unit/provider/package/aptitude_spec.rb +9 -5
  483. data/spec/unit/provider/package/aptrpm_spec.rb +2 -2
  484. data/spec/unit/provider/package/dpkg_spec.rb +274 -99
  485. data/spec/unit/provider/package/openbsd_spec.rb +84 -1
  486. data/spec/unit/provider/package/opkg_spec.rb +3 -3
  487. data/spec/unit/provider/package/pip_spec.rb +16 -0
  488. data/spec/unit/provider/package/pkgdmg_spec.rb +62 -7
  489. data/spec/unit/provider/package/rpm_spec.rb +112 -21
  490. data/spec/unit/provider/package/urpmi.rb +80 -0
  491. data/spec/unit/provider/package/windows/exe_package_spec.rb +1 -1
  492. data/spec/unit/provider/package/yum_spec.rb +85 -0
  493. data/spec/unit/provider/package/zypper_spec.rb +25 -6
  494. data/spec/unit/provider/parsedfile_spec.rb +3 -2
  495. data/spec/unit/provider/service/init_spec.rb +10 -10
  496. data/spec/unit/provider/service/openrc_spec.rb +16 -0
  497. data/spec/unit/provider/service/openwrt_spec.rb +1 -1
  498. data/spec/unit/provider/service/redhat_spec.rb +7 -0
  499. data/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +2 -2
  500. data/spec/unit/provider/user/aix_spec.rb +89 -0
  501. data/spec/unit/provider/user/directoryservice_spec.rb +11 -4
  502. data/spec/unit/provider/user/user_role_add_spec.rb +18 -0
  503. data/spec/unit/provider_spec.rb +2 -13
  504. data/spec/unit/reports/http_spec.rb +1 -1
  505. data/spec/unit/resource/catalog_spec.rb +23 -97
  506. data/spec/unit/resource/resource_type.json +34 -0
  507. data/spec/unit/resource/status_spec.rb +56 -0
  508. data/spec/unit/resource/type_collection_spec.rb +6 -6
  509. data/spec/unit/resource/type_spec.rb +25 -5
  510. data/spec/unit/resource_spec.rb +68 -24
  511. data/spec/unit/run_spec.rb +16 -0
  512. data/spec/unit/scheduler/scheduler_spec.rb +14 -27
  513. data/spec/unit/semver_spec.rb +5 -0
  514. data/spec/unit/settings/enum_setting_spec.rb +27 -0
  515. data/spec/unit/settings_spec.rb +53 -44
  516. data/spec/unit/ssl/certificate_authority_spec.rb +155 -19
  517. data/spec/unit/transaction/additional_resource_generator_spec.rb +419 -0
  518. data/spec/unit/transaction/event_manager_spec.rb +2 -2
  519. data/spec/unit/transaction/event_spec.rb +57 -0
  520. data/spec/unit/transaction/report_spec.rb +66 -0
  521. data/spec/unit/transaction/resource_harness_spec.rb +27 -20
  522. data/spec/unit/transaction_spec.rb +182 -390
  523. data/spec/unit/type/augeas_spec.rb +3 -3
  524. data/spec/unit/type/component_spec.rb +0 -9
  525. data/spec/unit/type/computer_spec.rb +1 -1
  526. data/spec/unit/type/cron_spec.rb +2 -2
  527. data/spec/unit/type/exec_spec.rb +4 -2
  528. data/spec/unit/type/file/content_spec.rb +11 -0
  529. data/spec/unit/type/file/group_spec.rb +1 -1
  530. data/spec/unit/type/file_spec.rb +16 -8
  531. data/spec/unit/type/mount_spec.rb +445 -259
  532. data/spec/unit/type/package_spec.rb +4 -4
  533. data/spec/unit/type/resources_spec.rb +30 -1
  534. data/spec/unit/type/user_spec.rb +26 -3
  535. data/spec/unit/type/yumrepo_spec.rb +7 -27
  536. data/spec/unit/type/zone_spec.rb +4 -1
  537. data/spec/unit/type_spec.rb +66 -33
  538. data/spec/unit/util/backups_spec.rb +3 -3
  539. data/spec/unit/util/http_proxy_spec.rb +83 -0
  540. data/spec/unit/util/log_spec.rb +79 -8
  541. data/spec/unit/util/metric_spec.rb +12 -0
  542. data/spec/unit/util/monkey_patches_spec.rb +6 -0
  543. data/spec/unit/util/network_device/config_spec.rb +26 -64
  544. data/spec/unit/util/pidlock_spec.rb +4 -1
  545. data/spec/unit/util/tagging_spec.rb +5 -9
  546. data/spec/unit/util/warnings_spec.rb +1 -1
  547. data/spec/unit/util/watched_file_spec.rb +52 -0
  548. data/spec/unit/util/watcher/periodic_watcher_spec.rb +52 -0
  549. data/spec/unit/util/watcher_spec.rb +56 -0
  550. data/spec/unit/util_spec.rb +16 -0
  551. metadata +2767 -2576
  552. data/ext/debian/puppet.manpages +0 -32
  553. data/ext/osx/PackageInfo.plist +0 -36
  554. data/ext/osx/createpackage.sh +0 -187
  555. data/ext/redhat/rundir-perms.patch +0 -28
  556. data/lib/puppet/external/base64.rb +0 -19
  557. data/lib/puppet/util/graph.rb +0 -27
  558. data/lib/puppet/util/loadedfile.rb +0 -61
  559. data/lib/puppet/util/log_paths.rb +0 -22
  560. data/lib/puppet/util/subclass_loader.rb +0 -78
  561. data/spec/monkey_patches/publicize_methods.rb +0 -11
  562. data/spec/unit/util/loadedfile_spec.rb +0 -71
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ require 'puppet/pops'
3
+ require 'puppet_spec/pops'
4
+
5
+ # A Backend class that doesn't implement the needed API
6
+ class Puppet::Pops::Binder::Hiera2::Bad_backend
7
+ end
8
+
9
+ describe 'The hiera2 config' do
10
+
11
+ include PuppetSpec::Pops
12
+
13
+ let(:acceptor) { Puppet::Pops::Validation::Acceptor.new() }
14
+ let(:diag) { Puppet::Pops::Binder::Hiera2::DiagnosticProducer.new(acceptor) }
15
+
16
+ def config_dir(config_name)
17
+ File.dirname(my_fixture("#{config_name}/hiera.yaml"))
18
+ end
19
+
20
+ def test_config_issue(config_name, issue)
21
+ Puppet::Pops::Binder::Hiera2::Config.new(config_dir(config_name), diag)
22
+ acceptor.should have_issue(issue)
23
+ end
24
+
25
+ it 'should load and validate OK configuration' do
26
+ Puppet::Pops::Binder::Hiera2::Config.new(config_dir('ok'), diag)
27
+ acceptor.errors_or_warnings?.should() == false
28
+ end
29
+
30
+ it 'should report missing config file' do
31
+ Puppet::Pops::Binder::Hiera2::Config.new(File.dirname(my_fixture('missing/foo.txt')), diag)
32
+ acceptor.should have_issue(Puppet::Pops::Binder::Hiera2::Issues::CONFIG_FILE_NOT_FOUND)
33
+ end
34
+
35
+ it 'should report when config is not a hash' do
36
+ test_config_issue('not_a_hash', Puppet::Pops::Binder::Hiera2::Issues::CONFIG_IS_NOT_HASH)
37
+ end
38
+
39
+ it 'should report when config has syntax problems' do
40
+ if RUBY_VERSION.start_with?("1.8")
41
+ # Yes, it is a lobotomy or 2 short of a full brain...
42
+ # if a hash key is not in quotes it continues on the next line and gobbles what is there instead
43
+ # of reporting an error
44
+ test_config_issue('bad_syntax', Puppet::Pops::Binder::Hiera2::Issues::MISSING_HIERARCHY)
45
+ else
46
+ test_config_issue('bad_syntax', Puppet::Pops::Binder::Hiera2::Issues::CONFIG_FILE_SYNTAX_ERROR)
47
+ end
48
+ end
49
+
50
+ it 'should report when config has no hierarchy defined' do
51
+ test_config_issue('no_hierarchy', Puppet::Pops::Binder::Hiera2::Issues::MISSING_HIERARCHY)
52
+ end
53
+
54
+ it 'should report when config has no backends defined' do
55
+ test_config_issue('no_backends', Puppet::Pops::Binder::Hiera2::Issues::MISSING_BACKENDS)
56
+ end
57
+
58
+ it 'should report when config hierarchy is malformed' do
59
+ test_config_issue('malformed_hierarchy', Puppet::Pops::Binder::Hiera2::Issues::CATEGORY_MUST_BE_THREE_ELEMENT_ARRAY)
60
+ end
61
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ require 'puppet/pops'
3
+
4
+ describe "Hiera2 YAML backend" do
5
+
6
+ include PuppetSpec::Files
7
+
8
+ def fixture_dir(config_name)
9
+ my_fixture("#{config_name}")
10
+ end
11
+
12
+ before(:all) do
13
+ Puppet[:binder] = true
14
+ require 'puppetx'
15
+ require 'puppet/pops/binder/hiera2/yaml_backend'
16
+ end
17
+
18
+ after(:all) do
19
+ Puppet[:binder] = false
20
+ end
21
+
22
+ it "returns the expected hash from a valid yaml file" do
23
+ Puppet::Pops::Binder::Hiera2::YamlBackend.new().read_data(fixture_dir("ok"), "common").should == {'brillig' => 'slithy'}
24
+ end
25
+
26
+ it "returns an empty hash from an empty yaml file" do
27
+ Puppet::Pops::Binder::Hiera2::YamlBackend.new().read_data(fixture_dir("empty"), "common").should == {}
28
+ end
29
+
30
+ it "returns an empty hash from an invalid yaml file" do
31
+ Puppet::Pops::Binder::Hiera2::YamlBackend.new().read_data(fixture_dir("invalid"), "common").should == {}
32
+ end
33
+ end
@@ -0,0 +1,789 @@
1
+ require 'spec_helper'
2
+ require 'puppet/pops'
3
+
4
+ module InjectorSpecModule
5
+ def injector(binder)
6
+ Puppet::Pops::Binder::Injector.new(binder)
7
+ end
8
+
9
+ def factory
10
+ Puppet::Pops::Binder::BindingsFactory
11
+ end
12
+
13
+ def test_layer_with_empty_bindings
14
+ factory.named_layer('test-layer', factory.named_bindings('test').model)
15
+ end
16
+
17
+ def test_layer_with_bindings(*bindings)
18
+ factory.named_layer('test-layer', *bindings)
19
+ end
20
+
21
+ def null_scope()
22
+ nil
23
+ end
24
+
25
+ def type_calculator
26
+ Puppet::Pops::Types::TypeCalculator
27
+ end
28
+
29
+ def type_factory
30
+ Puppet::Pops::Types::TypeFactory
31
+ end
32
+
33
+ # Returns a binder with the effective categories highest/test, node/kermit, environment/dev (and implicit 'common')
34
+ #
35
+ def binder_with_categories
36
+ b = Puppet::Pops::Binder::Binder.new()
37
+ b.define_categories(factory.categories(['highest', 'test', 'node', 'kermit', 'environment','dev']))
38
+ b
39
+ end
40
+
41
+ class TestDuck
42
+ end
43
+
44
+ class Daffy < TestDuck
45
+ end
46
+
47
+
48
+ class AngryDuck < TestDuck
49
+ # Supports assisted inject, returning a Donald duck as the default impl of Duck
50
+ def self.inject(injector, scope, binding, *args)
51
+ Donald.new()
52
+ end
53
+ end
54
+
55
+ class Donald < AngryDuck
56
+ end
57
+
58
+ class ArneAnka < AngryDuck
59
+ attr_reader :label
60
+
61
+ def initialize()
62
+ @label = 'A Swedish angry cartoon duck'
63
+ end
64
+ end
65
+
66
+ class ScroogeMcDuck < TestDuck
67
+ attr_reader :fortune
68
+
69
+ # Supports assisted inject, returning an ScroogeMcDuck with 1$ fortune or first arg in args
70
+ # Note that when injected (via instance producer, or implict assisted inject, the inject method
71
+ # always wins.
72
+ def self.inject(injector, scope, binding, *args)
73
+ self.new(args[0].nil? ? 1 : args[0])
74
+ end
75
+
76
+ def initialize(fortune)
77
+ @fortune = fortune
78
+ end
79
+ end
80
+
81
+ class NamedDuck < TestDuck
82
+ attr_reader :name
83
+ def initialize(name)
84
+ @name = name
85
+ end
86
+ end
87
+
88
+ # Test custom producer that on each produce returns a duck that is twice as rich as its predecessor
89
+ class ScroogeProducer < Puppet::Pops::Binder::Producers::Producer
90
+ attr_reader :next_capital
91
+ def initialize
92
+ @next_capital = 100
93
+ end
94
+ def produce(scope)
95
+ ScroogeMcDuck.new(@next_capital *= 2)
96
+ end
97
+ end
98
+ end
99
+
100
+ describe 'Injector' do
101
+ include InjectorSpecModule
102
+
103
+ let(:bindings) { factory.named_bindings('test') }
104
+ let(:scope) { null_scope()}
105
+ let(:duck_type) { type_factory.ruby(InjectorSpecModule::TestDuck) }
106
+
107
+ let(:binder) { Puppet::Pops::Binder::Binder.new()}
108
+
109
+ let(:cbinder) do
110
+ b = Puppet::Pops::Binder::Binder.new()
111
+ b.define_categories(factory.categories([]))
112
+ b
113
+ end
114
+
115
+ let(:lbinder) do
116
+ cbinder.define_layers(layered_bindings)
117
+ end
118
+
119
+
120
+ let(:layered_bindings) { factory.layered_bindings(test_layer_with_bindings(bindings.model)) }
121
+ #let(:xinjector) { Puppet::Pops::Binder::Injector.new(lbinder) }
122
+
123
+ context 'When created' do
124
+ it 'should raise an error when given binder is not configured at all' do
125
+ expect { Puppet::Pops::Binder::Injector.new(binder()) }.to raise_error(/Given Binder is not configured/)
126
+ end
127
+
128
+ it 'should raise an error if binder has categories, but is not completely configured' do
129
+ expect { Puppet::Pops::Binder::Injector.new(cbinder) }.to raise_error(/Given Binder is not configured/)
130
+ end
131
+
132
+ it 'should not raise an error if binder is configured' do
133
+ lbinder.configured?().should == true # of something is very wrong
134
+ expect { injector(lbinder) }.to_not raise_error
135
+ end
136
+
137
+ it 'should create an empty injector given an empty binder' do
138
+ expect { cbinder.define_layers(layered_bindings) }.to_not raise_exception
139
+ end
140
+
141
+ it "should be possible to reference the TypeCalculator" do
142
+ injector(lbinder).type_calculator.is_a?(Puppet::Pops::Types::TypeCalculator).should == true
143
+ end
144
+
145
+ it "should be possible to reference the KeyFactory" do
146
+ injector(lbinder).key_factory.is_a?(Puppet::Pops::Binder::KeyFactory).should == true
147
+ end
148
+ end
149
+
150
+ context "When looking up objects" do
151
+ it 'lookup(scope, name) finds bound object of type Data with given name' do
152
+ bindings.bind().name('a_string').to('42')
153
+ injector(lbinder).lookup(scope, 'a_string').should == '42'
154
+ end
155
+
156
+ context 'a block transforming the result can be given' do
157
+ it 'that transform a found value given scope and value' do
158
+ bindings.bind().name('a_string').to('42')
159
+ injector(lbinder).lookup(scope, 'a_string') {|zcope, val| val + '42' }.should == '4242'
160
+ end
161
+
162
+ it 'that transform a found value given only value' do
163
+ bindings.bind().name('a_string').to('42')
164
+ injector(lbinder).lookup(scope, 'a_string') {|val| val + '42' }.should == '4242'
165
+ end
166
+
167
+ it 'that produces a default value when entry is missing' do
168
+ bindings.bind().name('a_string').to('42')
169
+ injector(lbinder).lookup(scope, 'a_non_existing_string') {|val| val ? (raise Error, "Should not happen") : '4242' }.should == '4242'
170
+ end
171
+ end
172
+
173
+ context "and class is not bound" do
174
+ it "assisted inject kicks in for classes with zero args constructor" do
175
+ duck_type = type_factory.ruby(InjectorSpecModule::Daffy)
176
+ injector = injector(lbinder)
177
+ injector.lookup(scope, duck_type).is_a?(InjectorSpecModule::Daffy).should == true
178
+ injector.lookup_producer(scope, duck_type).produce(scope).is_a?(InjectorSpecModule::Daffy).should == true
179
+ end
180
+
181
+ it "assisted inject produces same instance on lookup but not on lookup producer" do
182
+ duck_type = type_factory.ruby(InjectorSpecModule::Daffy)
183
+ injector = injector(lbinder)
184
+ d1 = injector.lookup(scope, duck_type)
185
+ d2 = injector.lookup(scope, duck_type)
186
+ d1.equal?(d2).should == true
187
+
188
+ d1 = injector.lookup_producer(scope, duck_type).produce(scope)
189
+ d2 = injector.lookup_producer(scope, duck_type).produce(scope)
190
+ d1.equal?(d2).should == false
191
+ end
192
+
193
+ it "assisted inject kicks in for classes with a class inject method" do
194
+ duck_type = type_factory.ruby(InjectorSpecModule::ScroogeMcDuck)
195
+ injector = injector(lbinder)
196
+ # Do not pass any arguments, the ScroogeMcDuck :inject method should pick 1 by default
197
+ # This tests zero args passed
198
+ injector.lookup(scope, duck_type).fortune.should == 1
199
+ injector.lookup_producer(scope, duck_type).produce(scope).fortune.should == 1
200
+ end
201
+
202
+ it "assisted inject selects the inject method if it exists over a zero args constructor" do
203
+ injector = injector(lbinder)
204
+ duck_type = type_factory.ruby(InjectorSpecModule::AngryDuck)
205
+ injector.lookup(scope, duck_type).is_a?(InjectorSpecModule::Donald).should == true
206
+ injector.lookup_producer(scope, duck_type).produce(scope).is_a?(InjectorSpecModule::Donald).should == true
207
+ end
208
+
209
+ it "assisted inject selects the zero args constructor if injector is from a superclass" do
210
+ injector = injector(lbinder)
211
+ duck_type = type_factory.ruby(InjectorSpecModule::ArneAnka)
212
+ injector.lookup(scope, duck_type).is_a?(InjectorSpecModule::ArneAnka).should == true
213
+ injector.lookup_producer(scope, duck_type).produce(scope).is_a?(InjectorSpecModule::ArneAnka).should == true
214
+ end
215
+ end
216
+
217
+ context 'and conditionals are in use' do
218
+ let(:binder) { binder_with_categories()}
219
+ let(:lbinder) { binder.define_layers(layered_bindings) }
220
+
221
+ it "should be possible to shadow a bound value in a higher precedented category" do
222
+ bindings.bind().name('a_string').to('42')
223
+ bindings.when_in_category('environment', 'dev').bind().name('a_string').to('43')
224
+ bindings.when_in_category('node', 'kermit').bind().name('a_string').to('being green')
225
+ injector(lbinder).lookup(scope,'a_string').should == 'being green'
226
+ end
227
+
228
+ it "shadowing should not happen when not in a category" do
229
+ bindings.bind().name('a_string').to('42')
230
+ bindings.when_in_category('environment', 'dev').bind().name('a_string').to('43')
231
+ bindings.when_in_category('node', 'piggy').bind().name('a_string').to('being green')
232
+ injector(lbinder).lookup(scope,'a_string').should == '43'
233
+ end
234
+
235
+ it "multiple predicates makes binding more specific" do
236
+ bindings.bind().name('a_string').to('42')
237
+ bindings.when_in_category('environment', 'dev').bind().name('a_string').to('43')
238
+ bindings.when_in_category('node', 'kermit').bind().name('a_string').to('being green')
239
+ bindings.when_in_categories({'node'=>'kermit', 'environment'=>'dev'}).bind().name('a_string').to('being dev green')
240
+ injector(lbinder).lookup(scope,'a_string').should == 'being dev green'
241
+ end
242
+
243
+ it "multiple predicates makes binding more specific, but not more specific than higher precedence" do
244
+ bindings.bind().name('a_string').to('42')
245
+ bindings.when_in_category('environment', 'dev').bind().name('a_string').to('43')
246
+ bindings.when_in_category('node', 'kermit').bind().name('a_string').to('being green')
247
+ bindings.when_in_categories({'node'=>'kermit', 'environment'=>'dev'}).bind().name('a_string').to('being dev green')
248
+ bindings.when_in_category('highest', 'test').bind().name('a_string').to('bazinga')
249
+ injector(lbinder).lookup(scope,'a_string').should == 'bazinga'
250
+ end
251
+ end
252
+
253
+ context "and multiple layers are in use" do
254
+ let(:binder) { binder_with_categories()}
255
+
256
+ it "a higher layer shadows anything in a lower layer" do
257
+ bindings1 = factory.named_bindings('test1')
258
+ bindings1.when_in_category("highest", "test").bind().name('a_string').to('bad stuff')
259
+ lower_layer = factory.named_layer('lower-layer', bindings1.model)
260
+
261
+ bindings2 = factory.named_bindings('test2')
262
+ bindings2.bind().name('a_string').to('good stuff')
263
+ higher_layer = factory.named_layer('higher-layer', bindings2.model)
264
+
265
+ binder.define_layers(factory.layered_bindings(higher_layer, lower_layer))
266
+ injector = injector(binder)
267
+ injector.lookup(scope,'a_string').should == 'good stuff'
268
+ end
269
+ end
270
+
271
+ context "and dealing with Data types" do
272
+ let(:binder) { binder_with_categories()}
273
+ let(:lbinder) { binder.define_layers(layered_bindings) }
274
+
275
+ it "should treat all data as same type w.r.t. key" do
276
+ bindings.bind().name('a_string').to('42')
277
+ bindings.bind().name('an_int').to(43)
278
+ bindings.bind().name('a_float').to(3.14)
279
+ bindings.bind().name('a_boolean').to(true)
280
+ bindings.bind().name('an_array').to([1,2,3])
281
+ bindings.bind().name('a_hash').to({'a'=>1,'b'=>2,'c'=>3})
282
+
283
+ injector = injector(lbinder)
284
+ injector.lookup(scope,'a_string').should == '42'
285
+ injector.lookup(scope,'an_int').should == 43
286
+ injector.lookup(scope,'a_float').should == 3.14
287
+ injector.lookup(scope,'a_boolean').should == true
288
+ injector.lookup(scope,'an_array').should == [1,2,3]
289
+ injector.lookup(scope,'a_hash').should == {'a'=>1,'b'=>2,'c'=>3}
290
+ end
291
+
292
+ it "should provide type-safe lookup of given type/name" do
293
+ bindings.bind().string().name('a_string').to('42')
294
+ bindings.bind().integer().name('an_int').to(43)
295
+ bindings.bind().float().name('a_float').to(3.14)
296
+ bindings.bind().boolean().name('a_boolean').to(true)
297
+ bindings.bind().array_of_data().name('an_array').to([1,2,3])
298
+ bindings.bind().hash_of_data().name('a_hash').to({'a'=>1,'b'=>2,'c'=>3})
299
+
300
+ injector = injector(lbinder)
301
+
302
+ # Check lookup using implied Data type
303
+ injector.lookup(scope,'a_string').should == '42'
304
+ injector.lookup(scope,'an_int').should == 43
305
+ injector.lookup(scope,'a_float').should == 3.14
306
+ injector.lookup(scope,'a_boolean').should == true
307
+ injector.lookup(scope,'an_array').should == [1,2,3]
308
+ injector.lookup(scope,'a_hash').should == {'a'=>1,'b'=>2,'c'=>3}
309
+
310
+ # Check lookup using expected type
311
+ injector.lookup(scope,type_factory.string(), 'a_string').should == '42'
312
+ injector.lookup(scope,type_factory.integer(), 'an_int').should == 43
313
+ injector.lookup(scope,type_factory.float(),'a_float').should == 3.14
314
+ injector.lookup(scope,type_factory.boolean(),'a_boolean').should == true
315
+ injector.lookup(scope,type_factory.array_of_data(),'an_array').should == [1,2,3]
316
+ injector.lookup(scope,type_factory.hash_of_data(),'a_hash').should == {'a'=>1,'b'=>2,'c'=>3}
317
+
318
+ # Check lookup using wrong type
319
+ expect { injector.lookup(scope,type_factory.integer(), 'a_string')}.to raise_error(/Type error/)
320
+ expect { injector.lookup(scope,type_factory.string(), 'an_int')}.to raise_error(/Type error/)
321
+ expect { injector.lookup(scope,type_factory.string(),'a_float')}.to raise_error(/Type error/)
322
+ expect { injector.lookup(scope,type_factory.string(),'a_boolean')}.to raise_error(/Type error/)
323
+ expect { injector.lookup(scope,type_factory.string(),'an_array')}.to raise_error(/Type error/)
324
+ expect { injector.lookup(scope,type_factory.string(),'a_hash')}.to raise_error(/Type error/)
325
+ end
326
+ end
327
+ end
328
+
329
+ context "When looking up producer" do
330
+ it 'the value is produced by calling produce(scope)' do
331
+ bindings.bind().name('a_string').to('42')
332
+ injector(lbinder).lookup_producer(scope, 'a_string').produce(scope).should == '42'
333
+ end
334
+
335
+ context 'a block transforming the result can be given' do
336
+ it 'that transform a found value given scope and producer' do
337
+ bindings.bind().name('a_string').to('42')
338
+ injector(lbinder).lookup_producer(scope, 'a_string') {|zcope, p| p.produce(zcope) + '42' }.should == '4242'
339
+ end
340
+
341
+ it 'that transform a found value given only producer' do
342
+ bindings.bind().name('a_string').to('42')
343
+ injector(lbinder).lookup_producer(scope, 'a_string') {|p| p.produce(scope) + '42' }.should == '4242'
344
+ end
345
+
346
+ it 'that can produce a default value when entry is not found' do
347
+ bindings.bind().name('a_string').to('42')
348
+ injector(lbinder).lookup_producer(scope, 'a_non_existing_string') {|p| p ? (raise Error,"Should not happen") : '4242' }.should == '4242'
349
+ end
350
+ end
351
+ end
352
+
353
+ context "When dealing with singleton vs. non singleton" do
354
+ it "should produce the same instance when producer is a singleton" do
355
+ bindings.bind().name('a_string').to('42')
356
+ injector = injector(lbinder)
357
+ a = injector.lookup(scope, 'a_string')
358
+ b = injector.lookup(scope, 'a_string')
359
+ a.equal?(b).should == true
360
+ end
361
+
362
+ it "should produce different instances when producer is a non singleton producer" do
363
+ bindings.bind().name('a_string').to_series_of('42')
364
+ injector = injector(lbinder)
365
+ a = injector.lookup(scope, 'a_string')
366
+ b = injector.lookup(scope, 'a_string')
367
+ a.should == '42'
368
+ b.should == '42'
369
+ a.equal?(b).should == false
370
+ end
371
+ end
372
+
373
+ context "When using the lookup producer" do
374
+ it "should lookup again to produce a value" do
375
+ bindings.bind().name('a_string').to_lookup_of('another_string')
376
+ bindings.bind().name('another_string').to('hello')
377
+ injector(lbinder).lookup(scope, 'a_string').should == 'hello'
378
+ end
379
+
380
+ it "should produce nil if looked up key does not exist" do
381
+ bindings.bind().name('a_string').to_lookup_of('non_existing')
382
+ injector(lbinder).lookup(scope, 'a_string').should == nil
383
+ end
384
+
385
+ it "should report an error if lookup loop is detected" do
386
+ bindings.bind().name('a_string').to_lookup_of('a_string')
387
+ expect { injector(lbinder).lookup(scope, 'a_string') }.to raise_error(/Lookup loop/)
388
+ end
389
+ end
390
+
391
+ context "When using the hash lookup producer" do
392
+ it "should lookup a key in looked up hash" do
393
+ data_hash = type_factory.hash_of_data()
394
+ bindings.bind().name('a_string').to_hash_lookup_of(data_hash, 'a_hash', 'huey')
395
+ bindings.bind().name('a_hash').to({'huey' => 'red', 'dewey' => 'blue', 'louie' => 'green'})
396
+ injector(lbinder).lookup(scope, 'a_string').should == 'red'
397
+ end
398
+
399
+ it "should produce nil if looked up entry does not exist" do
400
+ data_hash = type_factory.hash_of_data()
401
+ bindings.bind().name('a_string').to_hash_lookup_of(data_hash, 'non_existing_entry', 'huey')
402
+ bindings.bind().name('a_hash').to({'huey' => 'red', 'dewey' => 'blue', 'louie' => 'green'})
403
+ injector(lbinder).lookup(scope, 'a_string').should == nil
404
+ end
405
+ end
406
+
407
+ context "When using the first found producer" do
408
+ it "should lookup until it finds a value, but not further" do
409
+ bindings.bind().name('a_string').to_first_found('b_string', 'c_string', 'g_string')
410
+ bindings.bind().name('c_string').to('hello')
411
+ bindings.bind().name('g_string').to('Oh, mrs. Smith...')
412
+ injector(lbinder).lookup(scope, 'a_string').should == 'hello'
413
+ end
414
+
415
+ it "should lookup until it finds a value using mix of type and name, but not further" do
416
+ bindings.bind().name('a_string').to_first_found('b_string', [type_factory.string, 'c_string'], 'g_string')
417
+ bindings.bind().name('c_string').to('hello')
418
+ bindings.bind().name('g_string').to('Oh, mrs. Smith...')
419
+ injector(lbinder).lookup(scope, 'a_string').should == 'hello'
420
+ end
421
+ end
422
+
423
+ context "When producing instances" do
424
+ it "should lookup an instance of a class without arguments" do
425
+ bindings.bind().type(duck_type).name('the_duck').to(InjectorSpecModule::Daffy)
426
+ injector(lbinder).lookup(scope, duck_type, 'the_duck').is_a?(InjectorSpecModule::Daffy).should == true
427
+ end
428
+
429
+ it "should lookup an instance of a class with arguments" do
430
+ bindings.bind().type(duck_type).name('the_duck').to(InjectorSpecModule::ScroogeMcDuck, 1234)
431
+ injector = injector(lbinder)
432
+
433
+ the_duck = injector.lookup(scope, duck_type, 'the_duck')
434
+ the_duck.is_a?(InjectorSpecModule::ScroogeMcDuck).should == true
435
+ the_duck.fortune.should == 1234
436
+ end
437
+
438
+ it "singleton producer should not be recreated between lookups" do
439
+ bindings.bind().type(duck_type).name('the_duck').to_producer(InjectorSpecModule::ScroogeProducer)
440
+ injector = injector(lbinder)
441
+
442
+ the_duck = injector.lookup(scope, duck_type, 'the_duck')
443
+ the_duck.is_a?(InjectorSpecModule::ScroogeMcDuck).should == true
444
+ the_duck.fortune.should == 200
445
+
446
+ # singleton, do it again to get next value in series - it is the producer that is a singleton
447
+ # not the produced value
448
+ the_duck = injector.lookup(scope, duck_type, 'the_duck')
449
+ the_duck.is_a?(InjectorSpecModule::ScroogeMcDuck).should == true
450
+ the_duck.fortune.should == 400
451
+
452
+ duck_producer = injector.lookup_producer(scope, duck_type, 'the_duck')
453
+ duck_producer.produce(scope).fortune.should == 800
454
+ end
455
+
456
+ it "series of producers should recreate producer on each lookup and lookup_producer" do
457
+ bindings.bind().type(duck_type).name('the_duck').to_producer_series(InjectorSpecModule::ScroogeProducer)
458
+ injector = injector(lbinder)
459
+
460
+ duck_producer = injector.lookup_producer(scope, duck_type, 'the_duck')
461
+ duck_producer.produce(scope).fortune().should == 200
462
+ duck_producer.produce(scope).fortune().should == 400
463
+
464
+ # series, each lookup gets a new producer (initialized to produce 200)
465
+ duck_producer = injector.lookup_producer(scope, duck_type, 'the_duck')
466
+ duck_producer.produce(scope).fortune().should == 200
467
+ duck_producer.produce(scope).fortune().should == 400
468
+
469
+ injector.lookup(scope, duck_type, 'the_duck').fortune().should == 200
470
+ injector.lookup(scope, duck_type, 'the_duck').fortune().should == 200
471
+ end
472
+ end
473
+
474
+ context "When working with multibind" do
475
+ context "of hash kind" do
476
+ it "a multibind produces contributed items keyed by their bound key-name" do
477
+ hash_of_duck = type_factory.hash_of(duck_type)
478
+ multibind_id = "ducks"
479
+
480
+ bindings.multibind(multibind_id).type(hash_of_duck).name('donalds_nephews')
481
+ bindings.bind.in_multibind(multibind_id).type(duck_type).name('nephew1').to(InjectorSpecModule::NamedDuck, 'Huey')
482
+ bindings.bind.in_multibind(multibind_id).type(duck_type).name('nephew2').to(InjectorSpecModule::NamedDuck, 'Dewey')
483
+ bindings.bind.in_multibind(multibind_id).type(duck_type).name('nephew3').to(InjectorSpecModule::NamedDuck, 'Louie')
484
+
485
+ injector = injector(lbinder)
486
+ the_ducks = injector.lookup(scope, hash_of_duck, "donalds_nephews")
487
+ the_ducks.size.should == 3
488
+ the_ducks['nephew1'].name.should == 'Huey'
489
+ the_ducks['nephew2'].name.should == 'Dewey'
490
+ the_ducks['nephew3'].name.should == 'Louie'
491
+ end
492
+
493
+ it "is an error to not bind contribution with a name" do
494
+ hash_of_duck = type_factory.hash_of(duck_type)
495
+ multibind_id = "ducks"
496
+
497
+ bindings.multibind(multibind_id).type(hash_of_duck).name('donalds_nephews')
498
+ # missing name
499
+ bindings.bind.in_multibind(multibind_id).type(duck_type).to(InjectorSpecModule::NamedDuck, 'Huey')
500
+ bindings.bind.in_multibind(multibind_id).type(duck_type).to(InjectorSpecModule::NamedDuck, 'Dewey')
501
+
502
+ expect {
503
+ the_ducks = injector(lbinder).lookup(scope, hash_of_duck, "donalds_nephews")
504
+ }.to raise_error(/must have a name/)
505
+ end
506
+
507
+ it "is an error to bind with duplicate key when using default (priority) conflict resolution" do
508
+ hash_of_duck = type_factory.hash_of(duck_type)
509
+ multibind_id = "ducks"
510
+
511
+ bindings.multibind(multibind_id).type(hash_of_duck).name('donalds_nephews')
512
+ # missing name
513
+ bindings.bind.in_multibind(multibind_id).type(duck_type).name('foo').to(InjectorSpecModule::NamedDuck, 'Huey')
514
+ bindings.bind.in_multibind(multibind_id).type(duck_type).name('foo').to(InjectorSpecModule::NamedDuck, 'Dewey')
515
+
516
+ expect {
517
+ the_ducks = injector(lbinder).lookup(scope, hash_of_duck, "donalds_nephews")
518
+ }.to raise_error(/Duplicate key/)
519
+ end
520
+
521
+ it "is not an error to bind with duplicate key when using (ignore) conflict resolution" do
522
+ hash_of_duck = type_factory.hash_of(duck_type)
523
+ multibind_id = "ducks"
524
+
525
+ bindings.multibind(multibind_id).type(hash_of_duck).name('donalds_nephews').producer_options(:conflict_resolution => :ignore)
526
+ bindings.bind.in_multibind(multibind_id).type(duck_type).name('foo').to(InjectorSpecModule::NamedDuck, 'Huey')
527
+ bindings.bind.in_multibind(multibind_id).type(duck_type).name('foo').to(InjectorSpecModule::NamedDuck, 'Dewey')
528
+
529
+ expect {
530
+ the_ducks = injector(lbinder).lookup(scope, hash_of_duck, "donalds_nephews")
531
+ }.to_not raise_error(/Duplicate key/)
532
+ end
533
+
534
+ it "should produce detailed type error message" do
535
+ hash_of_integer = type_factory.hash_of(type_factory.integer())
536
+
537
+ multibind_id = "ints"
538
+ mb = bindings.multibind(multibind_id).type(hash_of_integer).name('donalds_family')
539
+ bindings.bind.in_multibind(multibind_id).name('nephew').to('Huey')
540
+
541
+ expect { ducks = injector(lbinder).lookup(scope, 'donalds_family')
542
+ }.to raise_error(%r{expected: Integer, got: String})
543
+ end
544
+
545
+ it "should be possible to combine hash multibind contributions with append on conflict" do
546
+ # This case uses a multibind of individual strings, but combines them
547
+ # into an array bound to a hash key
548
+ # (There are other ways to do this - e.g. have the multibind lookup a multibind
549
+ # of array type to which nephews are contributed).
550
+ #
551
+ hash_of_data = type_factory.hash_of_data()
552
+ multibind_id = "ducks"
553
+ mb = bindings.multibind(multibind_id).type(hash_of_data).name('donalds_family')
554
+ mb.producer_options(:conflict_resolution => :append)
555
+
556
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Huey')
557
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Dewey')
558
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Louie')
559
+ bindings.bind.in_multibind(multibind_id).name('uncles').to('Scrooge McDuck')
560
+ bindings.bind.in_multibind(multibind_id).name('uncles').to('Ludwig Von Drake')
561
+
562
+ ducks = injector(lbinder).lookup(scope, 'donalds_family')
563
+
564
+ ducks['nephews'].should == ['Huey', 'Dewey', 'Louie']
565
+ ducks['uncles'].should == ['Scrooge McDuck', 'Ludwig Von Drake']
566
+ end
567
+
568
+ it "should be possible to combine hash multibind contributions with append, flat, and uniq, on conflict" do
569
+ # This case uses a multibind of individual strings, but combines them
570
+ # into an array bound to a hash key
571
+ # (There are other ways to do this - e.g. have the multibind lookup a multibind
572
+ # of array type to which nephews are contributed).
573
+ #
574
+ hash_of_data = type_factory.hash_of_data()
575
+ multibind_id = "ducks"
576
+ mb = bindings.multibind(multibind_id).type(hash_of_data).name('donalds_family')
577
+ mb.producer_options(:conflict_resolution => :append, :flatten => true, :uniq => true)
578
+
579
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Huey')
580
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Huey')
581
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Dewey')
582
+ bindings.bind.in_multibind(multibind_id).name('nephews').to(['Huey', ['Louie'], 'Dewey'])
583
+ bindings.bind.in_multibind(multibind_id).name('uncles').to('Scrooge McDuck')
584
+ bindings.bind.in_multibind(multibind_id).name('uncles').to('Ludwig Von Drake')
585
+
586
+ ducks = injector(lbinder).lookup(scope, 'donalds_family')
587
+
588
+ ducks['nephews'].should == ['Huey', 'Dewey', 'Louie']
589
+ ducks['uncles'].should == ['Scrooge McDuck', 'Ludwig Von Drake']
590
+ end
591
+
592
+ it "should fail attempts to append, perform uniq or flatten on type incompatible multibind hash" do
593
+ hash_of_integer = type_factory.hash_of(type_factory.integer())
594
+ ids = ["ducks1", "ducks2", "ducks3"]
595
+ mb = bindings.multibind(ids[0]).type(hash_of_integer).name('broken_family0')
596
+ mb.producer_options(:conflict_resolution => :append)
597
+ mb = bindings.multibind(ids[1]).type(hash_of_integer).name('broken_family1')
598
+ mb.producer_options(:flatten => :true)
599
+ mb = bindings.multibind(ids[2]).type(hash_of_integer).name('broken_family2')
600
+ mb.producer_options(:uniq => :true)
601
+
602
+
603
+ binder.define_categories(factory.categories([]))
604
+ binder.define_layers(factory.layered_bindings(test_layer_with_bindings(bindings.model)))
605
+ injector = injector(binder)
606
+ expect { injector.lookup(scope, 'broken_family0')}.to raise_error(/:conflict_resolution => :append/)
607
+ expect { injector.lookup(scope, 'broken_family1')}.to raise_error(/:flatten/)
608
+ expect { injector.lookup(scope, 'broken_family2')}.to raise_error(/:uniq/)
609
+ end
610
+
611
+ it "a higher priority contribution is selected when resolution is :priority" do
612
+ hash_of_duck = type_factory.hash_of(duck_type)
613
+ multibind_id = "ducks"
614
+
615
+ bindings.multibind(multibind_id).type(hash_of_duck).name('donalds_nephews')
616
+
617
+ mb1 = bindings.when_in_category("highest", "test").bind.in_multibind(multibind_id)
618
+ mb1.type(duck_type).name('nephew').to(InjectorSpecModule::NamedDuck, 'Huey')
619
+
620
+ mb2 = bindings.bind.in_multibind(multibind_id)
621
+ mb2.type(duck_type).name('nephew').to(InjectorSpecModule::NamedDuck, 'Dewey')
622
+
623
+ binder.define_categories(factory.categories(['highest', 'test']))
624
+ binder.define_layers(layered_bindings)
625
+
626
+ injector(binder).lookup(scope, hash_of_duck, "donalds_nephews")['nephew'].name.should == 'Huey'
627
+ end
628
+
629
+ it "a higher priority contribution wins when resolution is :merge" do
630
+ hash_of_data = type_factory.hash_of_data()
631
+ multibind_id = "hashed_ducks"
632
+
633
+ bindings.multibind(multibind_id).type(hash_of_data).name('donalds_nephews').producer_options(:conflict_resolution => :merge)
634
+
635
+ mb1 = bindings.when_in_category("highest", "test").bind.in_multibind(multibind_id)
636
+ mb1.name('nephew').to({'name' => 'Huey', 'is' => 'winner'})
637
+
638
+ mb2 = bindings.bind.in_multibind(multibind_id)
639
+ mb2.name('nephew').to({'name' => 'Dewey', 'is' => 'looser', 'has' => 'cap'})
640
+
641
+ binder.define_categories(factory.categories(['highest', 'test']))
642
+ binder.define_layers(layered_bindings)
643
+
644
+ the_ducks = injector(binder).lookup(scope, "donalds_nephews");
645
+ the_ducks['nephew']['name'].should == 'Huey'
646
+ the_ducks['nephew']['is'].should == 'winner'
647
+ the_ducks['nephew']['has'].should == 'cap'
648
+ end
649
+ end
650
+
651
+ context "of array kind" do
652
+ it "an array multibind produces contributed items, names are allowed but ignored" do
653
+ array_of_duck = type_factory.array_of(duck_type)
654
+ multibind_id = "ducks"
655
+
656
+ bindings.multibind(multibind_id).type(array_of_duck).name('donalds_nephews')
657
+ # one with name (ignored, expect no error)
658
+ bindings.bind.in_multibind(multibind_id).type(duck_type).name('nephew1').to(InjectorSpecModule::NamedDuck, 'Huey')
659
+ # two without name
660
+ bindings.bind.in_multibind(multibind_id).type(duck_type).to(InjectorSpecModule::NamedDuck, 'Dewey')
661
+ bindings.bind.in_multibind(multibind_id).type(duck_type).to(InjectorSpecModule::NamedDuck, 'Louie')
662
+
663
+ the_ducks = injector(lbinder).lookup(scope, array_of_duck, "donalds_nephews")
664
+ the_ducks.size.should == 3
665
+ the_ducks.collect {|d| d.name }.sort.should == ['Dewey', 'Huey', 'Louie']
666
+ end
667
+
668
+ it "should be able to make result contain only unique entries" do
669
+ # This case uses a multibind of individual strings, and combines them
670
+ # into an array of unique values
671
+ #
672
+ array_of_data = type_factory.array_of_data()
673
+ multibind_id = "ducks"
674
+ mb = bindings.multibind(multibind_id).type(array_of_data).name('donalds_family')
675
+ # turn off priority on named to not trigger conflict as all additions have the same precedence
676
+ # (could have used the default for unnamed and add unnamed entries).
677
+ mb.producer_options(:priority_on_named => false, :uniq => true)
678
+
679
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Huey')
680
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Dewey')
681
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Dewey') # duplicate
682
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Louie')
683
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Louie') # duplicate
684
+ bindings.bind.in_multibind(multibind_id).name('nephews').to('Louie') # duplicate
685
+
686
+ ducks = injector(lbinder).lookup(scope, 'donalds_family')
687
+ ducks.should == ['Huey', 'Dewey', 'Louie']
688
+ end
689
+
690
+ it "should be able to contribute elements and arrays of elements and flatten 1 level" do
691
+ # This case uses a multibind of individual strings and arrays, and combines them
692
+ # into an array of flattened
693
+ #
694
+ array_of_string = type_factory.array_of(type_factory.string())
695
+
696
+ multibind_id = "ducks"
697
+ mb = bindings.multibind(multibind_id).type(array_of_string).name('donalds_family')
698
+ # flatten one level
699
+ mb.producer_options(:flatten => 1)
700
+
701
+ bindings.bind.in_multibind(multibind_id).to('Huey')
702
+ bindings.bind.in_multibind(multibind_id).to('Dewey')
703
+ bindings.bind.in_multibind(multibind_id).to('Louie') # duplicate
704
+ bindings.bind.in_multibind(multibind_id).to(['Huey', 'Dewey', 'Louie'])
705
+
706
+ ducks = injector(lbinder).lookup(scope, 'donalds_family')
707
+ ducks.should == ['Huey', 'Dewey', 'Louie', 'Huey', 'Dewey', 'Louie']
708
+ end
709
+
710
+ it "should produce detailed type error message" do
711
+ array_of_integer = type_factory.array_of(type_factory.integer())
712
+
713
+ multibind_id = "ints"
714
+ mb = bindings.multibind(multibind_id).type(array_of_integer).name('donalds_family')
715
+ bindings.bind.in_multibind(multibind_id).to('Huey')
716
+
717
+ expect { ducks = injector(lbinder).lookup(scope, 'donalds_family')
718
+ }.to raise_error(%r{expected: Integer, or Array\[Integer\], got: String})
719
+ end
720
+ end
721
+
722
+ context "When using multibind in multibind" do
723
+ it "a hash multibind can be contributed to another" do
724
+ hash_of_data = type_factory.hash_of_data()
725
+ mb1_id = 'data1'
726
+ mb2_id = 'data2'
727
+ top = bindings.multibind(mb1_id).type(hash_of_data).name("top")
728
+ detail = bindings.multibind(mb2_id).type(hash_of_data).name("detail").in_multibind(mb1_id)
729
+
730
+ bindings.bind.in_multibind(mb1_id).name('a').to(10)
731
+ bindings.bind.in_multibind(mb1_id).name('b').to(20)
732
+ bindings.bind.in_multibind(mb2_id).name('a').to(30)
733
+ bindings.bind.in_multibind(mb2_id).name('b').to(40)
734
+ expect( injector(lbinder).lookup(scope, "top") ).to eql({'detail' => {'a' => 30, 'b' => 40}, 'a' => 10, 'b' => 20})
735
+ end
736
+ end
737
+
738
+ context "When looking up entries requiring evaluation" do
739
+ let(:node) { Puppet::Node.new('localhost') }
740
+ let(:compiler) { Puppet::Parser::Compiler.new(node)}
741
+ let(:scope) { Puppet::Parser::Scope.new(compiler) }
742
+ let(:parser) { Puppet::Pops::Parser::Parser.new() }
743
+
744
+ it "should be possible to lookup a concatenated string" do
745
+ scope['duck'] = 'Donald Fauntleroy Duck'
746
+ expr = parser.parse_string('"Hello $duck"').current()
747
+ bindings.bind.name('the_duck').to(expr)
748
+ injector(lbinder).lookup(scope, 'the_duck').should == 'Hello Donald Fauntleroy Duck'
749
+ end
750
+
751
+ it "should be possible to post process lookup with a puppet lambda" do
752
+ model = parser.parse_string('fake() |$value| {$value + 1 }').current
753
+ bindings.bind.name('an_int').to(42).producer_options( :transformer => model.lambda)
754
+ injector(lbinder).lookup(scope, 'an_int').should == 43
755
+ end
756
+
757
+ it "should be possible to post process lookup with a ruby proc" do
758
+ transformer = lambda {|scope, value| value + 1 }
759
+ bindings.bind.name('an_int').to(42).producer_options( :transformer => transformer)
760
+ injector(lbinder).lookup(scope, 'an_int').should == 43
761
+ end
762
+ end
763
+ end
764
+ context "When there are problems with configuration" do
765
+ let(:binder) { binder_with_categories()}
766
+ let(:lbinder) { binder.define_layers(layered_bindings) }
767
+
768
+ it "reports error for surfacing abstract bindings" do
769
+ bindings.bind.abstract.name('an_int')
770
+ expect{injector(lbinder).lookup(scope, 'an_int') }.to raise_error(/The abstract binding .* was not overridden/)
771
+ end
772
+
773
+ it "does not report error for abstract binding that is ovrridden" do
774
+ bindings.bind.abstract.name('an_int')
775
+ bindings.when_in_category('highest', 'test').bind.override.name('an_int').to(142)
776
+ expect{injector(lbinder).lookup(scope, 'an_int') }.to_not raise_error
777
+ end
778
+
779
+ it "reports error for overriding binding that does not override" do
780
+ bindings.bind.override.name('an_int').to(42)
781
+ expect{injector(lbinder).lookup(scope, 'an_int') }.to raise_error(/Binding with unresolved 'override' detected/)
782
+ end
783
+
784
+ it "reports error for binding without producer" do
785
+ bindings.bind.name('an_int')
786
+ expect{injector(lbinder).lookup(scope, 'an_int') }.to raise_error(/Binding without producer/)
787
+ end
788
+ end
789
+ end