chefspec 3.1.4 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (532) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -0
  3. data/.travis.yml +39 -0
  4. data/CHANGELOG.md +444 -0
  5. data/CONTRIBUTING.md +52 -0
  6. data/Gemfile +2 -0
  7. data/ISSUES.md +41 -0
  8. data/LICENSE +22 -0
  9. data/README.md +893 -0
  10. data/Rakefile +29 -0
  11. data/chefspec.gemspec +42 -0
  12. data/examples/apt_package/recipes/install.rb +13 -0
  13. data/examples/apt_package/recipes/purge.rb +13 -0
  14. data/examples/apt_package/recipes/reconfig.rb +13 -0
  15. data/examples/apt_package/recipes/remove.rb +13 -0
  16. data/examples/apt_package/recipes/upgrade.rb +13 -0
  17. data/examples/apt_package/spec/install_spec.rb +23 -0
  18. data/examples/apt_package/spec/purge_spec.rb +19 -0
  19. data/examples/apt_package/spec/reconfig_spec.rb +19 -0
  20. data/examples/apt_package/spec/remove_spec.rb +19 -0
  21. data/examples/apt_package/spec/upgrade_spec.rb +19 -0
  22. data/examples/attributes/attributes/default.rb +1 -0
  23. data/examples/attributes/recipes/default.rb +4 -0
  24. data/examples/attributes/spec/default_spec.rb +20 -0
  25. data/examples/batch/recipes/run.rb +13 -0
  26. data/examples/batch/spec/run_spec.rb +23 -0
  27. data/examples/cached/recipes/default.rb +1 -0
  28. data/examples/cached/spec/default_spec.rb +13 -0
  29. data/examples/chef_gem/recipes/install.rb +13 -0
  30. data/examples/chef_gem/recipes/purge.rb +13 -0
  31. data/examples/chef_gem/recipes/reconfig.rb +13 -0
  32. data/examples/chef_gem/recipes/remove.rb +13 -0
  33. data/examples/chef_gem/recipes/upgrade.rb +13 -0
  34. data/examples/chef_gem/spec/install_spec.rb +23 -0
  35. data/examples/chef_gem/spec/purge_spec.rb +19 -0
  36. data/examples/chef_gem/spec/reconfig_spec.rb +19 -0
  37. data/examples/chef_gem/spec/remove_spec.rb +19 -0
  38. data/examples/chef_gem/spec/upgrade_spec.rb +19 -0
  39. data/examples/compile_time/recipes/default.rb +3 -0
  40. data/examples/compile_time/spec/default_spec.rb +27 -0
  41. data/examples/cookbook_file/recipes/create.rb +15 -0
  42. data/examples/cookbook_file/recipes/create_if_missing.rb +15 -0
  43. data/examples/cookbook_file/recipes/delete.rb +15 -0
  44. data/examples/cookbook_file/recipes/touch.rb +15 -0
  45. data/examples/cookbook_file/spec/create_if_missing_spec.rb +28 -0
  46. data/examples/cookbook_file/spec/create_spec.rb +32 -0
  47. data/examples/cookbook_file/spec/delete_spec.rb +19 -0
  48. data/examples/cookbook_file/spec/touch_spec.rb +19 -0
  49. data/examples/cron/recipes/create.rb +10 -0
  50. data/examples/cron/recipes/delete.rb +9 -0
  51. data/examples/cron/spec/create_spec.rb +19 -0
  52. data/examples/cron/spec/delete_spec.rb +15 -0
  53. data/examples/custom_matcher/libraries/matcher.rb +23 -0
  54. data/examples/custom_matcher/providers/thing.rb +2 -0
  55. data/examples/custom_matcher/recipes/install.rb +13 -0
  56. data/examples/custom_matcher/recipes/remove.rb +13 -0
  57. data/examples/custom_matcher/resources/thing.rb +5 -0
  58. data/examples/custom_matcher/spec/install_spec.rb +27 -0
  59. data/examples/custom_matcher/spec/remove_spec.rb +23 -0
  60. data/examples/deploy/recipes/deploy.rb +10 -0
  61. data/examples/deploy/recipes/force_deploy.rb +9 -0
  62. data/examples/deploy/recipes/rollback.rb +9 -0
  63. data/examples/deploy/spec/deploy_spec.rb +15 -0
  64. data/examples/deploy/spec/force_deploy_spec.rb +15 -0
  65. data/examples/deploy/spec/rollback_spec.rb +15 -0
  66. data/examples/directory/recipes/create.rb +14 -0
  67. data/examples/directory/recipes/delete.rb +14 -0
  68. data/examples/directory/spec/create_spec.rb +30 -0
  69. data/examples/directory/spec/delete_spec.rb +26 -0
  70. data/examples/dpkg_package/recipes/install.rb +13 -0
  71. data/examples/dpkg_package/recipes/purge.rb +13 -0
  72. data/examples/dpkg_package/recipes/remove.rb +13 -0
  73. data/examples/dpkg_package/spec/install_spec.rb +23 -0
  74. data/examples/dpkg_package/spec/purge_spec.rb +19 -0
  75. data/examples/dpkg_package/spec/remove_spec.rb +19 -0
  76. data/examples/easy_install_package/recipes/install.rb +13 -0
  77. data/examples/easy_install_package/recipes/purge.rb +13 -0
  78. data/examples/easy_install_package/recipes/remove.rb +13 -0
  79. data/examples/easy_install_package/recipes/upgrade.rb +13 -0
  80. data/examples/easy_install_package/spec/install_spec.rb +23 -0
  81. data/examples/easy_install_package/spec/purge_spec.rb +19 -0
  82. data/examples/easy_install_package/spec/remove_spec.rb +19 -0
  83. data/examples/easy_install_package/spec/upgrade_spec.rb +19 -0
  84. data/examples/env/recipes/create.rb +13 -0
  85. data/examples/env/recipes/delete.rb +13 -0
  86. data/examples/env/recipes/modify.rb +13 -0
  87. data/examples/env/spec/create_spec.rb +23 -0
  88. data/examples/env/spec/delete_spec.rb +19 -0
  89. data/examples/env/spec/modify_spec.rb +19 -0
  90. data/examples/erl_call/recipes/run.rb +13 -0
  91. data/examples/erl_call/spec/run_spec.rb +23 -0
  92. data/examples/execute/recipes/run.rb +13 -0
  93. data/examples/execute/spec/run_spec.rb +23 -0
  94. data/examples/expect_exception/recipes/compile_error.rb +1 -0
  95. data/examples/expect_exception/recipes/converge_error.rb +5 -0
  96. data/examples/expect_exception/recipes/no_error.rb +1 -0
  97. data/examples/expect_exception/spec/compile_error_spec.rb +10 -0
  98. data/examples/expect_exception/spec/converge_error_spec.rb +10 -0
  99. data/examples/expect_exception/spec/no_error_spec.rb +10 -0
  100. data/examples/file/recipes/create.rb +15 -0
  101. data/examples/file/recipes/create_if_missing.rb +15 -0
  102. data/examples/file/recipes/delete.rb +15 -0
  103. data/examples/file/recipes/touch.rb +15 -0
  104. data/examples/file/spec/create_if_missing_spec.rb +28 -0
  105. data/examples/file/spec/create_spec.rb +32 -0
  106. data/examples/file/spec/delete_spec.rb +19 -0
  107. data/examples/file/spec/touch_spec.rb +19 -0
  108. data/examples/freebsd_package/recipes/install.rb +13 -0
  109. data/examples/freebsd_package/recipes/remove.rb +13 -0
  110. data/examples/freebsd_package/spec/install_spec.rb +23 -0
  111. data/examples/freebsd_package/spec/remove_spec.rb +19 -0
  112. data/examples/gem_package/recipes/install.rb +13 -0
  113. data/examples/gem_package/recipes/purge.rb +13 -0
  114. data/examples/gem_package/recipes/reconfig.rb +13 -0
  115. data/examples/gem_package/recipes/remove.rb +13 -0
  116. data/examples/gem_package/recipes/upgrade.rb +13 -0
  117. data/examples/gem_package/spec/install_spec.rb +23 -0
  118. data/examples/gem_package/spec/purge_spec.rb +19 -0
  119. data/examples/gem_package/spec/reconfig_spec.rb +19 -0
  120. data/examples/gem_package/spec/remove_spec.rb +19 -0
  121. data/examples/gem_package/spec/upgrade_spec.rb +19 -0
  122. data/examples/git/recipes/checkout.rb +13 -0
  123. data/examples/git/recipes/export.rb +13 -0
  124. data/examples/git/recipes/sync.rb +13 -0
  125. data/examples/git/spec/checkout_spec.rb +19 -0
  126. data/examples/git/spec/export_spec.rb +19 -0
  127. data/examples/git/spec/sync_spec.rb +23 -0
  128. data/examples/group/recipes/create.rb +13 -0
  129. data/examples/group/recipes/manage.rb +13 -0
  130. data/examples/group/recipes/modify.rb +13 -0
  131. data/examples/group/recipes/remove.rb +13 -0
  132. data/examples/group/spec/create_spec.rb +23 -0
  133. data/examples/group/spec/manage_spec.rb +19 -0
  134. data/examples/group/spec/modify_spec.rb +19 -0
  135. data/examples/group/spec/remove_spec.rb +18 -0
  136. data/examples/guards/recipes/default.rb +13 -0
  137. data/examples/guards/spec/default_spec.rb +17 -0
  138. data/examples/heavy_provider_light_resource/libraries/resource_service.rb +15 -0
  139. data/examples/heavy_provider_light_resource/providers/service.rb +9 -0
  140. data/examples/heavy_provider_light_resource/recipes/default.rb +4 -0
  141. data/examples/heavy_provider_light_resource/spec/provider_service_spec.rb +7 -0
  142. data/examples/http_request/recipes/delete.rb +13 -0
  143. data/examples/http_request/recipes/get.rb +13 -0
  144. data/examples/http_request/recipes/head.rb +13 -0
  145. data/examples/http_request/recipes/options.rb +13 -0
  146. data/examples/http_request/recipes/post.rb +13 -0
  147. data/examples/http_request/recipes/put.rb +13 -0
  148. data/examples/http_request/spec/delete_spec.rb +19 -0
  149. data/examples/http_request/spec/get_spec.rb +23 -0
  150. data/examples/http_request/spec/head_spec.rb +19 -0
  151. data/examples/http_request/spec/options_spec.rb +19 -0
  152. data/examples/http_request/spec/post_spec.rb +19 -0
  153. data/examples/http_request/spec/put_spec.rb +19 -0
  154. data/examples/ifconfig/recipes/add.rb +9 -0
  155. data/examples/ifconfig/recipes/delete.rb +8 -0
  156. data/examples/ifconfig/recipes/disable.rb +8 -0
  157. data/examples/ifconfig/recipes/enable.rb +8 -0
  158. data/examples/ifconfig/spec/add_spec.rb +19 -0
  159. data/examples/ifconfig/spec/delete_spec.rb +15 -0
  160. data/examples/ifconfig/spec/disable_spec.rb +15 -0
  161. data/examples/ifconfig/spec/enable_spec.rb +15 -0
  162. data/examples/include_recipe/recipes/default.rb +1 -0
  163. data/examples/include_recipe/recipes/not.rb +0 -0
  164. data/examples/include_recipe/recipes/other.rb +0 -0
  165. data/examples/include_recipe/spec/default_spec.rb +13 -0
  166. data/examples/inherits/recipes/default.rb +5 -0
  167. data/examples/inherits/spec/default_spec.rb +21 -0
  168. data/examples/ips_package/recipes/install.rb +13 -0
  169. data/examples/ips_package/recipes/remove.rb +13 -0
  170. data/examples/ips_package/recipes/upgrade.rb +13 -0
  171. data/examples/ips_package/spec/install_spec.rb +23 -0
  172. data/examples/ips_package/spec/remove_spec.rb +19 -0
  173. data/examples/ips_package/spec/upgrade_spec.rb +19 -0
  174. data/examples/link/recipes/create.rb +13 -0
  175. data/examples/link/recipes/delete.rb +13 -0
  176. data/examples/link/recipes/link_to.rb +3 -0
  177. data/examples/link/spec/create_spec.rb +23 -0
  178. data/examples/link/spec/delete_spec.rb +19 -0
  179. data/examples/link/spec/link_to_spec.rb +11 -0
  180. data/examples/log/recipes/write.rb +14 -0
  181. data/examples/log/spec/write_spec.rb +24 -0
  182. data/examples/macports_package/recipes/install.rb +13 -0
  183. data/examples/macports_package/recipes/purge.rb +13 -0
  184. data/examples/macports_package/recipes/remove.rb +13 -0
  185. data/examples/macports_package/recipes/upgrade.rb +13 -0
  186. data/examples/macports_package/spec/install_spec.rb +23 -0
  187. data/examples/macports_package/spec/purge_spec.rb +19 -0
  188. data/examples/macports_package/spec/remove_spec.rb +19 -0
  189. data/examples/macports_package/spec/upgrade_spec.rb +19 -0
  190. data/examples/mdadm/recipes/assemble.rb +13 -0
  191. data/examples/mdadm/recipes/create.rb +13 -0
  192. data/examples/mdadm/recipes/stop.rb +13 -0
  193. data/examples/mdadm/spec/assemble_spec.rb +19 -0
  194. data/examples/mdadm/spec/create_spec.rb +23 -0
  195. data/examples/mdadm/spec/stop_spec.rb +19 -0
  196. data/examples/mount/recipes/disable.rb +8 -0
  197. data/examples/mount/recipes/enable.rb +8 -0
  198. data/examples/mount/recipes/mount.rb +9 -0
  199. data/examples/mount/recipes/remount.rb +8 -0
  200. data/examples/mount/recipes/umount.rb +8 -0
  201. data/examples/mount/spec/disable_spec.rb +15 -0
  202. data/examples/mount/spec/enable_spec.rb +15 -0
  203. data/examples/mount/spec/mount_spec.rb +19 -0
  204. data/examples/mount/spec/remount_spec.rb +15 -0
  205. data/examples/mount/spec/umount_spec.rb +15 -0
  206. data/examples/multiple_actions/recipes/default.rb +3 -0
  207. data/examples/multiple_actions/recipes/sequential.rb +7 -0
  208. data/examples/multiple_actions/spec/default_spec.rb +14 -0
  209. data/examples/multiple_actions/spec/sequential_spec.rb +13 -0
  210. data/examples/multiple_run_action/recipes/default.rb +5 -0
  211. data/examples/multiple_run_action/spec/default_spec.rb +18 -0
  212. data/examples/notifications/recipes/chained.rb +12 -0
  213. data/examples/notifications/recipes/default.rb +7 -0
  214. data/examples/notifications/recipes/delayed.rb +7 -0
  215. data/examples/notifications/recipes/immediately.rb +7 -0
  216. data/examples/notifications/spec/chained_spec.rb +21 -0
  217. data/examples/notifications/spec/default_spec.rb +16 -0
  218. data/examples/notifications/spec/delayed_spec.rb +16 -0
  219. data/examples/notifications/spec/immediately_spec.rb +16 -0
  220. data/examples/ohai/recipes/reload.rb +13 -0
  221. data/examples/ohai/spec/reload_spec.rb +23 -0
  222. data/examples/package/recipes/install.rb +13 -0
  223. data/examples/package/recipes/purge.rb +13 -0
  224. data/examples/package/recipes/reconfig.rb +13 -0
  225. data/examples/package/recipes/remove.rb +13 -0
  226. data/examples/package/recipes/upgrade.rb +13 -0
  227. data/examples/package/spec/install_spec.rb +23 -0
  228. data/examples/package/spec/purge_spec.rb +19 -0
  229. data/examples/package/spec/reconfig_spec.rb +19 -0
  230. data/examples/package/spec/remove_spec.rb +19 -0
  231. data/examples/package/spec/upgrade_spec.rb +19 -0
  232. data/examples/pacman_package/recipes/install.rb +13 -0
  233. data/examples/pacman_package/recipes/purge.rb +13 -0
  234. data/examples/pacman_package/recipes/remove.rb +13 -0
  235. data/examples/pacman_package/recipes/upgrade.rb +13 -0
  236. data/examples/pacman_package/spec/install_spec.rb +23 -0
  237. data/examples/pacman_package/spec/purge_spec.rb +19 -0
  238. data/examples/pacman_package/spec/remove_spec.rb +19 -0
  239. data/examples/pacman_package/spec/upgrade_spec.rb +19 -0
  240. data/examples/portage_package/recipes/install.rb +13 -0
  241. data/examples/portage_package/recipes/purge.rb +13 -0
  242. data/examples/portage_package/recipes/remove.rb +13 -0
  243. data/examples/portage_package/recipes/upgrade.rb +13 -0
  244. data/examples/portage_package/spec/install_spec.rb +23 -0
  245. data/examples/portage_package/spec/purge_spec.rb +19 -0
  246. data/examples/portage_package/spec/remove_spec.rb +19 -0
  247. data/examples/portage_package/spec/upgrade_spec.rb +19 -0
  248. data/examples/powershell_script/recipes/run.rb +13 -0
  249. data/examples/powershell_script/spec/run_spec.rb +23 -0
  250. data/examples/registry_key/recipes/create.rb +13 -0
  251. data/examples/registry_key/recipes/create_if_missing.rb +13 -0
  252. data/examples/registry_key/recipes/delete.rb +13 -0
  253. data/examples/registry_key/recipes/delete_key.rb +13 -0
  254. data/examples/registry_key/spec/create_if_missing_spec.rb +19 -0
  255. data/examples/registry_key/spec/create_spec.rb +23 -0
  256. data/examples/registry_key/spec/delete_key_spec.rb +19 -0
  257. data/examples/registry_key/spec/delete_spec.rb +19 -0
  258. data/examples/remote_directory/recipes/create.rb +13 -0
  259. data/examples/remote_directory/recipes/create_if_missing.rb +13 -0
  260. data/examples/remote_directory/recipes/delete.rb +13 -0
  261. data/examples/remote_directory/spec/create_if_missing_spec.rb +19 -0
  262. data/examples/remote_directory/spec/create_spec.rb +23 -0
  263. data/examples/remote_directory/spec/delete_spec.rb +19 -0
  264. data/examples/remote_file/recipes/create.rb +18 -0
  265. data/examples/remote_file/recipes/create_if_missing.rb +16 -0
  266. data/examples/remote_file/recipes/delete.rb +16 -0
  267. data/examples/remote_file/recipes/touch.rb +16 -0
  268. data/examples/remote_file/spec/create_if_missing_spec.rb +19 -0
  269. data/examples/remote_file/spec/create_spec.rb +23 -0
  270. data/examples/remote_file/spec/delete_spec.rb +19 -0
  271. data/examples/remote_file/spec/touch_spec.rb +19 -0
  272. data/examples/render_file/files/default/cookbook_file +1 -0
  273. data/examples/render_file/recipes/default.rb +15 -0
  274. data/examples/render_file/recipes/template_helpers.rb +9 -0
  275. data/examples/render_file/spec/default_spec.rb +73 -0
  276. data/examples/render_file/spec/template_helpers_spec.rb +10 -0
  277. data/examples/render_file/templates/default/_partial.erb +1 -0
  278. data/examples/render_file/templates/default/partial.erb +1 -0
  279. data/examples/render_file/templates/default/template.erb +1 -0
  280. data/examples/render_file/templates/default/template_with_helper.erb +1 -0
  281. data/examples/roles/recipes/another.rb +3 -0
  282. data/examples/roles/recipes/default.rb +1 -0
  283. data/examples/roles/roles/role.rb +9 -0
  284. data/examples/roles/spec/default_spec.rb +21 -0
  285. data/examples/route/recipes/add.rb +13 -0
  286. data/examples/route/recipes/delete.rb +13 -0
  287. data/examples/route/spec/add_spec.rb +23 -0
  288. data/examples/route/spec/delete_spec.rb +19 -0
  289. data/examples/rpm_package/recipes/install.rb +13 -0
  290. data/examples/rpm_package/recipes/remove.rb +13 -0
  291. data/examples/rpm_package/recipes/upgrade.rb +13 -0
  292. data/examples/rpm_package/spec/install_spec.rb +23 -0
  293. data/examples/rpm_package/spec/remove_spec.rb +19 -0
  294. data/examples/rpm_package/spec/upgrade_spec.rb +19 -0
  295. data/examples/ruby_block/recipes/run.rb +9 -0
  296. data/examples/ruby_block/spec/run_spec.rb +18 -0
  297. data/examples/script/recipes/run_bash.rb +13 -0
  298. data/examples/script/recipes/run_csh.rb +13 -0
  299. data/examples/script/recipes/run_perl.rb +13 -0
  300. data/examples/script/recipes/run_python.rb +13 -0
  301. data/examples/script/recipes/run_ruby.rb +13 -0
  302. data/examples/script/recipes/run_script.rb +13 -0
  303. data/examples/script/spec/run_bash_spec.rb +23 -0
  304. data/examples/script/spec/run_csh_spec.rb +23 -0
  305. data/examples/script/spec/run_perl_spec.rb +23 -0
  306. data/examples/script/spec/run_python_spec.rb +23 -0
  307. data/examples/script/spec/run_ruby_spec.rb +23 -0
  308. data/examples/script/spec/run_script_spec.rb +23 -0
  309. data/examples/server/recipes/client.rb +6 -0
  310. data/examples/server/recipes/data_bag.rb +7 -0
  311. data/examples/server/recipes/environment.rb +6 -0
  312. data/examples/server/recipes/node.rb +6 -0
  313. data/examples/server/recipes/role.rb +6 -0
  314. data/examples/server/recipes/search.rb +5 -0
  315. data/examples/server/spec/client_spec.rb +17 -0
  316. data/examples/server/spec/data_bag_spec.rb +26 -0
  317. data/examples/server/spec/environment_spec.rb +17 -0
  318. data/examples/server/spec/node_spec.rb +40 -0
  319. data/examples/server/spec/role_spec.rb +17 -0
  320. data/examples/server/spec/search_spec.rb +58 -0
  321. data/examples/service/recipes/disable.rb +13 -0
  322. data/examples/service/recipes/enable.rb +13 -0
  323. data/examples/service/recipes/reload.rb +13 -0
  324. data/examples/service/recipes/restart.rb +13 -0
  325. data/examples/service/recipes/start.rb +13 -0
  326. data/examples/service/recipes/stop.rb +13 -0
  327. data/examples/service/spec/disable_spec.rb +19 -0
  328. data/examples/service/spec/enable_spec.rb +19 -0
  329. data/examples/service/spec/reload_spec.rb +19 -0
  330. data/examples/service/spec/restart_spec.rb +19 -0
  331. data/examples/service/spec/start_spec.rb +19 -0
  332. data/examples/service/spec/stop_spec.rb +19 -0
  333. data/examples/smartos_package/recipes/install.rb +13 -0
  334. data/examples/smartos_package/recipes/remove.rb +13 -0
  335. data/examples/smartos_package/recipes/upgrade.rb +13 -0
  336. data/examples/smartos_package/spec/install_spec.rb +23 -0
  337. data/examples/smartos_package/spec/remove_spec.rb +19 -0
  338. data/examples/smartos_package/spec/upgrade_spec.rb +19 -0
  339. data/examples/solaris_package/recipes/install.rb +13 -0
  340. data/examples/solaris_package/recipes/remove.rb +13 -0
  341. data/examples/solaris_package/spec/install_spec.rb +23 -0
  342. data/examples/solaris_package/spec/remove_spec.rb +19 -0
  343. data/examples/state_attrs/providers/lwrp.rb +3 -0
  344. data/examples/state_attrs/recipes/default.rb +3 -0
  345. data/examples/state_attrs/resources/lwrp.rb +6 -0
  346. data/examples/state_attrs/spec/default_spec.rb +12 -0
  347. data/examples/step_into/providers/lwrp.rb +3 -0
  348. data/examples/step_into/recipes/default.rb +1 -0
  349. data/examples/step_into/resources/lwrp.rb +4 -0
  350. data/examples/step_into/spec/default_spec.rb +19 -0
  351. data/examples/stub_command/recipes/default.rb +5 -0
  352. data/examples/stub_command/recipes/other_recipe.rb +3 -0
  353. data/examples/stub_command/spec/default_spec.rb +28 -0
  354. data/examples/stub_data_bag/recipes/default.rb +5 -0
  355. data/examples/stub_data_bag/spec/default_spec.rb +27 -0
  356. data/examples/stub_data_bag_item/recipes/default.rb +5 -0
  357. data/examples/stub_data_bag_item/spec/default_spec.rb +27 -0
  358. data/examples/stub_node/recipes/default.rb +0 -0
  359. data/examples/stub_node/spec/default_spec.rb +17 -0
  360. data/examples/stub_search/recipes/default.rb +5 -0
  361. data/examples/stub_search/spec/default_spec.rb +27 -0
  362. data/examples/subscribes/recipes/chained.rb +10 -0
  363. data/examples/subscribes/recipes/default.rb +5 -0
  364. data/examples/subscribes/recipes/delayed.rb +5 -0
  365. data/examples/subscribes/recipes/immediately.rb +5 -0
  366. data/examples/subscribes/spec/chained_spec.rb +21 -0
  367. data/examples/subscribes/spec/default_spec.rb +17 -0
  368. data/examples/subscribes/spec/delayed_spec.rb +16 -0
  369. data/examples/subscribes/spec/immediately_spec.rb +16 -0
  370. data/examples/subversion/recipes/checkout.rb +13 -0
  371. data/examples/subversion/recipes/export.rb +13 -0
  372. data/examples/subversion/recipes/force_export.rb +13 -0
  373. data/examples/subversion/recipes/sync.rb +13 -0
  374. data/examples/subversion/spec/checkout_spec.rb +19 -0
  375. data/examples/subversion/spec/export_spec.rb +19 -0
  376. data/examples/subversion/spec/force_export_spec.rb +19 -0
  377. data/examples/subversion/spec/sync_spec.rb +23 -0
  378. data/examples/template/recipes/create.rb +15 -0
  379. data/examples/template/recipes/create_if_missing.rb +15 -0
  380. data/examples/template/recipes/delete.rb +15 -0
  381. data/examples/template/recipes/touch.rb +15 -0
  382. data/examples/template/spec/create_if_missing_spec.rb +28 -0
  383. data/examples/template/spec/create_spec.rb +32 -0
  384. data/examples/template/spec/delete_spec.rb +19 -0
  385. data/examples/template/spec/touch_spec.rb +19 -0
  386. data/examples/use_inline_resources/libraries/matchers.rb +5 -0
  387. data/examples/use_inline_resources/providers/lwrp.rb +7 -0
  388. data/examples/use_inline_resources/recipes/default.rb +1 -0
  389. data/examples/use_inline_resources/resources/lwrp.rb +4 -0
  390. data/examples/use_inline_resources/spec/default_spec.rb +15 -0
  391. data/examples/user/recipes/create.rb +13 -0
  392. data/examples/user/recipes/lock.rb +13 -0
  393. data/examples/user/recipes/manage.rb +13 -0
  394. data/examples/user/recipes/modify.rb +13 -0
  395. data/examples/user/recipes/remove.rb +13 -0
  396. data/examples/user/recipes/unlock.rb +13 -0
  397. data/examples/user/spec/create_spec.rb +23 -0
  398. data/examples/user/spec/lock_spec.rb +19 -0
  399. data/examples/user/spec/manage_spec.rb +19 -0
  400. data/examples/user/spec/modify_spec.rb +19 -0
  401. data/examples/user/spec/remove_spec.rb +19 -0
  402. data/examples/user/spec/unlock_spec.rb +19 -0
  403. data/examples/yum_package/recipes/install.rb +13 -0
  404. data/examples/yum_package/recipes/purge.rb +13 -0
  405. data/examples/yum_package/recipes/remove.rb +13 -0
  406. data/examples/yum_package/recipes/upgrade.rb +13 -0
  407. data/examples/yum_package/spec/install_spec.rb +23 -0
  408. data/examples/yum_package/spec/purge_spec.rb +19 -0
  409. data/examples/yum_package/spec/remove_spec.rb +19 -0
  410. data/examples/yum_package/spec/upgrade_spec.rb +19 -0
  411. data/features/apt_package.feature +14 -0
  412. data/features/attributes.feature +7 -0
  413. data/features/batch.feature +13 -0
  414. data/features/cached.feature +7 -0
  415. data/features/chef_gem.feature +14 -0
  416. data/features/compile_time.feature +7 -0
  417. data/features/cookbook_file.feature +13 -0
  418. data/features/cron.feature +11 -0
  419. data/features/custom_matcher.feature +11 -0
  420. data/features/deploy.feature +12 -0
  421. data/features/directory.feature +11 -0
  422. data/features/dpkg_package.feature +12 -0
  423. data/features/easy_install_package.feature +13 -0
  424. data/features/env.feature +12 -0
  425. data/features/erl_call.feature +10 -0
  426. data/features/execute.feature +10 -0
  427. data/features/expect_exception.feature +12 -0
  428. data/features/file.feature +13 -0
  429. data/features/freebsd_package.feature +11 -0
  430. data/features/gem_package.feature +14 -0
  431. data/features/git.feature +12 -0
  432. data/features/group.feature +13 -0
  433. data/features/guards.feature +10 -0
  434. data/features/heavy_provider_light_resource.feature +10 -0
  435. data/features/http_request.feature +15 -0
  436. data/features/ifconfig.feature +13 -0
  437. data/features/include_recipe.feature +10 -0
  438. data/features/inherits.feature +7 -0
  439. data/features/ips_package.feature +12 -0
  440. data/features/link.feature +12 -0
  441. data/features/log.feature +10 -0
  442. data/features/macports_package.feature +13 -0
  443. data/features/mdadm.feature +12 -0
  444. data/features/mount.feature +14 -0
  445. data/features/multiple_actions.feature +11 -0
  446. data/features/multiple_run_action.feature +7 -0
  447. data/features/notifications.feature +13 -0
  448. data/features/ohai.feature +10 -0
  449. data/features/package.feature +14 -0
  450. data/features/pacman_package.feature +13 -0
  451. data/features/portage_package.feature +13 -0
  452. data/features/powershell_script.feature +13 -0
  453. data/features/registry_key.feature +13 -0
  454. data/features/remote_directory.feature +12 -0
  455. data/features/remote_file.feature +13 -0
  456. data/features/render_file.feature +16 -0
  457. data/features/roles.feature +7 -0
  458. data/features/route.feature +11 -0
  459. data/features/rpm_package.feature +12 -0
  460. data/features/ruby_block.feature +10 -0
  461. data/features/script.feature +15 -0
  462. data/features/server.feature +21 -0
  463. data/features/service.feature +15 -0
  464. data/features/smartos_package.feature +16 -0
  465. data/features/solaris_package.feature +15 -0
  466. data/features/state_attrs.feature +11 -0
  467. data/features/step_definitions/background_steps.rb +4 -0
  468. data/features/step_into.feature +7 -0
  469. data/features/stub_command.feature +7 -0
  470. data/features/stub_data_bag.feature +7 -0
  471. data/features/stub_data_bag_item.feature +7 -0
  472. data/features/stub_node.feature +7 -0
  473. data/features/stub_search.feature +7 -0
  474. data/features/subscribes.feature +13 -0
  475. data/features/subversion.feature +13 -0
  476. data/features/support/env.rb +36 -0
  477. data/features/support/executor.rb +18 -0
  478. data/features/template.feature +13 -0
  479. data/features/use_inline_resources.feature +7 -0
  480. data/features/user.feature +15 -0
  481. data/features/yum_package.feature +13 -0
  482. data/gemfiles/chef-11.0.0.gemfile +5 -0
  483. data/gemfiles/chef-11.2.0.gemfile +5 -0
  484. data/gemfiles/chef-11.4.4.gemfile +5 -0
  485. data/gemfiles/chef-11.6.0.gemfile +5 -0
  486. data/gemfiles/chef-11.8.0.gemfile +5 -0
  487. data/gemfiles/chef-master.gemfile +5 -0
  488. data/lib/chefspec/api.rb +13 -11
  489. data/lib/chefspec/api/notifications.rb +3 -3
  490. data/lib/chefspec/api/subscriptions.rb +35 -0
  491. data/lib/chefspec/coverage.rb +40 -34
  492. data/lib/chefspec/expect_exception.rb +14 -13
  493. data/lib/chefspec/formatter.rb +8 -8
  494. data/lib/chefspec/matchers.rb +1 -0
  495. data/lib/chefspec/matchers/include_recipe_matcher.rb +19 -18
  496. data/lib/chefspec/matchers/notifications_matcher.rb +25 -24
  497. data/lib/chefspec/matchers/render_file_matcher.rb +32 -31
  498. data/lib/chefspec/matchers/resource_matcher.rb +64 -63
  499. data/lib/chefspec/matchers/state_attrs_matcher.rb +18 -17
  500. data/lib/chefspec/matchers/subscribes_matcher.rb +59 -0
  501. data/lib/chefspec/renderer.rb +82 -81
  502. data/lib/chefspec/runner.rb +66 -51
  503. data/lib/chefspec/server.rb +84 -39
  504. data/lib/chefspec/stubs/stub.rb +10 -9
  505. data/lib/chefspec/version.rb +1 -1
  506. data/spec/spec_helper.rb +8 -0
  507. data/spec/support/hash.rb +35 -0
  508. data/spec/unit/api_spec.rb +18 -0
  509. data/spec/unit/cacher_spec.rb +54 -0
  510. data/spec/unit/expect_exception_spec.rb +32 -0
  511. data/spec/unit/extensions/lwrp_base_spec.rb +89 -0
  512. data/spec/unit/macros_spec.rb +119 -0
  513. data/spec/unit/matchers/include_recipe_matcher_spec.rb +38 -0
  514. data/spec/unit/matchers/link_to_matcher_spec.rb +39 -0
  515. data/spec/unit/matchers/notifications_matcher_spec.rb +5 -0
  516. data/spec/unit/matchers/render_file_matcher_spec.rb +41 -0
  517. data/spec/unit/matchers/resource_matcher_spec.rb +5 -0
  518. data/spec/unit/matchers/state_attrs_matcher_spec.rb +64 -0
  519. data/spec/unit/matchers/subscribes_matcher_spec.rb +5 -0
  520. data/spec/unit/renderer_spec.rb +51 -0
  521. data/spec/unit/runner_spec.rb +125 -0
  522. data/spec/unit/stubs/command_registry_spec.rb +27 -0
  523. data/spec/unit/stubs/command_stub_spec.rb +61 -0
  524. data/spec/unit/stubs/data_bag_item_registry_spec.rb +39 -0
  525. data/spec/unit/stubs/data_bag_item_stub_spec.rb +36 -0
  526. data/spec/unit/stubs/data_bag_registry_spec.rb +39 -0
  527. data/spec/unit/stubs/data_bag_stub_spec.rb +35 -0
  528. data/spec/unit/stubs/registry_spec.rb +29 -0
  529. data/spec/unit/stubs/search_registry_spec.rb +39 -0
  530. data/spec/unit/stubs/search_stub_spec.rb +36 -0
  531. data/spec/unit/stubs/stub_spec.rb +64 -0
  532. metadata +618 -5
@@ -0,0 +1,52 @@
1
+ Contributing to ChefSpec
2
+ ========================
3
+ Pull requests are merged via Github, you can find the documentation about how to fork a repository and start contributing to ChefSpec here [https://help.github.com/articles/fork-a-repo](https://help.github.com/articles/fork-a-repo).
4
+
5
+ All contributions are welcome to be submitted for review for inclusion, but before they will be accepted, we ask that you follow these simple steps:
6
+
7
+ * [Coding standards](#coding-standards)
8
+ * [Testing](#testing)
9
+ * [Documentation](#documentation)
10
+
11
+ Also, please be patient as not all items will be tested or reviewed immediately by the core team.
12
+
13
+ Please be receptive and responsive to feedback about your additions or changes. The core team and/or other community members may make suggestions or ask questions about your change. This is part of the review process, and helps everyone to understand what is happening, why it is happening, and potentially optimizes your code.
14
+
15
+ If you're looking to contribute but aren't sure where to start, check out the [open issues](https://github.com/sethvargo/chefspec/issues?state=open).
16
+
17
+
18
+ Will Not Merge
19
+ --------------
20
+ This section details, specifically, Pull Requests or features that will _not_ be merged:
21
+
22
+ 1. Matchers for non-Chef core resources. ChefSpec 3.0 introduced a way for cookbook maintainers to [package matchers _with_ their cookbooks](https://github.com/sethvargo/chefspec/tree/unify_matchers#packaging-lwrp-matchers) at distribution time.
23
+ 2. New features without accompanying unit tests, cucumber tests, and documentation.
24
+
25
+
26
+ Coding Standards
27
+ ----------------
28
+ The submitted code should be compatible with the standard Ruby coding guidelines. Here are some additional resources:
29
+
30
+ * [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide)
31
+ * [Github Styleguide](https://github.com/styleguide/ruby)
32
+
33
+ There is a tool called [Cane](https://github.com/square/cane) that allows you to validate your code's ABC complexity and documentation.
34
+
35
+
36
+ Testing
37
+ -------
38
+ Whether your pull request is a bug fix or introduces new classes or methods to the project, we kindly ask that you include tests for your changes. Even if it's just a small improvement, a test is necessary to ensure the bug is never re-introduced.
39
+
40
+ We understand that not all users submitting pull requests will be proficient with RSpec. The maintainers and community as a whole are a helpful group and can help you with writing tests. The [Better Specs](http://betterspecs.org/) site should provide some helpful resources to get you started.
41
+
42
+ ChefSpec is tested on [Travis CI](https://travis-ci.org/sethvargo/chefspec) against multiple Chef Versions and Ruby Versions. **Your patches must work for all Chef and Ruby Versions on Travis.** This is in an effort to maintain backward compatibility as long as possible. For more information on which Chef and Ruby versions to support, checkout the [`.travis.yml`](https://github.com/sethvargo/chefspec/blob/master/.travis.yml) file.
43
+
44
+
45
+ Documentation
46
+ -------------
47
+ Documentation is a crucial part to ChefSpec, especially given its broad depth of features. All documentation is placed inline on the method matcher so it can be generated with Yard. Please see existing matchers for an example and check out the [Yard documentation](http://yardoc.info)
48
+
49
+ When contributing new features, please ensure adequate documentation and examples are present.
50
+
51
+ ---
52
+ This contributing guide is based off of the [Joomla Contributing Guide](https://raw.github.com/joomla/joomla-framework/master/CONTRIBUTING.markdown).
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,41 @@
1
+ ChefSpec Issues
2
+ ---------------
3
+ This file documents the steps necessary to report and issue with ChefSpec. Following these guidelines will help ensure your issue is resolved in a timely manner.
4
+
5
+ Reporting
6
+ ---------
7
+ When you report an issue, please include the following information:
8
+
9
+ - What you're trying to accomplish
10
+ - An [SSCCE](http://sscce.org/)
11
+ - The command you ran
12
+ - What you expected to happen
13
+ - What actually happened
14
+ - The exception backtrace(s), if any
15
+ - What operating system and version
16
+ - Everything output by running `env`
17
+ - What version of Ruby you are using (run `ruby -v`)
18
+ - What version of Rubygems you are using (run `gem -v`)
19
+ - What version of Chef you are using (run `knife -v`)
20
+
21
+ Here's a snippet you can copy-paste into the issue and fill out:
22
+
23
+ ```text
24
+ (What is the issue? What are you trying to do? What happened?)
25
+
26
+ - Command: `...`
27
+ - OS:
28
+ - Ruby:
29
+ - Rubygems:
30
+ - Chef:
31
+ - env:
32
+ ```text
33
+ # Paste your env here
34
+ ```
35
+ - Backtrace:
36
+ ```text
37
+ # Paste backtrace here
38
+ ```
39
+ ```
40
+
41
+ [Create a ticket](https://github.com/sethvargo/chefspec/issues/new) describing your problem and include the information above.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (C) 2011 by Andrew Crump
4
+ Copyright (C) 2013 by Seth Vargo
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
@@ -0,0 +1,893 @@
1
+ ChefSpec
2
+ ========
3
+ [![Built on Travis](https://secure.travis-ci.org/sethvargo/chefspec.png?branch=master)](http://travis-ci.org/sethvargo/chefspec)
4
+ [![Gem Version](https://badge.fury.io/rb/chefspec.png)](http://badge.fury.io/rb/chefspec)
5
+ [![Dependency Status](https://gemnasium.com/sethvargo/chefspec.png)](https://gemnasium.com/sethvargo/chefspec)
6
+ [![Code Climate](https://codeclimate.com/github/sethvargo/chefspec.png)](https://codeclimate.com/github/sethvargo/chefspec)
7
+
8
+ ChefSpec is a unit testing framework for testing Chef cookbooks. ChefSpec makes it easy to write examples and get fast feedback on cookbook changes without the need for virtual machines or cloud servers.
9
+
10
+ ChefSpec runs your cookbook locally using Chef Solo without actually converging a node. This has two primary benefits:
11
+
12
+ - It's really fast!
13
+ - Your tests can vary node attributes, operating systems, and search results to assert behavior under varying conditions.
14
+
15
+
16
+ What people are saying
17
+ ----------------------
18
+ > I just wanted to drop you a line to say "HELL YES!" to ChefSpec. - [Joe Goggins](https://twitter.com/jgoggins)
19
+
20
+ > OK chefspec is my new best friend. Delightful few hours working with it. - [Michael Ivey](https://twitter.com/ivey)
21
+
22
+ **Chat with us - [#chefspec](irc://irc.freenode.net/chefspec) on Freenode**
23
+
24
+
25
+ Important Notes
26
+ ---------------
27
+ - **ChefSpec 3 requires Chef 11+! Please use the 2.x series for Chef 9 & 10 compatibility.**
28
+ - **This documentation corresponds to the master branch, which may be unreleased. Please check the README of the latest git tag or the gem's source for your version' documentation!**
29
+ - **Each resource matcher is self-documented using [Yard](http://rubydoc.info/github/sethvargo/chefspec) and has a corresponding aruba test from the [examples directory](https://github.com/sethvargo/chefspec/tree/master/examples).**
30
+ - **ChefSpec 3.0 requires Ruby 1.9 or higher!**
31
+
32
+ If you are migrating from ChefSpec v2.0.0, you should require the deprecations module after requiring `chefspec`:
33
+
34
+ ```ruby
35
+ # spec_helper.rb
36
+ require 'chefspec'
37
+ require 'chefspec/deprecations'
38
+ ```
39
+
40
+ After you have converted your specs, you can safely remove the deprecations module.
41
+
42
+
43
+ Writing a Cookbook Example
44
+ --------------------------
45
+ If you want `knife` to automatically generate spec stubs for you, install [knife-spec](https://github.com/sethvargo/knife-spec).
46
+
47
+ Given an extremely basic Chef recipe that just installs an operating system package:
48
+
49
+ ```ruby
50
+ package 'foo'
51
+ ```
52
+
53
+ the associated ChefSpec test might look like:
54
+
55
+ ```ruby
56
+ require 'chefspec'
57
+
58
+ describe 'example::default' do
59
+ let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
60
+
61
+ it 'installs foo' do
62
+ expect(chef_run).to install_package('foo')
63
+ end
64
+ end
65
+ ```
66
+
67
+ Let's step through this file to see what is happening:
68
+
69
+ 1. At the top of the spec file we require the chefspec gem. This is required so that our custom matchers are loaded. In larger projects, it is common practice to create a file named "spec_helper.rb" and include ChefSpec and perform other setup tasks in that file.
70
+ 1. The `describe` keyword is part of RSpec and indicates that everything nested beneath is describing the `example::default` recipe. The convention is to have a separate spec for each recipe in your cookbook.
71
+ 1. The `let` block on creates the `ChefSpec:Runner` and then does a fake Chef run with the run_list of `example::default`. Any subsequent examples can then refer to `chef_run` in order to make assertions about the resources that were created during the mock converge.
72
+ 1. The `described_recipe` macro is a ChefSpec helper method that infers the recipe from the `describe` block. Alternatively you could specify the recipe directly.
73
+ 1. The `it` block is an example specifying that the `foo` package is installed. Normally you will have multiple `it` blocks per recipe, each making a single assertion.
74
+
75
+
76
+ Configuration
77
+ -------------
78
+ ChefSpec exposes a configuration layer at the global level and at the `Runner` level. The following settings are available:
79
+
80
+ ```ruby
81
+ RSpec.configure do |config|
82
+ # Specify the path for Chef Solo to find cookbooks (default: [inferred from
83
+ # the location of the calling spec file])
84
+ config.cookbook_path = '/var/cookbooks'
85
+
86
+ # Specify the path for Chef Solo to find roles (default: [ascending search])
87
+ config.role_path = '/var/roles'
88
+
89
+ # Specify the Chef log_level (default: :warn)
90
+ config.log_level = :debug
91
+
92
+ # Specify the path to a local JSON file with Ohai data (default: nil)
93
+ config.path = 'ohai.json'
94
+
95
+ # Specify the operating platform to mock Ohai data from (default: nil)
96
+ config.platform = 'ubuntu'
97
+
98
+ # Specify the operating version to mock Ohai data from (default: nil)
99
+ config.version = '12.04'
100
+ end
101
+ ```
102
+
103
+ Values specified at the initialization of the `Runner` merge and take precedence over the global settings:
104
+
105
+ ```ruby
106
+ # Override only the operating system version (platform is still "ubuntu" from above)
107
+ ChefSpec::Runner.new(version: '10.04')
108
+
109
+ # Use a different operating system platform and version
110
+ ChefSpec::Runner.new(platform: 'centos', version: '5.4')
111
+
112
+ # Specify a different cookbook_path
113
+ ChefSpec::Runner.new(cookbook_path: '/var/my/other/path', role_path: '/var/my/roles')
114
+
115
+ # Add debug log output
116
+ ChefSpec::Runner.new(log_level: :debug).converge(described_recipe)
117
+ ```
118
+
119
+ **NOTE** You do not _need_ to specify a platform and version. However, some cookbooks may rely on [Ohai](http://github.com/opscode/ohai) data that ChefSpec cannot not automatically generate. Specifying the `platform` and `version` keys instructs ChefSpec to load stubbed Ohai attributes from another platform using [fauxhai](https://github.com/customink/fauxhai).
120
+
121
+ ### Berkshelf
122
+ If you are using Berkshelf, simply require `chefspec/berkshelf` in your `spec_helper` after requiring `chefspec`:
123
+
124
+ ```ruby
125
+ # spec_helper.rb
126
+ require 'chefspec'
127
+ require 'chefspec/berkshelf'
128
+ ```
129
+
130
+ Requiring this file will:
131
+
132
+ - Create a temporary working directory
133
+ - Download all the dependencies listed in your `Berksfile` into the temporary directory
134
+ - Set ChefSpec's `cookbook_path` to the temporary directory
135
+
136
+ ### Librarian
137
+
138
+ If you are using Librarian, simply require `chefspec/librarian` in your `spec_helper` after requiring `chefspec`:
139
+
140
+ ```ruby
141
+ # spec_helper.rb
142
+ require 'chefspec'
143
+ require 'chefspec/librarian'
144
+ ```
145
+
146
+ Requiring this file will:
147
+
148
+ - Create a temporary working directory
149
+ - Download all the dependencies listed in your `Cheffile` into the temporary directory
150
+ - Set ChefSpec's `cookbook_path` to the temporary directory
151
+
152
+ **NOTE** In order to test the cookbook in the current working directory, you
153
+ have to write your `Cheffile` like this:
154
+
155
+ ```ruby
156
+ # Cheffile
157
+ site 'http://community.opscode.com/api/v1'
158
+
159
+ cookbook 'name_of_your_cookbook', path: '.'
160
+ ```
161
+
162
+
163
+ Running Specs
164
+ -------------
165
+ ChefSpec is actually a very large RSpec extension, so you can run your tests using the RSpec CLI:
166
+
167
+ ```bash
168
+ $ rspec
169
+ ```
170
+
171
+ You can also specify a specific spec to run and various RSpec command line options:
172
+
173
+ ```bash
174
+ $ rspec spec/unit/recipes/default_spec.rb --color
175
+ ```
176
+
177
+ For more information on the RSpec CLI, please see the [documentation](https://relishapp.com/rspec/rspec-core/docs/command-line).
178
+
179
+
180
+ Making Assertions
181
+ -----------------
182
+ ChefSpec asserts that resource actions have been performed. In general, ChefSpec follows the following pattern:
183
+
184
+ ```ruby
185
+ require 'chefspec'
186
+
187
+ describe 'example::default' do
188
+ let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
189
+
190
+ it 'does something' do
191
+ expect(chef_run).to ACTION_RESOURCE(NAME)
192
+ end
193
+ end
194
+ ```
195
+
196
+ where:
197
+
198
+ - _ACTION_ - the action on the resource (e.g. `install`)
199
+ - _RESOURCE_ - the name of the resource (e.g. `package`)
200
+ - _NAME_ - the name attribute for the resource (e.g. `apache2`)
201
+
202
+ Here's a more concrete example:
203
+
204
+ ```ruby
205
+ require 'chefspec'
206
+
207
+ describe 'example::default' do
208
+ let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
209
+
210
+ it 'does something' do
211
+ expect(chef_run).to install_package('apache2')
212
+ end
213
+ end
214
+ ```
215
+
216
+ This test is asserting that the Chef run will have a _package_ resource with the name _apache2_ with an action of _install_.
217
+
218
+ To test that a resource action is performed with a specific set of attributes, you can call `with(ATTRIBUTES_HASH)` on the expectation, per the following example:
219
+
220
+ ```ruby
221
+ require 'chefspec'
222
+
223
+ describe 'example::default' do
224
+ let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
225
+
226
+ it 'does something' do
227
+ expect(chef_run).to modify_group('docker').with(members: ['vagrant'])
228
+ end
229
+ end
230
+ ```
231
+
232
+ This test is asserting that the Chef run will have a _group_ resource with the name _docker_, an action of _modify_, and an attributes hash including `{ members: ['vagrant'] }`.
233
+
234
+ ChefSpec includes matchers for all of Chef's core resources using the above schema. Each resource matcher is self-documented using [Yard](http://rubydoc.info/github/sethvargo/chefspec) and has a corresponding cucumber test from the [examples directory](https://github.com/sethvargo/chefspec/tree/master/examples).
235
+
236
+ Additionally, ChefSpec includes the following helpful matchers. They are also [documented in Yard](http://rubydoc.info/github/sethvargo/chefspec), but they are included here because they do not follow the "general pattern".
237
+
238
+ ##### include_recipe
239
+ Assert that the Chef run included a recipe from another cookbook
240
+
241
+ ```ruby
242
+ expect(chef_run).to include_recipe('other_cookbook::recipe')
243
+ ```
244
+
245
+ ##### notify
246
+ Assert that a resource notifies another in the Chef run
247
+
248
+ ```ruby
249
+ resource = chef_run.template('/etc/foo')
250
+ expect(resource).to notify('service[apache2]').to(:restart).immediately
251
+ ```
252
+
253
+ ##### subscribes
254
+ Assert that a resource subscribes to another in the Chef run
255
+
256
+ ```ruby
257
+ resource = chef_run.service('apache2')
258
+ expect(resource).to subscribe_to('template[/etc/foo]').on(:create).delayed
259
+ ```
260
+
261
+ ##### render_file
262
+ Assert that the Chef run renders a file (with optional content); this will match `cookbook_file`, `file`, and `template` resources and can also check the resulting content
263
+
264
+ ```ruby
265
+ expect(chef_run).to render_file('/etc/foo')
266
+ expect(chef_run).to render_file('/etc/foo').with_content('This is content')
267
+ expect(chef_run).to render_file('/etc/foo').with_content(/regex works too.+/)
268
+ ```
269
+
270
+ Additionally, it is possible to assert which [Chef phase of execution](http://docs.opscode.com/essentials_nodes_chef_run.html) a resource is created. Given a resource that is installed at compile time using `run_action`:
271
+
272
+ ```ruby
273
+ package('apache2').run_action(:install)
274
+ ```
275
+
276
+ You can assert that this package is installed during runtime using the `.at_compile_time` predicate on the resource matcher:
277
+
278
+ ```ruby
279
+ expect(chef_run).to install_package('apache2').at_compile_time
280
+ ```
281
+
282
+ Similarly, you can assert that a resource is executed during convergence time:
283
+
284
+ ```ruby
285
+ expect(chef_run).to install_package('apache2').at_converge_time
286
+ ```
287
+
288
+ Since "converge time" is the default behavior for all recipes, this test might be redundant and the predicate could be dropped depending on your situation.
289
+
290
+ **For more complex examples, please see the [examples directory](https://github.com/sethvargo/chefspec/tree/master/examples) or the [Yard documentation](http://rubydoc.info/github/sethvargo/chefspec).**
291
+
292
+
293
+ Setting node Attributes
294
+ -----------------------
295
+ Node attribute can be set when creating the `Runner`. The initializer yields a block that gives full access to the node object:
296
+
297
+ ```ruby
298
+ describe 'example::default' do
299
+ let(:chef_run) do
300
+ ChefSpec::Runner.new do |node|
301
+ node.set['cookbook']['attribute'] = 'hello'
302
+ end.converge(described_recipe)
303
+ end
304
+ end
305
+ ```
306
+
307
+ The `node` that is returned is actually a [`Chef::Node`](http://docs.opscode.com/essentials_node_object.html) object.
308
+
309
+ To set an attribute within a specific test, set the attribute in the `it` block and then **(re-)converge the node**:
310
+
311
+ ```ruby
312
+ describe 'example::default' do
313
+ let(:chef_run) { ChefSpec::Runner.new } # Notice we don't converge here
314
+
315
+ it 'performs the action' do
316
+ chef_run.node.set['cookbook']['attribute'] = 'hello'
317
+ chef_run.converge(described_recipe) # The converge happens inside the test
318
+
319
+ expect(chef_run).to do_something
320
+ end
321
+ end
322
+ ```
323
+
324
+
325
+ Using Chef Zero
326
+ ---------------
327
+ By default, ChefSpec runs in Chef Solo mode. As of ChefSpec v3.1.0, you can ask ChefSpec to create an in-memory Chef Server during testing using [ChefZero](https://github.com/jkeiser/chef-zero). This is especially helpful if you need to support searching or data bags.
328
+
329
+ To use the ChefSpec server, simply require the module in your `spec_helper`:
330
+
331
+ ```ruby
332
+ # spec_helper.rb
333
+ require 'chefspec'
334
+ require 'chefspec/server'
335
+ ```
336
+
337
+ This will automatically create a Chef server, synchronize all the cookbooks in your `cookbook_path`, and wire all the internals of Chef together. Recipe calls to `search`, `data_bag` and `data_bag_item` will now query the ChefSpec server.
338
+
339
+ ### DSL
340
+ The ChefSpec server includes a collection of helpful DSL methods for populating data into the Chef Server.
341
+
342
+ Create a client:
343
+
344
+ ```ruby
345
+ ChefSpec::Server.create_client('my_client', { admin: true })
346
+ ```
347
+
348
+ Create a data bag (and items):
349
+
350
+ ```ruby
351
+ ChefSpec::Server.create_data_bag('my_data_bag', {
352
+ 'item_1' => {
353
+ 'password' => 'abc123'
354
+ },
355
+ 'item_2' => {
356
+ 'password' => 'def456'
357
+ }
358
+ })
359
+ ```
360
+
361
+ Create an environment:
362
+
363
+ ```ruby
364
+ ChefSpec::Server.create_environment('my_environment', { description: '...' })
365
+ ```
366
+
367
+ Create a node:
368
+
369
+ ```ruby
370
+ ChefSpec::Server.create_node('my_node', { run_list: ['...'] })
371
+ ```
372
+
373
+ You may also be interested in the `stub_node` macro, which will create a new `Chef::Node` object and accepts the same parameters as the Chef Runner and a Fauxhai object:
374
+
375
+ ```ruby
376
+ www = stub_node(platform: 'ubuntu', version: '12.04') do |node|
377
+ node['fqdn'] = 'www1.example.com'
378
+ end
379
+
380
+ # `www` is now a local Chef::Node object you can use in your test. To push this
381
+ # node to the server, call `create_node`:
382
+
383
+ ChefSpec::Server.create_node('www', www)
384
+ ```
385
+
386
+ Create a role:
387
+
388
+ ```ruby
389
+ ChefSpec::Server.create_role('my_role', { default_attributes: {} })
390
+
391
+ # The role now exists on the Chef Server, you can add it to a node's run_list
392
+ # by adding it to the `converge` block:
393
+ let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe, 'role[my_role]') }
394
+ ```
395
+
396
+ **NOTE** The ChefSpec server is empty at the start of each example to avoid interdependent tests. You can use `before` blocks to load data before each test.
397
+
398
+
399
+ Stubbing
400
+ --------
401
+ ### Command
402
+ Given a recipe with shell guard:
403
+
404
+ ```ruby
405
+ template '/tmp/foo.txt' do
406
+ not_if 'grep /tmp/foo.txt text'
407
+ end
408
+ ```
409
+
410
+ ChefSpec will raise an error like:
411
+
412
+ ```text
413
+ Real commands are disabled. Unregistered command: `grep /tmp/foo.txt text`
414
+
415
+ You can stub this command with:
416
+
417
+ stub_command("grep /tmp/foo.txt text").and_return(true)
418
+
419
+ ============================================================
420
+ ```
421
+
422
+ Just like the error message says, you must stub the command result. This can be done inside a `before` block or inside the `it` block, and the stubbing method accepts both a value or Ruby code. If provided a value, the result is static. If provided a Ruby block, the block is evaluated each time the search is called.
423
+
424
+ ```ruby
425
+ describe 'example::default' do
426
+ let(:chef_run) { ChefSpec::Runner.new }
427
+
428
+ before do
429
+ stub_command("grep /tmp/foo.txt text").and_return(true)
430
+ end
431
+ end
432
+ ```
433
+
434
+ ```ruby
435
+ describe 'example::default' do
436
+ let(:chef_run) { ChefSpec::Runner.new }
437
+
438
+ before do
439
+ stub_command("grep /tmp/foo.txt text") { rand(50)%2 == 0 }
440
+ end
441
+ end
442
+ ```
443
+
444
+ ### Data Bag & Data Bag Item
445
+ **NOTE** This is not required if you are using a ChefSpec server.
446
+
447
+ Given a recipe that executes a `data_bag` method:
448
+
449
+ ```ruby
450
+ data_bag('users').each do |user|
451
+ data_bag_item('users', user['id'])
452
+ end
453
+ ```
454
+
455
+ ChefSpec will rails an error like:
456
+
457
+ ```text
458
+ Real data_bags are disabled. Unregistered data_bag: data_bag(:users)
459
+
460
+ You can stub this data_bag with:
461
+
462
+ stub_data_bag("users").and_return({})
463
+
464
+ ============================================================
465
+ ```
466
+
467
+ Just like the error message says, you must stub the result of the `data_bag` call. This can be done inside a `before` block or inside the `it` block, and the stubbing method accepts both a value or Ruby code. If provided a value, the result is static. If provided a Ruby block, the block is evaluated each time the search is called.
468
+
469
+ ```ruby
470
+ describe 'example::default' do
471
+ let(:chef_run) { ChefSpec::Runner.new }
472
+
473
+ before do
474
+ stub_data_bag('users').and_return([])
475
+ end
476
+ end
477
+ ```
478
+
479
+ ```ruby
480
+ describe 'example::default' do
481
+ let(:chef_run) { ChefSpec::Runner.new }
482
+
483
+ before do
484
+ stub_data_bag('users').and_return([
485
+ { id: 'svargo' },
486
+ { id: 'francis' }
487
+ ])
488
+
489
+ stub_data_bag_item('users', 'svargo').and_return({ ... })
490
+ stub_data_bag_item('users', 'francis') { (ruby code) }
491
+ end
492
+ end
493
+ ```
494
+
495
+ If you are using **Encrypted Data Bag Items**, you'll need to dive into the RSpec layer and stub that class method instead:
496
+
497
+ ```ruby
498
+ describe 'example::default' do
499
+ before do
500
+ Chef::EncryptedDataBagItem.stub(:load).with('users', 'svargo').and_return(...)
501
+ end
502
+ end
503
+ ```
504
+
505
+ ### Search
506
+ **NOTE** This is not required if you are using a ChefSpec server.
507
+
508
+ Because ChefSpec is a unit-testing framework, it is recommended that all third-party API calls be mocked or stubbed. ChefSpec exposes a helpful RSpec macro for stubbing search results in your tests. If you converge a Chef recipe that implements a `search` call, ChefSpec will throw an error like:
509
+
510
+ ```text
511
+ Real searches are disabled. Unregistered search: search(:node, 'name:hello')
512
+
513
+ You can stub this search with:
514
+
515
+ stub_search(:node, 'name:hello') { }
516
+
517
+ ============================================================
518
+ ```
519
+
520
+ Just like the error message says, you must stub the search result. This can be done inside a `before` block or inside the `it` block, and the stubbing method accepts both a value or Ruby code. If provided a value, the result is static. If provided a Ruby block, the block is evaluated each time the search is called.
521
+
522
+ ```ruby
523
+ describe 'example::default' do
524
+ let(:chef_run) { ChefSpec::Runner.new }
525
+
526
+ before do
527
+ stub_search(:node, 'name:hello').and_return([])
528
+ end
529
+ end
530
+ ```
531
+
532
+ ```ruby
533
+ describe 'example::default' do
534
+ let(:chef_run) { ChefSpec::Runner.new }
535
+
536
+ before do
537
+ stub_search(:node, 'name:hello') { (ruby_code) }
538
+ end
539
+ end
540
+ ```
541
+
542
+ Reporting
543
+ ---------
544
+ ChefSpec attempts to generate a report of resources read over resources tested. Please note, this feature is currently in beta phases and may not be 100% accurate. That being said, it's currently the only code coverage tool available for Chef recipes.
545
+
546
+ To generate the coverage report, add the following to the **very end** of your `spec_helper.rb`:
547
+
548
+ ```ruby
549
+ # Existing things...
550
+
551
+ at_exit { ChefSpec::Coverage.report! }
552
+ ```
553
+
554
+ By default, that method will output helpful information to standard out:
555
+
556
+ ```text
557
+ ChefSpec Coverage report generated at '.coverage/results.json':
558
+
559
+ Total Resources: 6
560
+ Touched Resources: 1
561
+ Touch Coverage: 16.67%
562
+
563
+ Untouched Resources:
564
+
565
+ package[git]: bacon/recipes/default.rb:2
566
+ package[build-essential]: bacon/recipes/default.rb:3
567
+ package[apache2]: bacon/recipes/default.rb:4
568
+ package[libvrt]: bacon/recipes/default.rb:5
569
+ package[core]: bacon/recipes/default.rb:6
570
+ ```
571
+
572
+ It also outputs a machine-parsable JSON file at `.coverage/results.json`. This file can be read by your CI server to determine changes in code coverage. We recommend adding the `.coverage` directory to your `.gitignore` to avoid committing it to git.
573
+
574
+ You can configure both the announcing behavior and JSON file. Please see the YARD documentation for more information.
575
+
576
+ If you want to restrict coverage reporting only against certain cookbook directories, you can do it using filters. For example, to include only the site-cookbooks directory for coverage reporting, add the following line in your ```spec/spec_helper.rb```
577
+
578
+ ```ruby
579
+ ChefSpec::Coverage.filters << File.expand_path('../../site-cookbooks', __FILE__)
580
+ ```
581
+
582
+
583
+ Mocking Out Environments
584
+ ------------------------
585
+ If you want to mock out `node.chef_environment`, you'll need to use RSpec mocks/stubs twice:
586
+
587
+ ```ruby
588
+ let(:chef_run) do
589
+ ChefSpec::Runner.new do |node|
590
+ # Create a new environment (you could also use a different :let block or :before block)
591
+ env = Chef::Environment.new
592
+ env.name 'staging'
593
+
594
+ # Stub the node to return this environment
595
+ node.stub(:chef_environment).and_return(env.name)
596
+
597
+ # Stub any calls to Environment.load to return this environment
598
+ Chef::Environment.stub(:load).and_return(env)
599
+ end.converge('cookbook::recipe')
600
+ end
601
+ ```
602
+
603
+ **There is probably a better/easier way to do this. If you have a better solution, please open an issue or Pull Request so we can make this less painful :)**
604
+
605
+
606
+ Testing LWRPs
607
+ -------------
608
+ **WARNING** Cookbooks with dashes (hyphens) are difficult to test with ChefSpec because of how Chef classifies objects. We recommend naming cookbooks with underscores (`_`) instead of dashes (`-`).
609
+
610
+ ChefSpec overrides all providers to take no action (otherwise it would actually converge your system). This means that the steps inside your LWRP are not actually executed. If an LWRP performs actions, those actions are never executed or added to the resource collection.
611
+
612
+ In order to run the actions exposed by your LWRP, you have to explicitly tell the `Runner` to step into it:
613
+
614
+ ```ruby
615
+ require 'chefspec'
616
+
617
+ describe 'foo::default' do
618
+ let(:chef_run) { ChefSpec::Runner.new(step_into: ['my_lwrp']).converge('foo::default') }
619
+
620
+ it 'installs the foo package through my_lwrp' do
621
+ expect(chef_run).to install_package('foo')
622
+ end
623
+ end
624
+ ```
625
+
626
+ **NOTE:** If your cookbook exposes LWRPs, it is highly recommended you also create a `libraries/matchers.rb` file as outlined below in the "Packaging Custom Matchers" section. **You should never `step_into` an LWRP unless you are testing it. Never `step_into` an LWRP from another cookbook!**
627
+
628
+
629
+ Packaging Custom Matchers
630
+ -------------------------
631
+ ChefSpec exposes the ability for cookbook authors to package custom matchers inside a cookbook so that other developers may take advantage of them in testing. This is done by creating a special library file in the cookbook named `matchers.rb`:
632
+
633
+ ```ruby
634
+ # cookbook/libraries/matchers.rb
635
+
636
+ if defined?(ChefSpec)
637
+ def my_custom_matcher(resource_name)
638
+ ChefSpec::Matchers::ResourceMatcher.new(resource, action, resource_name)
639
+ end
640
+ end
641
+ ```
642
+
643
+ 1. The entire contents of this file must be wrapped with the conditional clause checking if `ChefSpec` is defined.
644
+ 2. Each matcher is actually a top-level method. The above example corresponds to the following RSpec test:
645
+ ```ruby
646
+ expect(chef_run).to my_custom_matcher('...')
647
+ ```
648
+
649
+ 3. `ChefSpec::Matchers::ResourceMatcher` accepts three parameters:
650
+ 1. The name of the resource to find in the resource collection (i.e. the name of the LWRP).
651
+ 2. The action that resource should receive.
652
+ 3. The value of the name attribute of the resource to find. (This is typically proxied as the value from the matcher definition.)
653
+
654
+ ChefSpec's built-in `ResourceMatcher` _should_ satisfy most common use cases for packaging a custom matcher with your LWRPs. However, if your cookbook is extending Chef core or is outside of the scope of a traditional "resource", you may need to create a custom matcher. For more information on custom matchers in RSpec, please [watch the Railscast on Custom Matchers](http://railscasts.com/episodes/157-rspec-matchers-macros) or look at some of the other custom matchers in ChefSpec's source code.
655
+
656
+ #### Example
657
+ Suppose I have a cookbook named "motd" with a resource/provider "message".
658
+
659
+ ```ruby
660
+ # motd/resources/message.rb
661
+ actions :write
662
+ default_action :write
663
+
664
+ attribute :message, name_attribute: true
665
+ ```
666
+
667
+ ```ruby
668
+ # motd/providers/message.rb
669
+ action :write do
670
+ # ...
671
+ end
672
+ ```
673
+
674
+ Chef will dynamically build the `motd_message` LWRP at runtime that can be used in the recipe DSL:
675
+
676
+ ```ruby
677
+ motd_message 'my message'
678
+ ```
679
+
680
+ You can package a custom ChefSpec matcher with the motd cookbook by including the following code in `libraries/matchers.rb`:
681
+
682
+ ```ruby
683
+ # motd/libraries/matchers.rb
684
+ if defined?(ChefSpec)
685
+ def write_motd_message(message)
686
+ ChefSpec::Matchers::ResourceMatcher.new(:motd_message, :write, message)
687
+ end
688
+ end
689
+ ```
690
+
691
+ Other developers can write RSpec tests against your LWRP in their cookbooks:
692
+
693
+ ```ruby
694
+ expect(chef_run).to write_motd_message('my message')
695
+ ```
696
+
697
+ **Don't forget to include documentation in your cookbook's README noting the custom matcher and it's API!**
698
+
699
+
700
+ Writing Custom Matchers
701
+ -----------------------
702
+ If you are testing a cookbook that does not package it's LWRP matchers, you can create your own following the same pattern as the "Packaging Custom Matchers" section. Simply, create a file at `spec/support/matchers.rb` and add your resource matchers:
703
+
704
+ ```ruby
705
+ # spec/support/matchers.rb
706
+ def my_custom_matcher(resource_name)
707
+ ChefSpec::Matchers::ResourceMatcher.new(:resource, :action, resource_name)
708
+ end
709
+ ```
710
+
711
+ Then require this file in your `spec_helper.rb` so the matcher can be used:
712
+
713
+ ```ruby
714
+ require_relative 'support/matchers'
715
+ ```
716
+
717
+ Please use this as a _temporary_ solution. Consider sending a Pull Request to the LWRP author(s) packaging the custom resource matchers (see previous section).
718
+
719
+
720
+ Expecting Exceptions
721
+ --------------------
722
+ In Chef 11, custom formatters were introduced and ChefSpec uses a custom formatter to suppress Chef Client output. In the event of a convergence failure, ChefSpec will output the error message from the run to help you debug:
723
+
724
+ ```text
725
+ ================================================================================
726
+ Recipe Compile Error in apt_package/recipes/install.rb
727
+ ================================================================================
728
+
729
+ RuntimeError
730
+ ------------
731
+ RuntimeError
732
+
733
+ Cookbook Trace:
734
+ ---------------
735
+ .../apt_package/recipes/install.rb:1:in `from_file'
736
+ .../apt_package/spec/install_spec.rb:4:in `block (2 levels) in <top (required)>'
737
+ .../apt_package/spec/install_spec.rb:7:in `block (2 levels) in <top (required)>'
738
+
739
+ Relevant File Content:
740
+ ----------------------
741
+ .../apt_package/recipes/install.rb:
742
+
743
+ 1>> raise RuntimeError
744
+ 2:
745
+ 3: apt_package 'default_action'
746
+ ```
747
+
748
+ This output is automatically silenced when using RSpec's `raise_error` matcher:
749
+
750
+ ```ruby
751
+ let(:chef_run) { ChefSpec::Runner.new.converge('cookbook::recipe') }
752
+
753
+ it 'raises an error' do
754
+ expect {
755
+ chef_run
756
+ }.to raise_error
757
+ end
758
+ ```
759
+
760
+ You can also assert that a particular error was raised. If the error matches the given type, the output is suppressed. If not, the test fails and the entire stack trace is presented.
761
+
762
+ ```ruby
763
+ let(:chef_run) { ChefSpec::Runner.new.converge('cookbook::recipe') }
764
+
765
+ it 'raises an error' do
766
+ expect {
767
+ chef_run
768
+ }.to raise_error(RuntimeError)
769
+ end
770
+ ```
771
+
772
+ Testing Roles
773
+ -------------
774
+ Even though ChefSpec is cookbook-centric, you can still converge multiple recipes and roles in a single `ChefSpec::Runner` instance. Given a cookbook "bacon" with a default recipe:
775
+
776
+ ```ruby
777
+ # cookbooks/bacon/recipes/default.rb
778
+ package 'foo'
779
+ ```
780
+
781
+ and a default attributes file:
782
+
783
+ ```ruby
784
+ # cookbooks/bacon/attributes/default.rb
785
+ default['bacon']['temperature'] = 200
786
+ ```
787
+
788
+ and a role "breakfast":
789
+
790
+ ```ruby
791
+ # roles/breakfast.rb
792
+ default_attributes(
793
+ 'bacon' => {
794
+ 'temperature' => 150 # NOTE: This is different from the default value
795
+ }
796
+ )
797
+ run_list([
798
+ 'recipe[bacon::default]'
799
+ ])
800
+ ```
801
+
802
+ You can test that the role is appropriately applied by telling the `ChefSpec::Runner` to converge on the _role_ instead of a recipe:
803
+
804
+ ```ruby
805
+ let(:chef_run) { ChefSpec::Runner.new.converge('role[breakfast]') }
806
+ ```
807
+
808
+ Assert that the run_list is properly expanded:
809
+
810
+ ```ruby
811
+ expect(chef_run).to include_recipe('bacon::default')
812
+ ```
813
+
814
+ Assert that the correct attribute is used:
815
+
816
+ ```ruby
817
+ expect(runner.node['bacon']['temperature']).to eq(150)
818
+ ```
819
+
820
+ **NOTE** If your roles live somewhere outside of the expected path, you must set `RSpec.config.role_path` to point to the directory containing your roles **before** invoking the `#converge` method!
821
+
822
+ ```ruby
823
+ RSpec.configure do |config|
824
+ config.role_path = '/var/my/roles' # global setting
825
+ end
826
+
827
+ # - OR -
828
+
829
+ ChefSpec::Runner.new(role_path: '/var/my/roles') # local setting
830
+ ```
831
+
832
+
833
+ Faster Specs
834
+ ------------
835
+ ChefSpec aims to provide the easiest and simplest path for new users to write RSpec examples for Chef cookbooks. In doing so, it makes some sacrifices in terms of speed and agility of execution. In other words, ChefSpec favors "speed to develop" over "speed to execute". Many of these decisions are directly related to the way Chef dynamically loads resources at runtime.
836
+
837
+ If you understand how RSpec works and would like to see some significant speed improvements in your specs, you can use the `ChefSpec::Cacher` module inspired by [Juri Timošin](https://github.com/DracoAter). Just require the cacher module in your spec helper.
838
+
839
+ ```ruby
840
+ # spec_helper.rb
841
+ require 'chefspec/cacher'
842
+ ```
843
+
844
+ Next, convert all your `let` blocks to `cached`:
845
+
846
+ ```ruby
847
+ # before
848
+ let(:chef_run) { ChefSpec::Runer.new }
849
+
850
+ # after
851
+ cached(:chef_run) { ChefSpec::Runner.new }
852
+ ```
853
+
854
+ Everything else should work the same. Be advised, as the method name suggests, this will cache the results of your Chef Client Run for the **entire RSpec example**. This makes stubbing more of a challenge, since the node is already converged. For more information, please see [Juri Timošin's blog post on faster specs](http://dracoater.blogspot.com/2013/12/testing-chef-cookbooks-part-25-speeding.html) as well as the discussion in [#275](https://github.com/sethvargo/chefspec/issues/275).
855
+
856
+
857
+ Media & Third-party Tutorials
858
+ -----------------------------
859
+ - [CustomInk's Testing Chef Cookbooks](http://technology.customink.com/blog/2012/08/03/testing-chef-cookbooks/)
860
+ - [Jake Vanderdray's Practical ChefSpec](http://files.meetup.com/1780846/ChefSpec.pdf)
861
+ - [Jim Hopp's excellent Test Driven Development for Chef Practitioners](http://www.youtube.com/watch?v=o2e0aZUAVGw)
862
+ - [Joshua Timberman's Starting ChefSpec Examples](http://jtimberman.housepub.org/blog/2013/05/09/starting-chefspec-example/)
863
+ - [Juri Timošin's post on faster specs](http://dracoater.blogspot.com/2013/12/testing-chef-cookbooks-part-25-speeding.html)
864
+ - [Seth Vargo's Chef recipe code coverage](https://sethvargo.com/chef-recipe-code-coverage/)
865
+ - [Seth Vargo's TDDing tmux talk](http://www.confreaks.com/videos/2364-mwrc2013-tdding-tmux)
866
+ - [Stephen Nelson Smith's Test-Driven Infrastructure with Chef](http://shop.oreilly.com/product/0636920030973.do)
867
+
868
+
869
+ Development
870
+ -----------
871
+ 1. Fork the repository from GitHub.
872
+ 2. Clone your fork to your local machine:
873
+
874
+ $ git clone git@github.com:USER/chefspec.git
875
+
876
+ 3. Create a git branch
877
+
878
+ $ git checkout -b my_bug_fix
879
+
880
+ 4. **Write tests**
881
+ 5. Make your changes/patches/fixes, committing appropriately
882
+ 6. Run the tests: `bundle exec rake`
883
+ 7. Push your changes to GitHub
884
+ 8. Open a Pull Request
885
+
886
+ ChefSpec is on [Travis CI](http://travis-ci.org/sethvargo/chefspec) which tests against multiple Chef and Ruby versions.
887
+
888
+ If you are contributing, please see the [Contributing Guidelines](https://github.com/sethvargo/chefspec/blob/master/CONTRIBUTING.md) for more information.
889
+
890
+
891
+ License
892
+ -------
893
+ MIT - see the accompanying [LICENSE](https://github.com/sethvargo/chefspec/blob/master/LICENSE) file for details.